shard 的 allocate 控制

本文介绍Elasticsearch中Shard的分配控制方法,包括参数配置、reroute接口使用及冷热数据读写分离实施方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

某个 shard 分配在哪个节点上,一般来说,是由 ES 自动决定的。以下几种情况会触发分配动作:

  1. 新索引生成
  2. 索引的删除
  3. 新增副本分片
  4. 节点增减引发的数据均衡

ES 提供了一系列参数详细控制这部分逻辑:

  • cluster.routing.allocation.enable 该参数用来控制允许分配哪种分片。默认是 all。可选项还包括 primaries 和 new_primariesnone 则彻底拒绝分片。该参数的作用,本书稍后集群升级章节会有说明。
  • cluster.routing.allocation.allow_rebalance 该参数用来控制什么时候允许数据均衡。默认是 indices_all_active,即要求所有分片都正常启动成功以后,才可以进行数据均衡操作,否则的话,在集群重启阶段,会浪费太多流量了。
  • cluster.routing.allocation.cluster_concurrent_rebalance 该参数用来控制集群内同时运行的数据均衡任务个数。默认是 2 个。如果有节点增减,且集群负载压力不高的时候,可以适当加大。
  • cluster.routing.allocation.node_initial_primaries_recoveries 该参数用来控制节点重启时,允许同时恢复几个主分片。默认是 4 个。如果节点是多磁盘,且 IO 压力不大,可以适当加大。
  • cluster.routing.allocation.node_concurrent_recoveries 该参数用来控制节点除了主分片重启恢复以外其他情况下,允许同时运行的数据恢复任务。默认是 2 个。所以,节点重启时,可以看到主分片迅速恢复完成,副本分片的恢复却很慢。除了副本分片本身数据要通过网络复制以外,并发线程本身也减少了一半。当然,这种设置也是有道理的——主分片一定是本地恢复,副本分片却需要走网络,带宽是有限的。从 ES 1.6 开始,冷索引的副本分片可以本地恢复,这个参数也就是可以适当加大了。
  • indices.recovery.concurrent_streams 该参数用来控制节点从网络复制恢复副本分片时的数据流个数。默认是 3 个。可以配合上一条配置一起加大。
  • indices.recovery.max_bytes_per_sec 该参数用来控制节点恢复时的速率。默认是 40MB。显然是比较小的,建议加大。

此外,ES 还有一些其他的分片分配控制策略。比如以 tag 和 rack_id 作为区分等。一般来说,Elastic Stack 场景中使用不多。运维人员可能比较常见的策略有两种:

  1. 磁盘限额 为了保护节点数据安全,ES 会定时(cluster.info.update.interval,默认 30 秒)检查一下各节点的数据目录磁盘使用情况。在达到 cluster.routing.allocation.disk.watermark.low (默认 85%)的时候,新索引分片就不会再分配到这个节点上了。在达到 cluster.routing.allocation.disk.watermark.high (默认 90%)的时候,就会触发该节点现存分片的数据均衡,把数据挪到其他节点上去。这两个值不但可以写百分比,还可以写具体的字节数。有些公司可能出于成本考虑,对磁盘使用率有一定的要求,需要适当抬高这个配置:
# curl -XPUT localhost:9200/_cluster/settings -d '{
    "transient" : {
        "cluster.routing.allocation.disk.watermark.low" : "85%",
        "cluster.routing.allocation.disk.watermark.high" : "10gb",
        "cluster.info.update.interval" : "1m"
    }
}'
  1. 热索引分片不均 默认情况下,ES 集群的数据均衡策略是以各节点的分片总数(indices_all_active)作为基准的。这对于搜索服务来说无疑是均衡搜索压力提高性能的好办法。但是对于 Elastic Stack 场景,一般压力集中在新索引的数据写入方面。正常运行的时候,也没有问题。但是当集群扩容时,新加入集群的节点,分片总数远远低于其他节点。这时候如果有新索引创建,ES 的默认策略会导致新索引的所有主分片几乎全分配在这台新节点上。整个集群的写入压力,压在一个节点上,结果很可能是这个节点直接被压死,集群出现异常。 所以,对于 Elastic Stack 场景,强烈建议大家预先计算好索引的分片数后,配置好单节点分片的限额。比如,一个 5 节点的集群,索引主分片 10 个,副本 1 份。则平均下来每个节点应该有 4 个分片,那么就配置:
# curl -s -XPUT http://127.0.0.1:9200/logstash-2015.05.08/_settings -d '{
    "index": { "routing.allocation.total_shards_per_node" : "5" }
}'

注意,这里配置的是 5 而不是 4。因为我们需要预防有机器故障,分片发生迁移的情况。如果写的是 4,那么分片迁移会失败。

此外,另一种方式则更加玄妙,Elasticsearch 中有一系列参数,相互影响,最终联合决定分片分配:

  • cluster.routing.allocation.balance.shard 节点上分配分片的权重,默认为 0.45。数值越大越倾向于在节点层面均衡分片。
  • cluster.routing.allocation.balance.index 每个索引往单个节点上分配分片的权重,默认为 0.55。数值越大越倾向于在索引层面均衡分片。
  • cluster.routing.allocation.balance.threshold 大于阈值则触发均衡操作。默认为1。

Elasticsearch 中的计算方法是:

(indexBalance (node.numShards(index) – avgShardsPerNode(index)) + shardBalance(node.numShards() – avgShardsPerNode)) <=> weightthreshold

所以,也可以采取加大 cluster.routing.allocation.balance.index,甚至设置 cluster.routing.allocation.balance.shard 为 0 来尽量采用索引内的节点均衡。

reroute 接口

上面说的各种配置,都是从策略层面,控制分片分配的选择。在必要的时候,还可以通过 ES 的 reroute 接口,手动完成对分片的分配选择的控制。

reroute 接口支持五种指令:allocate_replicaallocate_stale_primaryallocate_empty_primarymove 和 cancel。常用的一般是 allocate 和 move:

  • allocate_* 指令

因为负载过高等原因,有时候个别分片可能长期处于 UNASSIGNED 状态,我们就可以手动分配分片到指定节点上。默认情况下只允许手动分配副本分片(即使用 allocate_replica),所以如果要分配主分片,需要单独加一个 accept_data_loss 选项:

# curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
  "commands" : [ {
        "allocate_stale_primary" :
            {
              "index" : "logstash-2015.05.27", "shard" : 61, "node" : "10.19.0.77", "accept_data_loss" : true
            }
        }
  ]
}'

注意,allocate_stale_primary 表示准备分配到的节点上可能有老版本的历史数据,运行时请提前确认一下是哪个节点上保留有这个分片的实际目录,且目录大小最大。然后手动分配到这个节点上。以此减少数据丢失。

  • move 指令

因为负载过高,磁盘利用率过高,服务器下线,更换磁盘等原因,可以会需要从节点上移走部分分片:

curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
  "commands" : [ {
        "move" :
            {
              "index" : "logstash-2015.05.22", "shard" : 0, "from_node" : "10.19.0.81", "to_node" : "10.19.0.104"
            }
        }
  ]
}'

分配失败原因

如果是自己手工 reroute 失败,Elasticsearch 返回的响应中会带上失败的原因。不过格式非常难看,一堆 YES,NO。从 5.0 版本开始,Elasticsearch 新增了一个 allocation explain 接口,专门用来解释指定分片的具体失败理由:

`` curl -XGET 'http://localhost:9200/_cluster/allocation/explain' -d'{ "index": "logstash-2016.10.31", "shard": 0, "primary": false

}'


得到的响应如下:

