from:http://www.infoq.com/cn/articles/anatomy-of-an-elasticsearch-cluster-part02
剖析Elasticsearch集群系列涵蓋了當今最流行的分布式搜索引擎Elasticsearch的底層架構和原型實例。
本文是這個系列的第二篇,我們將討論Elasticsearch如何處理分布式的三個C((共識(consensus)、并發(concurrency)和一致(consistency))的問題、Elasticsearch分片的內部概念,比如translog(預寫日志,WAL(Write Ahead Log)),以及Lucene中的段。
本系列已經得到原文著者Ronak Nathani的授權
在本系列的前一篇中,我們討論了Elasticsearch的底層存儲模型及CRUD(創建、讀取、更新和刪除)操作的工作原理。在本文中,我將分享Elasticsearch是如何應對分布式系統中的一些基本挑戰的,以及分片的內部概念。這其中包括了一些操作方面的事情,Insight Data的工程師們已經在使用Elasticsearch構建的數據平臺之上成功地實踐并真正理解。我將在本文中主要講述:
共識——裂腦問題及法定票數的重要性
共識是分布式系統的一項基本挑戰。它要求系統中的所有進程/節點必須對給定數據的值/狀態達成共識。已經有很多共識算法諸如Raft、Paxos等,從數學上的證明了是行得通的。但是,Elasticsearch卻實現了自己的共識系統(zen discovery),Elasticsearch之父Shay Banon在這篇文章中解釋了其中的原因。zen discovery模塊包含兩個部分:
- Ping: 執行節點使用ping來發現彼此
- 單播(Unicast):該模塊包含一個主機名列表,用以控制哪些節點需要ping通
Elasticsearch是端對端的系統,其中的所有節點彼此相連,有一個master節點保持活躍,它會更新和控制集群內的狀態和操作。建立一個新的Elasticsearch集群要經過一次選舉,選舉是ping過程的一部分,在所有符合條件的節點中選取一個master,其他節點將加入這個master節點。ping間隔參數ping_interval
的默認值是1秒,ping超時參數ping_timeout
的默認值是3秒。因為節點要加入,它們會發送一個請求給master節點,加入超時參數join_timeout
的默認值是ping_timeout
值的20倍。如果master出現問題,那么群集中的其他節點開始重新ping以啟動另一次選舉。這個ping的過程還可以幫助一個節點在忽然失去master時,通過其他節點發現master。
注意:默認情況下,client節點和data節點不參與這個選舉過程。可以在elasticsearch.yml配置文件中,通過設置discovery.zen.master_election.filter_client
屬性和discovery.zen.master_election.filter_data
屬性為false
來改變這種默認行為。
故障檢測的原理是這樣的,master節點會ping所有其他節點,以檢查它們是否還活著;然后所有節點ping回去,告訴master他們還活著。
如果使用默認的設置,Elasticsearch有可能遭到裂腦問題的困擾。在網絡分區的情況下,一個節點可以認為master死了,然后選自己作為master,這就導致了一個集群內出現多個master。這可能會導致數據丟失,也可能無法正確合并數據。可以按照如下公式,根據有資格參加選舉的節點數,設置法定票數屬性的值,來避免爆裂的發生。
discovery.zen.minimum_master_nodes = int(# of master eligible nodes/2)+1

這個屬性要求法定票數的節點加入新當選的master節點,來完成并獲得新master節點接受的master身份。對于確保群集穩定性和在群集大小變化時動態地更新,這個屬性是非常重要的。圖a和b演示了在網絡分區的情況下,設置或不設置minimum_master_nodes
屬性時,分別發生的現象。
注意:對于一個生產集群來說,建議使用3個節點專門做master,這3個節點將不服務于任何客戶端請求,而且在任何給定時間內總是只有1個活躍。
我們已經搞清楚了Elasticsearch中共識的處理,現在讓我們來看看它是如何處理并發的。
并發
Elasticsearch是一個分布式系統,支持并發請求。當創建/更新/刪除請求到達主分片時,它也會被平行地發送到分片副本上。但是,這些請求到達的順序可能是亂序的。在這種情況下,Elasticsearch使用樂觀并發控制,來確保文檔的較新版本不會被舊版本覆蓋。
每個被索引的文檔都擁有一個版本號,版本號在每次文檔變更時遞增并應用到文檔中。這些版本號用來確保有序接受變更。為了確保在我們的應用中更新不會導致數據丟失,Elasticsearch的API允許我們指定文件的當前版本號,以使變更被接受。如果在請求中指定的版本號比分片上存在的版本號舊,請求失敗,這意味著文檔已經被另一個進程更新了。如何處理失敗的請求,可以在應用層面來控制。Elasticsearch還提供了其他的鎖選項,可以通過這篇來閱讀。
當我們發送并發請求到Elasticsearch后,接下來面對的問題是——如何保證這些請求的讀寫一致?現在,還無法清楚回答,Elasticsearch應落在CAP三角形的哪條邊上,我不打算在這篇文章里解決這個素來已久的爭辯。

但是,我們要一起看下如何使用Elasticsearch實現寫讀一致。
一致——確保讀寫一致
對于寫操作而言,Elasticsearch支持的一致性級別,與大多數其他的數據庫不同,允許預檢查,來查看有多少允許寫入的可用分片。可選的值有quorum、one和all。默認的設置為quorum,也就是說只有當大多數分片可用時才允許寫操作。即使大多數分片可用,還是會因為某種原因發生寫入副本失敗,在這種情況下,副本被認為故障,分片將在一個不同的節點上重建。
對于讀操作而言,新的文檔只有在刷新時間間隔之后,才能被搜索到。為了確保搜索請求的返回結果包含文檔的最新版本,可設置replication為sync(默認),這將使操作在主分片和副本碎片都完成后才返回寫請求。在這種情況下,搜索請求從任何分片得到的返回結果都包含的是文檔的最新版本。即使我們的應用為了更高的索引率而設置了replication=async,我們依然可以為搜索請求設置參數_preference為primary。這樣,搜索請求將查詢主分片,并確保結果中的文檔是最新版本。
我們已經了解了Elasticsearch如何處理共識、并發和一致,讓我們來看看分片內部的一些主要概念,正是這些特點讓Elasticsearch成為一個分布式搜索引擎。
Translog(預寫日志)
因為關系數據庫的發展,預寫日志(WAL)或者事務日志(translog)的概念早已遍及數據庫領域。在發生故障的時候,translog能確保數據的完整性。translog的基本原理是,變更必須在數據實際的改變提交到磁盤上之前,被記錄下來并提交。
當新的文檔被索引或者舊的文檔被更新時,Lucene索引將發生變更,這些變更將被提交到磁盤以持久化。這是一個很昂貴的操作,如果在每個請求之后都被執行。因此,這個操作在多個變更持久化到磁盤時被執行一次。正如我們在上一篇文章中描述的那樣,Lucene提交的沖洗(flush)操作默認每30分鐘執行一次或者當translog變得太大(默認512MB)時執行。在這樣的情況下,有可能失去2個Lucene提交之間的所有變更。為了避免這種問題,Elasticsearch采用了translog。所有索引/刪除/更新操作被寫入到translog,在每個索引/刪除/更新操作執行之后(默認情況下是每5秒),translog會被同步以確保變更被持久化。translog被同步到主分片和副本之后,客戶端才會收到寫請求的確認。
在兩次Lucene提交之間發生硬件故障的情況下,可以通過重放translog來恢復自最后一次Lucene提交前的任何丟失的變更,所有的變更將會被索引所接受。
注意:建議在重啟Elasticsearch實例之前顯式地執行沖洗translog,這樣啟動會更快,因為要重放的translog被清空。POST /_all/_flush命令可用于沖洗集群中的所有索引。
使用translog的沖洗操作,在文件系統緩存中的段被提交到磁盤,使索引中的變更持久化。現在讓我們來看看Lucene的段。
Lucene的段
Lucene索引是由多個段組成,段本身是一個功能齊全的倒排索引。段是不可變的,允許Lucene將新的文檔增量地添加到索引中,而不用從頭重建索引。對于每一個搜索請求而言,索引中的所有段都會被搜索,并且每個段會消耗CPU的時鐘周、文件句柄和內存。這意味著段的數量越多,搜索性能會越低。
為了解決這個問題,Elasticsearch會合并小段到一個較大的段(如下圖所示),提交新的合并段到磁盤,并刪除那些舊的小段。

這會在后臺自動執行而不中斷索引或者搜索。由于段合并會耗盡資源,影響搜索性能,Elasticsearch會節制合并過程,為搜索提供足夠的可用資源。
接下來有什么?
從搜索請求角度來說,一個Elasticsearch索引中給定分片內的所有Lucene段都會被搜索,但是,從Elasticsearch集群角度而言,獲取所有匹配的文檔或者深入有序結果文檔是有害的。在本系列的后續文章中我們將揭曉原因,讓我們來看一下接下來的主題,內容包括了一些在Elasticsearch中為相關性搜索結果的低延遲所做的權衡。
- Elasticsearch準實時性方面的內容
- 為什么搜索中的深層分頁是有害的?
- 搜索相關性計算中的權衡之道
查看原文地址:Anatomy of an Elasticsearch Cluster: Part II