elasticsearch 路由文檔到分片


路由文檔到分片

當你索引一個文檔,它被存儲在單獨一個主分片上。Elasticsearch是如何知道文檔屬於哪個分片的呢?當你創建一個新文檔,它是如何知道是應該存儲在分片1還是分片2上的呢?

進程不能是隨機的,因為我們將來要檢索文檔。事實上,它根據一個簡單的算法決定:

shard = hash(routing) % number_of_primary_shards

routing值是一個任意字符串,它默認是_id但也可以自定義。這個routing字符串通過哈希函數生成一個數字,然后除以主切片的數量得到一個余數(remainder),余數的范圍永遠是0number_of_primary_shards - 1,這個數字就是特定文檔所在的分片。

這也解釋了為什么主分片的數量只能在創建索引時定義且不能修改:如果主分片的數量在未來改變了,所有先前的路由值就失效了,文檔也就永遠找不到了。

有時用戶認為固定數量的主分片會讓之后的擴展變得很困難。現實中,有些技術會在你需要的時候讓擴展變得容易。

所有的文檔API(getindexdeletebulkupdatemget)都接收一個routing參數,它用來自定義文檔到分片的映射。自定義路由值可以確保所有相關文檔——例如屬於同一個人的文檔——被保存在同一分片上。我們將在《擴展》章節說明你為什么需要這么做。

參考: http://es.xiaoleilu.com/040_Distributed_CRUD/05_Routing.html

而我們為什么會需要自定義的Routing模式呢?首先默認的Routing模式在很多情況下都是能滿足我們的需求的——平均的數據分布、對我們來說是透明的、多數時候性能也不是問題。但是在我們更深入地理解我們的數據的特征之后,使用自定義的Routing模式可能會給我們帶來更好的性能。

通常情況下,ElasticSearch是如何把數據分發到各個分片中,哪個分片存儲哪一類的文檔等細節並不重要。因為查詢時,將查詢命令分發到每個分片 就OK了。唯一的關鍵點在於算法,將數據均等地分配到各個分片的算法。在刪除或者更新文檔時,情況就會變得有點復雜了。實際上,這也不是什么大問題。只要 保證分片算法在處理文檔時,對於相同的文檔標識生成相同的映射值就可以了。如果我們有這樣的分片算法,ElasticSearch就知道在處理文檔時,如 何定位到正確的分片。但是,在選擇文檔的存儲分片時,采用一個更加智能的辦法不就更省事兒了嗎?比如,把某一特定類型的書籍存儲到特定的分片上去,這樣在 搜索這一類書籍的時候就可以避免搜索其它的分片,也就避免了多個分片搜索結果的合並。這就是路由功能(routing)的用武之地。路由功能向 ElasticSearch提供一種信息來決定哪些分片用於存儲和查詢。同一個路由值將映射到同一個分片。這基本上就是在說:“通過使用用戶提供的路由值,就可以做到定向存儲,定向搜索。”

假設你有一個100個分片的索引。當一個請求在集群上執行時會發生什么呢?

1. 這個搜索的請求會被發送到一個節點

2. 接收到這個請求的節點,將這個查詢廣播到這個索引的每個分片上(可能是主分片,也可能是復制分片)

3. 每個分片執行這個搜索查詢並返回結果

4. 結果在通道節點上合並、排序並返回給用戶


因為默認情況下,Elasticsearch使用文檔的ID(類似於關系數據庫中的自增ID,當然,如果不指定ID的 話,Elasticsearch使用的是隨機值)將文檔平均的分布於所有的分片上,這導致了Elasticsearch不能確定文檔的位置,所以它必須將 這個請求廣播到所有的100個分片上去執行。這同時也解釋了為什么主分片的數量在索引創建的時候是固定下來的,並且永遠不能改變。因為如果分片的數量改變 了,所有先前的路由值就會變成非法了,文檔相當於丟失了。

原來的查詢語句:“請告訴我,USER1的文檔數量一共有多少”

使用自定義Routing(在USESR ID上)后的查詢語句:“請告訴我,USER1的文檔數量一共有多少,它就在第三個分片上,其它的分片就不要去掃描了”


指定個性化路由

所有的文檔API(get,index,delete,update和mget)都能接收一個routing參數,可以用來形成個性化文檔分片映射。一個個性化的routing值可以確保相關的文檔存儲到同樣的分片上——比如,所有屬於同一個用戶的文檔。


第一種方法,也是比較直觀的方法就是直接在請求的URL中指定routing參數:

    curl -XPOST 'http://localhost:9200/store/order?routing=user123' -d '  
    {  
        "productName": "sample",  
        "customerID": "user123"  
    }'  

這樣我們就按照用戶的customerID的值將具有相同customerID的文檔置於同一分片上了。

第二種方法就是直接從文檔中提取到對應的路由值:

    curl -XPUT 'http://localhost:9200/store/order/_mapping' -d '  
    {  
        "order": {  
            "_routing": {  
                "required": true,  
                "path": "customerID"  
            }  
        }  
    }'  

這樣的方法和第一種方法在效果上一樣的,但是有一點需要注意,相比於第一種方法這種方法的效率稍低,因為第一種方法直接就在請求的參數中確定了路由的值,而第二種方法中,首先需要將文檔讀入之后,再從中提取到對應的路由值。

利用路由機制的查詢

利用路由機制的查詢也是非常簡單明了的,只需要在查詢中指定對應的路由值即可:

    curl -XGET 'http://localhost:9200/store/order/_search?routing=user123' -d '  
    {  
        "query": {  
            "filtered": {  
                "query": {  
                    "match_all": {}  
                },  
                "filter": {  
                    "term": {  
                        "userID": "user123"  
                    }  
                }  
            }  
        }  
    }'  

 

通過指定的路由值,我們就可以直接定位到user123的文檔所在的分片,而不用一股腦的向索引的所有節點都發送請求。這樣的話,會大大減少系統資源的浪費。

 

當然,也可以同時指定多個路由值,方法也是顯而易見的,只需要在查詢參數中指定多個路由值即可:

    curl -XGET 'http://localhost:9200/forum/posts/?routing=Admin,Moderator' -d '{}'  

路由機制的總結

實際上,如果不明確指明使用路由機制,實際上路由機制也是在發揮作用的,只是默認的路由值是文檔的id而已。而個性化路由的需求主要是和業務相關 的。默認的路由(如果是自動的生成的id)直觀上會把所有的文檔隨機分配到一個分片上,而個性化的路由值就是和業務相關的了。這也會造成一些潛在的問題, 比如user123本身的文檔就非常多,有數十萬個,而其他大多數的用戶只有幾個文檔,這樣的話就會導致user123所在的分片較大,出現數據偏移的情 況,特別是多個這樣的用戶處於同一分片的時候,現象會更明顯。具體的使用還是要結合實際的應用場景來選擇的。

參考:http://blog.csdn.net/cnweike/article/details/38531997


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM