Elasticsearch的路由機制與其分片機制有着直接的關係。Elasticsearch的路由機制便是經過哈希算法,將具備相同哈希值的文檔放置到同一個主分片中。這個和經過哈希算法來進行負載均衡幾乎是同樣的。oop
而Elasticsearch也有一個默認的路由算法:它會將文檔的ID值做爲依據將其哈希到相應的主分片上,這種算法基本上會保持全部數據在全部分片上的一個平均分佈,而不會產生數據熱點。post
而咱們爲何會須要自定義的Routing模式呢?首先默認的Routing模式在不少狀況下都是能知足咱們的需求的——平均的數據分佈、對咱們來講是透明的、多數時候性能也不是問題。可是在咱們更深刻地理解咱們的數據的特徵以後,使用自定義的Routing模式可能會給咱們帶來更好的性能。性能
假設你有一個100個分片的索引。當一個請求在集羣上執行時會發生什麼呢?ui
1. 這個搜索的請求會被髮送到一個節點url
2. 接收到這個請求的節點,將這個查詢廣播到這個索引的每一個分片上(多是主分片,也多是複製分片)
3. 每一個分片執行這個搜索查詢並返回結果
4. 結果在通道節點上合併、排序並返回給用戶
由於默認狀況下,Elasticsearch使用文檔的ID(相似於關係數據庫中的自增ID,固然,若是不指定ID的話,Elasticsearch使用的是隨機值)將文檔平均的分佈於全部的分片上,這致使了Elasticsearch不能肯定文檔的位置,因此它必須將這個請求廣播到全部的100個分片上去執行。這同時也解釋了爲何主分片的數量在索引建立的時候是固定下來的,而且永遠不能改變。由於若是分片的數量改變了,全部先前的路由值就會變成非法了,文檔至關於丟失了。
而自定義的Routing模式,可使咱們的查詢更具目的性。咱們沒必要盲目地去廣播查詢請求,取而代之的是:咱們要告訴Elasticsearch咱們的數據在哪一個分片上。
原來的查詢語句:「請告訴我,USER1的文檔數量一共有多少」
使用自定義Routing(在USESR ID上)後的查詢語句:「請告訴我,USER1的文檔數量一共有多少,它就在第三個分片上,其它的分片就不要去掃描了」
全部的文檔API(get,index,delete,update和mget)都能接收一個routing參數,能夠用來造成個性化文檔分片映射。一個個性化的routing值能夠確保相關的文檔存儲到一樣的分片上——好比,全部屬於同一個用戶的文檔。
第一種方法,也是比較直觀的方法就是直接在請求的URL中指定routing參數:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XPOST 'http://localhost:9200/store/order?routing=user123' -d '
{
"productName": "sample",
"customerID": "user123"
}'
這樣咱們就按照用戶的customerID的值將具備相同customerID的文檔置於同一分片上了。
第二種方法就是直接從文檔中提取到對應的路由值:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XPUT 'http://localhost:9200/store/order/_mapping' -d '
{
"order": {
"_routing": {
"required": true,
"path": "customerID"
}
}
}'
這樣的方法和第一種方法在效果上同樣的,可是有一點須要注意,相比於第一種方法這種方法的效率稍低,由於第一種方法直接就在請求的參數中肯定了路由的值,而第二種方法中,首先須要將文檔讀入以後,再從中提取到對應的路由值。
利用路由機制的查詢也是很是簡單明瞭的,只須要在查詢中指定對應的路由值便可:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XGET 'http://localhost:9200/store/order/_search?routing=user123' -d '
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"term": {
"userID": "user123"
}
}
}
}
}'
經過指定的路由值,咱們就能夠直接定位到user123的文檔所在的分片,而不用一股腦的向索引的全部節點都發送請求。這樣的話,會大大減小系統資源的浪費。
固然,也能夠同時指定多個路由值,方法也是顯而易見的,只須要在查詢參數中指定多個路由值便可:
[plain] view plaincopy
<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
curl -XGET 'http://localhost:9200/forum/posts/?routing=Admin,Moderator' -d '{}'
實際上,若是不明確指明使用路由機制,實際上路由機制也是在發揮做用的,只是默認的路由值是文檔的id而已。而個性化路由的需求主要是和業務相關的。默認的路由(若是是自動的生成的id)直觀上會把全部的文檔隨機分配到一個分片上,而個性化的路由值就是和業務相關的了。這也會形成一些潛在的問題,好比user123自己的文檔就很是多,有數十萬個,而其餘大多數的用戶只有幾個文檔,這樣的話就會致使user123所在的分片較大,出現數據偏移的狀況,特別是多個這樣的用戶處於同一分片的時候,現象會更明顯。具體的使用仍是要結合實際的應用場景來選擇的。