## 調整集群的分片分配
<div style="text-indent:2em;">
<p>在<i>ElasticSearch Server</i>一書中,我們探討了如何強制改變分片的分配方式,如何取消、如何使用一條API命令在集群中轉移分片。然而在談論到分片分配時,ElasticSearch允許我們做的不止如此,我們還可以定義以系列用于分片分配的規則。例如,假定一個4-節點的集群,圖示如下:</p>
<center><img src="../4_node.png"/></center>
<p>正如你所看到的一樣,集群由4個節點構成。每個節點都綁定了一個特定的IP地址,同時每個節點也擁有tag屬性和group屬性(可以在elasticsearch.yml文件中設置node.tag和node.group屬性)。集群用來展示分片分配過濾器是如何工作的。group屬性和tag屬性可以用任意其它的名字替換,只需要把node作為自定義屬性的前綴即可。比如你喜歡用屬性名,party,就只需要把node.party:party1添加到你的elasticsearch.yml文件中即可。</p>
<h4>Allocation awareness 配置</h4>
<p>Allocation awareness制允許用戶使用泛型參數來配置分片及分片副本的分配。為了演示allocation awareness的工作方式,我們使用我們的樣例集群。為了集群的演示效果,我們在elasticsearch.yml文件中添加如下的屬性:
<blockquote>cluster.routing.allocation.awareness.attributes:group</blockquote>
</p>
<p>這條配置命令用來通知Elasticsearh使用node.group屬性作為集群的awareness參數。</p>
<!--note structure -->
<div style="height:80px;width:650px;text-indent:0em;">
<div style="float:left;width:13px;height:100%; background:black;">
<img src="../lm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
<div style="float:left;width:50px;height:100%;position:relative;">
<img src="../note.png" style="position:absolute; top:30%; "/>
</div>
<div style="float:left; width:550px;height:100%;">
<p style="font-size:13px;margin-top:5px;">設置cluster.routing.allocation.awareness.attributes屬性的參數時,可以指定多個值。比如:
<blockquote>cluster.routing.allocation.awareness.attributes:group,node </blockquote>
</p>
</div>
<div style="float:left;width:13px;height:100%;background:black;">
<img src="../rm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
</div> <!-- end of note structure -->
<p>參數設置好以后,我們先啟動兩個節點,兩個節點的node.group值都是groupA,并且用如下的命令創建索引:
<blockquote style="text-indent:0em;">
curl -XPOST 'localhost:9200/mastering' -d '{
<blockquote>"settings" : {
"index" : {<blockquote>
"number\_of\_shards" : 2,<br/>
"number\_of\_replicas" : 1</blockquote>
}
}</blockquote>
}'
</blockquote>
</p>
<p>這個命令執行后,我們的2-節點集群看起來或多或少地類似于下面的圖形:</p>
<center> <img src="../43_group_1.png"/></center>
<p>正如所看見的那樣,索引的分片平均分配到了兩個節點中。現在,我們看看當啟動剩下的兩個節點時(node.group屬性值設置為groupB)將會發生什么?</p>
<center> <img src="../43_group_2.png"/></center>
<p>注意兩者的不同點:主分片并沒有從原來分配的節點中移出,反而是分片副本移動到了node.grooup值不同的節點中,這正是我們所希望的結果。在集群中使用了shard allocation awareness功能后,ElasticSearch不會把決定allocation awareness的屬性(在本例中是node.group值)相同的分片或者分片副本分配到同一個節點中。該功能典型的用例是把集群拓撲結構部署到物理機或者虛擬機時,確保你的集群不會出現單點故障問題。</p>
<!--note structure -->
<div style="height:80px;width:650px;text-indent:0em;">
<div style="float:left;width:13px;height:100%; background:black;">
<img src="../lm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
<div style="float:left;width:50px;height:100%;position:relative;">
<img src="../note.png" style="position:absolute; top:30%; "/>
</div>
<div style="float:left; width:550px;height:100%;">
<p style="font-size:13px;margin-top:5px;">請記住在使用allocation awareness功能時,分片不會被分配到沒有設置相應屬性的節點上。所在在我們的案例中,分片分配機制不會考慮分配分片到沒有設置node.group屬性的節點。
</p>
</div>
<div style="float:left;width:13px;height:100%;background:black;">
<img src="../rm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
</div> <!-- end of note structure -->
<h4>Forcing allocation awareness</h4>
(文本的描述不并清晰,參考http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-cluster.html,一看就懂)
<p>當我們事先知道awareness屬性的取值范圍并且不希望集群中有過多的分片副本時,使用forcing allocation awareness機制會很方便。比如,不希望集群中負載了過多的分片副本,我們可以強制allocation awareness只在有確定參數值時起作用。我們可以指定cluster.routing.allocation.awareness.force.zone.values屬性的值,這是一個多值屬性,多個值可以用逗號區分開來。比如,如果我們希望allocation awareness只在node.group屬性的值為groupA和groupB生效時,我們可以在elasticsearch.yml文件中加入如下的代碼:
<blockquote>
cluster.routing.allocation.awareness.attributes: group<br/>
cluster.routing.allocation.awareness.force.zone.values: groupA, groupB
</blockquote>
</p>
<h4>過濾</h4>
<p>ElasticSearch允許用戶從整個集群或者索引的層面上配置allocation機制。在集群層面上配置allocation機制時,我們可以用如下的屬性前綴:
<ul>
<li>cluster.routing.allocation.include</li>
<li>cluster.routing.allocation.require</li>
<li>cluster.routing.allocation.exclude</li>
</ul>
如果是在索引層面的分配,我們用如下的屬性前綴:
<ul>
<li>index.routing.allocation.include</li>
<li>index.routing.allocation.require</li>
<li>index.routing.allocation.exclude</li>
</ul>
上面提到的前綴可以和elasticsearch.yml文件中定義的屬性(tag屬性和group屬性)結合起來,而且還有一個命名為\_ip的屬性允許用戶匹配或者排除一些特定IP的節點。比如:
<blockquote>cluster.routing.allocation.include.\_ip:192.168.2.1</blockquote>
如果我們希望把group屬性值為groupA的節點包括進來,我們可以設置如下的屬性:
<blockquote>cluster.routing.allocation.include.group:groupA</blockquote>
注意我們使用cluster.routing.allocation.include屬性的方式是以它為前綴并和其它屬性的名字串聯起來,在本例中是group屬性。
</p>
<h4>include,exclude,required屬性的意義</h4>
<p>如果讀者仔細觀察了前面提到的參數,應該能注意到它們分為三種:
<ul>
<li>include:這種類型將導致所有定義了該參數的節點都會被包括進來。如果配置多種include的條件,那么在進行分片分配的時候,只要有一個條件滿足,節點就會被allocation考慮進去。比如,如果我們在配置的cluster.routing.allocation.include.tag參數中中添加2個值:node1和node2,那么最終索引的分片會分配到第一個節點和第二個節點中(從左到右數)。總結一下:對于帶有include allocation參數類型的結點,ElasticSearch會考慮把分片分配到該節點,但是并不意味著ElasticSearch一定會把分片分配到節點。</li>
<li>require:這個屬性是ElasticSearch 0.90版本引入到allocation filter中去的。它需要節點的所有相關屬性值都滿足它設定的值。比如,如果我們往配置文件中添加cluster.routing.allocation.require.tag參數并設其值為node1,添加cluster.routing.allocation.require.group參數并設其值為groupA,最終所有的分片將會分配到第一個節點(IP值為192.168.2.1的節點)</li>
<li>exclude:這個屬性允許我們在allocation過程中排除匹配屬性值的節點。比如,如果我們設置cluster.routing.allocation.include.tag的值為groupA,最終我們的索引分片只會分配到IP值為192.168.3.1和192.168.3.2的節點上(例子中的第3和第4個節點)。</li>
</ul>
</p>
<!--note structure -->
<div style="height:80px;width:650px;text-indent:0em;">
<div style="float:left;width:13px;height:100%; background:black;">
<img src="../lm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
<div style="float:left;width:50px;height:100%;position:relative;">
<img src="../note.png" style="position:absolute; top:30%; "/>
</div>
<div style="float:left; width:550px;height:100%;">
<p style="font-size:13px;margin-top:5px;">屬性值可以使用簡單的正則表達式。比如,如果我們包含所有group屬性中屬性值以字符串group開頭的結點,可以設置cluster.routing.allocation.include.group的值為group*。在我們的樣例集群中,它會匹配到group參數值為groupA和groupB的節點。
</p>
</div>
<div style="float:left;width:13px;height:100%;background:black;">
<img src="../rm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
</div> <!-- end of note structure -->
<h4>運行時allocation參數更新</h4>
<p>除了可以在elasticsearch.yml文件中設置前面討論的屬性,當集群在線時,我們也可以通過update API來實時更新這些參數。</p>
<h5>索引層面的參數更新</h5>
<p>如果想更新給定索引(比如例子中的mastering索引)的配置信息,我們就要運行運行如下的命令:
<blockquote>curl -XPUT 'localhost:9200/mastering/\_settings' -d '{
"index.routing.allocation.require.group": "groupA"
}' </blockquote>
正如你所看到的,命令被發送到給定索引的\_settings端點。在一條命令中可以包含多個屬性。
<h5>集群層面的參數更新</h5>
<p>如果想更新整個集群的配置信息,我們就要運行運行如下的命令:
<blockquote>curl -XPUT 'localhost:9200/\_cluster/\_settings' -d '{
"transient" : {
"cluster.routing.allocation.require.group": "groupA"
}
}' </blockquote>
正如你所看到的,命令被發送到\_cluster\_settings端點。在一條命令中可以包含多個屬性。請記住上面命令中transient關鍵字,它表示設置的屬性在集群重啟后就不再生效。如果希望設置的屬性永久生效,用persistent屬性代替transient屬性就可以了。下面的命令示例將會使用用戶設置在系統重啟后依然生效:
<blockquote>curl -XPUT 'localhost:9200/\_cluster/\_settings' -d '{
"peristent" : {
"cluster.routing.allocation.require.group": "groupA"
}
}' </blockquote>
</p>
<!--note structure -->
<div style="height:80px;width:650px;text-indent:0em;">
<div style="float:left;width:13px;height:100%; background:black;">
<img src="../lm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
<div style="float:left;width:50px;height:100%;position:relative;">
<img src="../note.png" style="position:absolute; top:30%; "/>
</div>
<div style="float:left; width:550px;height:100%;">
<p style="font-size:13px;margin-top:5px;">請注意,在相應的結節上運行上面的命令時,會導致分片在節點間的移動。
</p>
</div>
<div style="float:left;width:13px;height:100%;background:black;">
<img src="../rm.png" height="70px" width="13px" style="margin-top:5px;"/>
</div>
</div> <!-- end of note structure -->
<h3>限定每個分片上節點的數量</h3>
<p>除了前面提到的那些屬性,我們也允許用戶自定義每個節點上能夠分配的分片(主分片和分片副本)數量。為了實現這個功能,用戶需要在index.routing.allocation.total\_shards\_per\_node屬性中設置相應的值。比如在elasticsearch.yml文件中,我們應該設置如下:
<blockquote>
index.routing.allocation.total\_shards\_per\_node:4
</blockquote>
這個屬性規定了每個節點中,單個索引最多允許分配4個分片。這個屬性也可以通過update API在線上實時修改:
<blockquote>
curl -XPUT 'localhost:9200/mastering/\_settings' -d '{
"index.routing.allocation.total\_shards\_per\_node": "4"
}'
</blockquote>
現在,讓我們看看在elasticsearch.yml文件中配置了allocation的相關屬性后,幾個單索引集群會變成什么樣。
</p>
<h4>"結點包含"屬性</h4>
<p>現在通過我們的示例集群來看看allocation inclusion 是怎么工作的。最開始,用如下的命令創建一個mastering索引。
<blockquote>curl -XPOST 'localhost:9200/mastering' -d '{
"settings" : {
"index" : {
"number\_of\_shards" : 2,
"number\_of\_replicas" : 0
}
}
}'</blockquote>
創建索引后,試著執行如下的命令:
<blockquote>
curl -XPUT 'localhost:9200/mastering/\_settings' -d '{
"index.routing.allocation.include.tag": "node1",
"index.routing.allocation.include.group": "groupA",
"index.routing.allocation.total\_shards\_per\_node": 1
}'
</blockquote>
如果讓索引狀態可視化,那么集群看起來應該跟下面的圖差不多.
</p>
<center><img src="../43-include.png"/></center>
<p>正如你所看見的,Mastering索引的分片只分配到了tag屬性值為node1或者group屬性值為groupA的節點。</p>
<h4>"結點必須"屬性</h4>
<p>現在對我們的示例集群再回收利用(假定集群中已經沒有任何索引存在)。我們再一次用如下的命令創建一個mastering索引:
<blockquote>curl -XPOST 'localhost:9200/mastering' -d '{
"settings" : {
"index" : {
"number\_of\_shards" : 2,
"number\_of\_replicas" : 0
}
}
}'</blockquote>
隨后,試著執行下面命令:
<blockquote>curl -XPUT 'localhost:9200/mastering/\_settings' -d '{
"index.routing.allocation.require.tag": "node1",
"index.routing.allocation.require.group": "groupA"
}'</blockquote>
如果讓索引狀態可視化,那么集應該跟如下圖所示:
</p>
<center><img src="../43-require.png"/></center>
<p>我們可以看到圖示跟使用include屬性有些不同。這是因為我們告訴ElasticSearch把Mastering索引的分片只分配到滿足require參數所有設定值的節點上,在本例中只有第一個節點滿足條件。</p>
<h4>"結點排除"屬性</h4>
<p>我們再一次使用示例集群,并且用如下的命令創建mastering索引:
<blockquote>
curl -XPOST 'localhost:9200/mastering' -d '{
"settings" : {
"index" : {
"number\_of\_shards" : 2,
"number\_of\_replicas" : 0
}
}
}'
</blockquote>
隨后,試著執行下面的命令來測試allocation exclusion屬性:
<blockquote>
curl -XPUT 'localhost:9200/mastering/\_settings' -d '{
"index.routing.allocation.exclude.tag": "node1",
"index.routing.allocation.require.group": "groupA"
}'
</blockquote>
接下來,查看集群中各個節點的狀態:
</p>
<center><img src="../43-exclude.png"/></center>
<p>正如所見的那樣,我們需要group屬性值為groupA,但同時我們又要排除tag屬性中值為node1的節點。這導致Mastering索引的分片被分配到了IP地址為192.168.2.2的節點上,這也是我們所希望的。</p>
<h3>其它的shard allocation屬性</h3>
<p>除了前面提到的那些屬性,在配置shard allocation時,ElasticSearch還提供了其它的幾個特性。下面我們一起來了解一下這些屬性,看看集群中還有哪些是我們可以控制的<ul>
<li>cluster.routing.allocation.allow\_rebalance: 這個屬性用來控制rebalancing發生的時間,它是基于集群中分片的狀態來判斷的。這個屬性有以下幾個可選值:[always,indice\_primaries\_active, indices\_all\_active]。如果設置屬性值為always,則rebalancing操作時,不用判斷集群中分片的狀態。(這個值要小心使用,因為它能導致集群出現高負載狀態);如果設置屬性值為indice\_primaries\_active,當所有的主分片都可用時,rebalancing才會發生,如果設置屬性值為indices\_all\_active,那么必須所有分片(主分片和分片副本)都已經分配就位,rebalancing才會發生。默認值是indices\_all\_active。</li>
<li>cluster.routing.allocation.cluster\_concurrent\_rebalance:該屬性的默認值為2,指定了集群中同一時間允許的rebalance操作的并發數。如果該值設置得比較大,將會導致比較高的I/O,比較頻繁的網絡活動以及比較高的節點負載。</li>
<li>cluster.routing.allocation.node\_initial\_primaries\_recoveries:該屬性指定了每個節點可以同時恢復的主分片數量。由于主分片的恢復通常比較快,所以就算該值設置得比較高也不會給節點帶來太大的壓力。該屬性的默認值是4。</li>
<li>cluster.routing.allocation.node\_concurrent\_recoveries:該屬性值默認為2。用來指定單節點上恢復操作的并發數。需要記住的是,如果值設置的過大,將到導致非常頻繁的I/O活動。</li>
<li>cluster.routing.allocation.disable\_new\_allocation:該屬性值默認為flase。用來禁止新創建的索引分配分片(主分片和分片副本都算在內)。該屬性可以用于以下場景:出于某些原因,希望新創建的索引暫時不進行分片的分配。該屬性同時也可以用來禁止現有的索引分配新的分片,只需要在該索引中設置index.routing.allocation.disable\_new\_allocation屬性的值為true即可。</li>
<li>cluster.routing.allocation.disable\_allocation:該屬性的默認值是false,用來禁止分配已經創建好的分片和分片副本。需要注意把分片副本提升成主分片(在主分片不存在時)操作并不屬于分片分配,所以即使該屬性值設置為true,對分片提升操作也沒有影響。該屬性可以用于以下場景:需要短時間禁止新創建的索引進行分片的分配。</li>
<li>cluster.routing.allocation.disable\_replica\_allocation:該屬性值默認為false,如果該屬性值設置為true,分片副本的分配將會被禁止。該屬性可用于以下場景:需要暫時停止分片副本的分配。該屬性也可通過在索引的設置項中設置index.routing.allocation.disable\_replica\_allocation為true來禁止某個特定索引的分片副本的分配。 </li>
</ul>
上面提到的所有屬性都是既可以在elasticsearch.yml文件中設置,也可以用update API來設置。但是在實際應用中,用戶一般只使用update API來使設置生效,比如
cluster.routing.allocation.disable\_new\_
allocation,
cluster.routing.allocation.disable\_allocation, 或者
cluster.routing.allocation.disable\_replica\_allocation
</p>
</div>
- 前言
- 第1章 認識Elasticsearch
- 認識Apache Lucene
- 熟悉Lucene
- 總體架構
- 分析你的文本
- Lucene查詢語言
- 認識 ElasticSearch
- 基本概念
- ElasticSearch背后的核心理念
- ElasticSearch的工作原理
- 本章小結
- 第2章 強大的用戶查詢語言DSL
- Lucene默認打分算法
- 查詢重寫機制
- 重排序
- 批處理
- 查詢結果的排序
- Update API
- 使用filters優化查詢
- filters和scope在ElasticSearch Faceting模塊的應用
- 本章小結
- 第3章 索引底層控制
- 第4章 探究分布式索引架構
- 選擇恰當的分片數量和分片副本數量
- 路由功能淺談
- 調整集群的分片分配
- 改變分片的默認分配方式
- 查詢的execution preference
- 學以致用
- 本章小結
- 第5章 管理Elasticsearch
- 選擇正確的directory實現類——存儲模塊
- Discovery模塊的配置
- 索引段數據統計
- 理解ElasticSearch的緩存
- 本章小結
- 第6章 應對突發事件
- 第7章 優化用戶體驗
- 第8章 ElasticSearch Java API
- 第9章 開發ElasticSearch插件