shard分配策略
集群分片分配是指將索引的shard分配到其他節點的過程,會在如下情況下觸發:
- 集群內有節點宕機,需要故障恢復;
- 增加副本;
- 索引的動態均衡,包括集群內部節點數量調整、刪除索引副本、刪除索引等情況;
上述策略開關,可以動態調整,由參數cluster.routing.allocation.enable控制,啟用或者禁用特定分片的分配。該參數的可選參數有:
- all - 默認值,允許為所有類型分片分配分片;
- primaries - 僅允許分配主分片的分片;
- new_primaries - 僅允許為新索引的主分片分配分片;
- none - 任何索引都不允許任何類型的分片;
重新啟動節點時,此設置不會影響本地主分片的恢復。如果重新啟動的節點具有未分配的主分片的副本,會立即恢復該主分片。
PUT _cluster/settings { "persistent" : { "cluster.routing.rebalance.enable": "none", ##允許在一個節點上發生多少並發傳入分片恢復。 默認為2。 ##多數為副本 "cluster.routing.allocation.node_concurrent_incoming_recoveries":2, ##允許在一個節點上發生多少並發傳出分片恢復,默認為2. ## 多數為主分片 "cluster.routing.allocation.node_concurrent_outgoing_recoveries":2, ##為上面兩個的統一簡寫 "cluster.routing.allocation.node_concurrent_recoveries":2, ##在通過網絡恢復副本時,節點重新啟動后未分配的主節點的恢復使用來自本地 磁盤的數據。 ##這些應該很快,因此更多初始主要恢復可以在同一節點上並行發生。 默認為4。 "cluster.routing.allocation.node_initial_primaries_recoveries":4, ##允許執行檢查以防止基於主機名和主機地址在單個主機上分配同一分片的多個實例。 ##默認為false,表示默認情況下不執行檢查。 此設置僅適用於在同一台計算機上啟動多個節點的情況。這個我的理解是如果設置為false, ##則同一個節點上多個實例可以存儲同一個shard的多個副本沒有容災作用了 "cluster.routing.allocation.same_shard.host":true } }
rebalance策略
cluster.routing.rebalance.enable為特定類型的分片啟用或禁用重新平衡:
-
all - (默認值)允許各種分片的分片平衡;
-
primaries - 僅允許主分片的分片平衡;
-
replicas - 僅允許對副本分片進行分片平衡;
-
none - 任何索引都不允許任何類型的分片平衡;
cluster.routing.allocation.allow_rebalance用來控制rebalance觸發條件:
-
always - 始終允許重新平衡;
-
indices_primaries_active - 僅在所有主分片可用時;
-
indices_all_active - (默認)僅當所有分片都激活時;
cluster.routing.allocation.cluster_concurrent_rebalance用來控制均衡力度,允許集群內並發分片的rebalance數量,默認為2。
cluster.routing.allocation.node_concurrent_recoveries,每個node上允許rebalance的片數量。
ElasticSearch集群什么時候會進行rebalance?
rebalance策略的觸發條件,主要由下面幾個參數控制:
## 每個節點上的從shard數量,-1代表不限制 cluster.routing.allocation.total_shards_per_node: -1 ## 定義分配在該節點的分片數的因子 閾值=因子*(當前節點的分片數-集群的總分片數/節點數,即每個節點的平均分片數) cluster.routing.allocation.balance.shard: 0.45f ## 定義分配在該節點某個索引的分片數的因子,閾值=因子*(保存當前節點的某個索引的分片數-索引的總分片數/節點數,即每個節點某個索引的平均分片數) cluster.routing.allocation.balance.index: 0.55f ## 超出這個閾值就會重新分配分片 cluster.routing.allocation.balance.threshold: 1.0f ## 磁盤參數 ## 啟用基於磁盤的分發策略 cluster.routing.allocation.disk.threshold_enabled: true ## 硬盤使用率高於這個值的節點,則不會分配分片 cluster.routing.allocation.disk.watermark.low: "85%" ## 如果硬盤使用率高於這個值,則會重新分片該節點的分片到別的節點 cluster.routing.allocation.disk.watermark.high: "90%" ## 當前硬盤使用率的查詢頻率 cluster.info.update.interval: "30s" ## 計算硬盤使用率時,是否加上正在重新分配給其他節點的分片的大小 cluster.routing.allocation.disk.include_relocations: true
elasticsearch內部計算公式是:
weightindex(node, index) = indexBalance * (node.numShards(index) – avgShardsPerNode(index)) weightnode(node, index) = shardBalance * (node.numShards() – avgShardsPerNode) weightprimary(node, index) = primaryBalance * (node.numPrimaries() – avgPrimariesPerNode) weight(node, index) = weightindex(node, index) + weightnode(node, index) + weightprimary(node, index)
如果計算最后的weight(node, index)大於threshold, 就會發生shard遷移。
自定義規則
可以通過設置分片的分布規則來人為地影響分片的分布,示例如下:
假設有幾個機架,可以在每個節點設置機架的屬性:
node.attr.rack_id: r1
現在添加一條策略,設置rack_id作為分片規則的一個屬性
PUT _cluster/settings { "persistent": { "cluster.routing.allocation.awareness.attributes":"r1" } }
上面設置意味着rack_id會用來作為分片分布的依據。例如:我們啟動兩個node.attr.rack_id設置r1的節點,然后建立一個5個分片,一個副本的索引。這個索引就會完全分布在這兩個節點上。如果再啟動另外兩個節點,node.attr.rack_id設置成r2,分片會重新分布,但是一個分片和它的副本不會分配到同樣rack_id值的節點上。
可以為分片分布規則設置多個屬性,例如:
cluster.routing.allocation.awareness.attributes: rack_id,zone
注意:當設置了分片分布屬性時,如果集群中的節點沒有設置其中任何一個屬性,那么分片就不會分布到這個節點中。
強制分布規則
更多的時候,我們不想更多的副本被分布到相同分布規則屬性值的一群節點上,那么,我們可以強制分片規則為一個指定的值。
例如,我們有一個分片規則屬性叫zone,並且我們知道有兩個zone,zone1和zone2。下面是設置:
cluster.routing.allocation.awareness.force.zone.values: zone1,zone2
cluster.routing.allocation.awareness.attributes: zone
現在我們啟動兩個node.zone設置成zone1的節點,然后創建一個5個分片,一個副本的索引。索引建立完成后只有5個分片(沒有副本),只有當我們啟動node.zone設置成zone2的節點時,副本才會分配到那節點上。
分片分布過濾
允許通過include/exclude過濾器來控制分片的分布。這些過濾器可以設置在索引級別上或集群級別上。下面是個索引級別上的例子:
假如我們有四個節點,每個節點都有一個叫tag(可以是任何名字)的屬性。每個節點都指定一個tag的值。如:節點一設置成node.tag: value1,節點二設置成node.tag: value2,如此類推。我們可以創建一個索引然后只把它分布到tag值為value1和value2的節點中,可以通過設置index.routing.allocation.include.tag為value1,value2達到這樣的效果,如:
PUT /test/_settings { "index.routing.allocation.include.tag" : "value1,value2" }
與此相反,通過設置index.routing.allocation.exclude.tag為value3,我們也可以創建一個索引讓其分布在除了tag設置為value3的所有節點中,如:
PUT /test/_settings { "index.routing.allocation.include.tag" : "value3" }
include或exclude過濾器的值都會使用通配符來匹配,如value*。一個特別的屬性名是_ip,它可以用來匹配節點的ip地址。
顯然,一個節點可能擁有多個屬性值,所有屬性的名字和值都在配置文件中配置。如,下面是多個節點的配置:
node.group1: group1_value1
node.group2: group2_value4
同樣的方法,include和exclude也可以設置多個值,如:
PUT /test/_settings { "index.routing.allocation.include.group1" : "xxx" , "index.routing.allocation.include.group1" : "yyy", "index.routing.allocation. exclude.group1" : "zzz" }
上面的設置可以通過索引更新的api實時更新到索引上,允許實時移動索引分片。