{ "shard" : { "index" : "myindex", "index_uuid" : "KnW0-zELRs6PK84l0r38ZA", "id" : 0, "primary" : false }, "assigned" : false, "shard_state_fetch_pending": false, "unassigned_info" : { "reason" : "INDEX_CREATED", "at" : "2016-03-22T20:04:23.620Z" }, "allocation_delay_ms" : 0, "remaining_delay_ms" : 0, "nodes" : { "V-Spi0AyRZ6ZvKbaI3691w" : { "node_name" : "H5dfFeA", "node_attributes" : { "bar" : "baz" }, "store" : { "shard_copy" : "NONE" }, "final_decision" : "NO", "final_explanation" : "the shard cannot be assigned because one or more allocation decider returns a 'NO' decision", "weight" : 0.06666675, "decisions" : [ { "decider" : "filter", "decision" : "NO", "explanation" : "node does not match index include filters [foo:\"bar\"]" } ] }, "Qc6VL8c5RWaw1qXZ0Rg57g" : { ...


这会是很长一串 JSON,把集群里所有的节点都列上来,挨个解释为什么不能分配到这个节点。

## 节点下线

集群中个别节点出现故障预警等情况,需要下线,也是 Elasticsearch 运维工作中常见的情况。如果已经稳定运行过一段时间的集群,每个节点上都会保存有数量不少的分片。这种时候通过 reroute 接口手动转移,就显得太过麻烦了。这个时候,有另一种方式:

curl -XPUT 127.0.0.1:9200/_cluster/settings -d '{ "transient" :{ "cluster.routing.allocation.exclude._ip" : "10.0.0.1" } }'


Elasticsearch 集群就会自动把这个 IP 上的所有分片,都自动转移到其他节点上。等到转移完成,这个空节点就可以毫无影响的下线了。

和 `_ip` 类似的参数还有 `_host`, `_name` 等。此外,这类参数不单是 cluster 级别,也可以是 index 级别。下一小节就是 index 级别的用例。

## 冷热数据的读写分离

Elasticsearch 集群一个比较突出的问题是: 用户做一次大的查询的时候, 非常大量的读 IO 以及聚合计算导致机器 Load 升高, CPU 使用率上升, 会影响阻塞到新数据的写入, 这个过程甚至会持续几分钟。所以,可能需要仿照 MySQL 集群一样,做读写分离。

### 实施方案

1. N 台机器做热数据的存储, 上面只放当天的数据。这 N 台热数据节点上面的 elasticsearc.yml 中配置 `node.attr.tag: hot`
2. 之前的数据放在另外的 M 台机器上。这 M 台冷数据节点中配置 `node.attr.tag: stale`
3. 模板中控制对新建索引添加 hot 标签:

{ "order" : 0, "template" : "*", "settings" : { "index.routing.allocation.include.tag" : "hot" } }

4. 每天计划任务更新索引的配置, 将 tag 更改为 stale, 索引会自动迁移到 M 台冷数据节点

curl -XPUT http://127.0.0.1:9200/indexname/_settings -d'

{ "index": { "routing": { "allocation": { "include": { "tag": "stale" } } } } }' ```

这样,写操作集中在 N 台热数据节点上,大范围的读操作集中在 M 台冷数据节点上。避免了堵塞影响。

+

该方案运用的,是 Elasticsearch 中的 allocation filter 功能,详细说明见:https://www.elastic.co/guide/en/elasticsearch/reference/master/shard-allocation-filtering.html

转载自:shard 的 allocate 控制

<think>嗯,用户之前问过关于Elasticsearch分布式架构如何处理节点故障的问题,现在又接着问分片和副本。看来他们可能是在学习ES的分布式机制,或者是正在搭建集群需要了解这些概念。 首先,用户之前的问题是关于节点故障的自动处理,所以现在问分片和副本应该是想深入理解数据存储和冗余的机制。分片和副本是ES实现高可用和扩展性的核心,需要详细解释两者的区别和联系。 用户可能不太清楚分片和副本的作用,或者混淆了它们的概念。需要明确分片是数据分割的单位,而副本是分片的复制,用于故障恢复和负载均衡。可能还需要举例说明,比如索引如何被分成多个分片,每个分片如何有副本。 另外,用户可能关心实际应用中的配置,比如如何设置分片数和副本数,最佳实践是什么。需要提到分片过多或过少的影响,副本数量的调整对集群性能的影响,以及如何根据硬件资源来规划。 还要注意用户可能的误区,比如认为增加副本可以无限提高性能,但实际上副本会占用存储和计算资源。需要解释平衡可用性和资源消耗的重要性。 用户可能还需要知道分片和副本在故障恢复中的具体作用,比如主分片失效时副本如何提升为主分片,恢复过程中数据如何同步。这部分可以结合之前的节点故障处理机制来回答,形成知识连贯性。 最后,可能还需要提到一些常见问题,比如分片无法分配的原因,如何监控分片状态,以及调整分片和副本时的注意事项。这些实际操作的内容对用户来说可能非常实用。</think>### Elasticsearch 分片(Shard)与副本(Replica)详解 --- #### 一、核心概念对比 | 特性 | **分片(Shard)** | **副本(Replica)** | |-------------|--------------------------------------|--------------------------------------| | **本质** | 数据的最小物理存储单元 | 分片的完整拷贝 | | **类型** | 主分片(Primary) / 副本分片(Replica)| 只能是主分片的副本 | | **读写权限** | 主分片可读写,副本分片默认只读 | 仅响应查询请求 | | **创建时机** | 索引创建时固定数量(不可修改) | 可动态调整数量 | | **作用目标** | 解决**数据水平扩展**问题 | 解决**高可用**和**查询负载均衡**问题 | --- #### 二、技术实现细节 ##### 1. **分片工作机制** - **分片公式**: $$ \text{总数据存储量} = \text{主分片数} \times (1 + \text{副本数}) \times \text{单分片数据量} $$ - **路由机制**: 文档通过哈希算法分配到指定主分片: $$ \text{shard\_num} = hash(\_routing) \% \text{num\_primary\_shards} $$ - **分片限制**: 单个分片建议大小在 `10GB-50GB`(超过 `100GB` 可能影响性能) ##### 2. **副本运作原理** - **实时同步**: 主分片通过 `Translog` 保证数据变更顺序,副本采用 `pull` 模式同步数据 - **一致性模型**: - **同步写入**:需多数副本确认(通过 `wait_for_active_shards` 参数控制) - **异步刷新**:默认每秒刷新(`refresh_interval=1s`) --- #### 三、配置与优化策略 ##### 1. **分片数量决策** - **黄金法则**: 分片总数 = 节点数 × 单节点承载分片数(建议 `500-1000`/节点) 例如:3节点集群,单节点承载上限 800 分片 → 总容量约 `2400` 分片 - **动态调整限制**: 主分片数创建后不可变,只能通过 `Reindex API` 重建索引调整 ##### 2. **副本配置技巧** ```json // 创建索引时指定分片配置 PUT /my_index { "settings": { "number_of_shards": 3, // 主分片数 "number_of_replicas": 2 // 每个主分片的副本数 } } // 动态修改副本数(实时生效) PUT /my_index/_settings { "number_of_replicas": 1 } ``` ##### 3. **性能优化要点** - **冷热分离架构**: 使用 `ILM(Index Lifecycle Management)` 将旧索引副本数降为 `0` - **写入优化**: 临时关闭副本(`index.number_of_replicas=0`)提升批量导入速度 - **查询加速**: 增加副本可实现读请求的**多副本负载均衡** --- #### 四、故障场景应对 ##### 1. **分片未分配(UNASSIGNED)** - **常见原因**: - 磁盘空间不足(`85%` 水位线触发只读模式) - 节点属性不匹配分配规则(如 `rack` 标签约束) - **解决方案**: ```bash # 强制分配分片(慎用) POST /_cluster/reroute { "commands": [{ "allocate_stale_primary": { "index": "my_index", "shard": 0, "node": "node-1", "accept_data_loss": true } }] } ``` ##### 2. **副本同步延迟** - **检测方法**: ```bash GET /_cat/shards?v&h=index,shard,prirep,state,docs,store ``` - **处理方案**: - 检查网络带宽(`indices.recovery.max_bytes_per_sec`) - 优化映射字段类型,减少 `_source` 体积 --- #### 五、最佳实践总结 1. **容量规划**: - 预估数据总量 → 确定主分片数 - 根据 SLA 要求 → 确定副本数(生产环境至少 `1` 副本) 2. **硬件匹配原则**: - 单个分片数据量 ≈ 节点内存的 `1/10`(如 `64GB` 内存 → 分片大小 `6-7GB`) - 使用 `SSD` 磁盘降低副本同步延迟 3. **监控关键指标**: - `indices.search.fetch_current`(副本查询负载) - `indices.indexing.index_current`(主分片写入压力) - `thread_pool` 的 `write`/`search` 队列深度 4. **特殊场景处理**: - **时序数据**:使用 `Rollover API` 自动创建新分片 - **全局搜索**:设置 `preference=_primary` 强制主分片查询 --- #### 六、经典误区解析 - **误区1**:"增加副本数一定能提升查询性能" ✅ 实际:当查询为 `CPU 密集型` 时,过多副本可能引发线程竞争 - **误区2**:"主分片越多越好" ✅ 实际:分片过多会导致 `元数据管理开销` 指数级增长 - **误区3**:"副本可以替代备份" ✅ 实际:副本不能防范 `误删除`,仍需 `Snapshot` 实现真正备份 --- 通过合理配置分片与副本,可在**数据可靠性**、**查询性能**、**硬件成本**之间找到最佳平衡点。建议通过 `Elasticsearch Rally` 进行分片方案的基准测试验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值