配置高性能ElasticSearch集羣的9個小貼士

轉載自:http://www.linuxidc.com/Linux/2017-01/139165.htm
Loggly服務底層的很多核心功能都使用了ElasticSearch作爲搜索引擎。就像Jon Gifford(譯者注:Loggly博客作者之一)在他近期關於“ElasticSearch vs Solr”的文章中所述,日誌管理在搜索技術方面產生一些粗暴的需求,堅持下來以後,它必須能夠:

在超大規模數據集上可靠地進行準實時索引 - 在我們的案例中,每秒有超過100,000個日誌事件與此同時,在該索引上可靠高效地處理超大量的搜索請求

當時我們正在構建Gen2日誌管理服務,想保證使用的所有ElasticSearch配置信息,可以獲得最優的索引和搜索性能。悲劇的是,我們發現想在ElasticSearch文檔裏找到這樣的信息非常困難,因爲它們不只在一個地方。本文總結了我們的學習經驗,可作爲一個配置屬性的參考檢查單(checklist)用於優化你自己應用中的ES。

小貼士1:規劃索引、分片 以及集羣增長情況

ES使得創建大量索引和超大量分片非常地容易,但更重要的是理解每個索引和分片都是一筆開銷。如果擁有太多的索引或分片,單單是管理負荷就會影響到ES集羣的性能,潛在地也會影響到可用性方面。這裏我們專注於管理負荷,但運行大量的索引/分片依然會非常顯著地影響到索引和檢索性能。

我們發現影響管理負荷的最大因素是集羣狀態數據的大小,因爲它包含了集羣中每個索引的所有mapping數據。我們曾經一度有單個集羣擁有超過900MB的集羣狀態數據。該集羣雖然在運行但並不可用。

讓我們通過一些數據來瞭解到底發生了什麼 。。。。。。

假如有一個索引包含50k的mapping數據(我們當時是有700個字段)。如果每小時生成一個索引,那麼每天將增加24 x 50k的集羣狀態數據,或者1.2MB。如果需要在系統中保留一年的數據,那麼集羣狀態數據將高達438MB(以及8670個索引,43800個分片)。如果與每天一個索引(18.25MB,365個索引,1825個分片)作比較,會看到每小時的索引策略將會是一個完全不同的境況。

幸運的是,一旦系統中有一些真實數據的話,實際上非常容易做這些預測。我們應當能夠看到集羣必須處理多少狀態數據和多少索引/分片。在上到生產環境之前真的應該演練一下,以便防止凌晨3:00收到集羣掛掉的電話告警。

在配置方面,我們完全可以控制系統中有多少索引(以及有多少分片),這將讓我們遠離危險地帶。

小貼士2:在配置前瞭解集羣的拓撲結構

Loggly通過獨立的master節點和data節點來運行ES。這裏不討論太多的部署細節(請留意後續博文),但爲了做出正確的配置選擇,需要先確定部署的拓撲結構。

另外,我們爲索引和搜索使用單獨的ES client節點。這將減輕data節點的一些負載,更重要的是,這樣我們的管道就可以和本地客戶端通信,從而與集羣的其他節點通信。

可通過設置以下兩個屬性的值爲true或false來創建ES的data節點和master節點:

Master node: node.master:true node.data:false

Data node: node.master:false node.data:true

Client node: node.master:false node.data:false
以上是相對容易的部分,現在來看一些值得關注的ES高級屬性。對大多數部署場景來說默認設置已經足夠了,但如果你的ES使用情況和我們在log管理中遇到的一樣難搞,你將會從下文的建議中受益良多。

小貼士3: 內存設置

Linux把它的物理RAM分成多個內存塊,稱之爲分頁。內存交換(swapping)是這樣一個過程,它把內存分頁複製到預先設定的叫做交換區的硬盤空間上,以此釋放內存分頁。物理內存和交換區加起來的大小就是虛擬內存的可用額度。

內存交換有個缺點,跟內存比起來硬盤非常慢。內存的讀寫速度以納秒來計算,而硬盤是以毫秒來計算,所以訪問硬盤比訪問內存要慢幾萬倍。交換次數越多,進程就越慢,所以應該不惜一切代價避免內存交換的發生。

ES的mlockall屬性允許ES節點不交換內存。(注意只有Linux/Unix系統可設置。)這個屬性可以在yaml文件中設置:

bootstrap.mlockall: true
在5.x版本中,已經改成了bootstrap.memory_lock: true.

mlockall默認設置成false,即ES節點允許內存交換。一旦把這個值加到屬性文件中,需要重啓ES節點纔可生效。可通過以下方式來確定該值是否設置正確:

curl http://localhost:9200/_nodes/process?pretty
如果你正在設置這個屬性,請使用-DXmx選項或ES_HEAP_SIZE屬性來確保ES節點分配了足夠的內存。

小貼士4:discovery.zen屬性控制ElasticSearch的發現協議

Elasticsearch默認使用服務發現(Zen discovery)作爲集羣節點間發現和通信的機制。Azure、EC2和GCE也有使用其他的發現機制。服務發現由discovery.zen.*開頭的一系列屬性控制。

在0.x和1.x版本中同時支持單播和多播,且默認是多播。所以要在這些版本的ES中使用單播,需要設置屬性discovery.zen.ping.multicast.enabled爲false。

從2.0開始往後服務發現就僅支持單播了。

首先需要使用屬性discovery.zen.ping.unicast.hosts指定一組通信主機。方便起見,在集羣中的所有主機上爲該屬性設置相同的值,使用集羣節點的名稱來定義主機列表。

屬性discovery.zen.minimum_master_nodes決定了有資格作爲master的節點的最小數量,即一個應當“看見”集羣範圍內運作的節點。如果集羣中有2個以上節點,建議設置該值爲大於1。一種計算方法是,假設集羣中的節點數量爲N,那麼該屬性應該設置爲N/2+1。

Data和master節點以兩種不同方式互相探測:

通過master節點ping集羣中的其他節點以驗證他們處於運行狀態通過集羣中的其他節點ping master節點以驗證他們處於運行狀態或者是否需要初始化一個選舉過程

節點探測過程通過discover.zen.fd.ping_timeout屬性控制,默認值是30s,決定了節點將會等待響應多久後超時。當運行一個較慢的或者擁堵的網絡時,應該調整這個屬性;如果在一個慢速網絡中,將該屬性調大;其值越大,探測失敗的機率就越小。

Loggly的discovery.zen相關屬性配置如下:

discovery.zen.fd.ping_timeout: 30s

discovery.zen.minimum_master_nodes: 2

discovery.zen.ping.unicast.hosts: [“esmaster01″,”esmaster02″,”esmaster03″]
以上屬性配置表示節點探測將在30秒內發生,因爲設置了discovery.zen.fd.ping_timeout屬性。另外,其他節點應當探測到最少兩個master節點(我們有3個master)。我們的單播主機是esmaster01、 esmaster02、esmaster03。

小貼士5:當心DELETE _all

必須要了解的一點是,ES的DELETE API允許用戶僅僅通過一個請求來刪除索引,支持使用通配符,甚至可以使用_all作爲索引名來代表所有索引。例如:

curl -XDELETE ‘http://localhost:9200/*/’
這個特性非常有用,但也非常危險,特別是在生產環境中。在我們的所有集羣中,已通過設置action.destructive_requires_name:true來禁用了它。

這項配置在1.0版本中開始引用,並取代了0.90版本中使用的配置屬性disable_delete_all_indices。

小貼士6:使用Doc Values

2.0及以上版本默認開啓Doc Values特性,但在更早的ES版本中必須顯式地設置。當進行大規模的排序和聚合操作時,Doc Values相比普通屬性有着明顯的優勢。本質上是將ES轉換成一個列式存儲,從而使ES的許多分析類特性在性能上遠超預期。

爲了一探究竟,我們可以在ES裏比較一下Doc Values和普通屬性。

當使用一個普通屬性去排序或聚合時,該屬性會被加載到屬性數據緩存中。一個屬性首次被緩存時,ES必須分配足夠大的堆空間,以便能保存每一個值,然後使用每個文檔的值逐步填充。這個過程可能會耗費一些時間,因爲可能需要從磁盤讀取他們的值。一旦這個過程完成,這些數據的任何相關操作都將使用這份緩存數據,並且會很快。如果嘗試填充太多的屬性到緩存,一些屬性將被回收,隨後再次使用到這些屬性時將會強制它們重新被加載到緩存,且同樣有啓動開銷。爲了更加高效,人們會想到最小化或淘汰,這意味着我們的屬性數量將受限於此種方式下的緩存大小。

相比之下,Doc Values屬性使用基於硬盤的數據結構,且能被內存映射到進程空間,因此不影響堆使用,同時提供實質上與屬性數據緩存一樣的性能。當這些屬性首次從硬盤讀取數據時仍然會有較小的啓動開銷,但這會由操作系統緩存去處理,所以只有真正需要的數據會被實際讀取。

Doc Values因此最小化了堆的使用(因爲垃圾收集),併發揮了操作系統文件緩存的優勢,從而可進一步最小化磁盤讀操作的壓力。

小貼士7:ElasticSearch配額類屬性設置指南

分片分配就是分配分片到節點的過程,可能會發生在初始化恢復、副本分配、或者集羣再平衡的階段,甚至發生在處理節點加入或退出的階段。

屬性cluster.routing.allocation.cluster_concurrent_rebalance決定了允許併發再平衡的分片數量。這個屬性需要根據硬件使用情況去適當地配置,比如CPU個數、IO負載等。如果該屬性設置不當,將會影響ES的索引性能。

cluster.routing.allocation.cluster_concurrent_rebalance:2

默認值是2,表示任意時刻只允許同時移動2個分片。最好將該屬性設置得較小,以便壓制分片再平衡,使其不影響索引。

另一個分片分配相關的屬性是cluster.routing.allocation.disk.threshold_enabled。如果該屬性設備爲true(默認值),在分配分片到一個節點時將會把可用的磁盤空間算入配額內。關閉該屬性會導致ES可能分配分片到一個磁盤可用空間不足的節點,從而影響分片的增長。

當打開時,分片分配會將兩個閥值屬性加入配額:低水位和高水位。

低水位定義ES將不再分配新分片到該節點的磁盤使用百分比。(默認是85%)高水位定義分配將開始從該節點遷移走分片的磁盤使用百分比。(默認是90%)

這兩個屬性都可以被定義爲磁盤使用的百分比(比如“80%”表示80%的磁盤空間已使用,或者說還有20%未��用),或者最小可用空間大小(比如“20GB”表示該節點還有20GB的可用空間)。

如果有很多的小分片,那麼默認值就非常保守了。舉個例子,如果有一個1TB的硬盤,分片是典型的10GB大小,那麼理論上可以在該節點上分配100個分片。在默認設置的情況下,只能分配80個分片到該節點上,之後ES就認爲這個節點已經滿了。

爲得到適合的配置參數,應該看看分片到底在變多大之後會結束他們的生命週期,然後從這裏反推,確認包括一個安全係數。在上面的例子中,只有5個分片寫入,所以需要一直確保有50GB的可用空間。對於一個1TB的硬盤,這個情形會變成95%的低水位線,並且沒有安全係數。額外的,比如一個50%的安全係數,意味着應該確保有75GB的可以空間,或者一個92.5%的低水位線。

小貼士8:Recovery屬性允許快速重啓

ES有很多恢複相關的屬性,可以提升集羣恢復和重啓的速度。最佳屬性設置依賴於當前使用的硬件(硬盤和網絡是最常見的瓶頸),我們能給出的最好建議是測試、測試、還是測試。

想控制多少個分片可以在單個節點上同時恢復,使用:

cluster.routing.allocation.node_concurrent_recoveries
恢復分片是一個IO非常密集的操作,所以應當謹慎調整該值。在5.x版本中,該屬性分爲了兩個:

cluster.routing.allocation.node_concurrent_incoming_recoveries

cluster.routing.allocation.node_concurrent_outgoing_recoveries
想控制單個節點上的併發初始化主分片數量,使用:

cluster.routing.allocation.node_initial_primaries_recoveries
想控制恢復一個分片時打開的並行流數量,使用:

indices.recovery.concurrent_streams
與流數量密切相關的,是用於恢復的總可用網絡帶寬:

indices.recovery.max_bytes_per_sec
除了所有這些屬性,最佳配置將依賴於所使用的硬件。如果有SSD硬盤以及萬兆光纖網絡,那麼最佳配置將完全不同於使用普通磁盤和千兆網卡。

以上所有屬性都將在集羣重啓後生效。

小貼士9:線程池屬性防止數據丟失

ElasticSearch節點有很多的線程池,用於提升一個節點中的線程管理效率。

在Loggly,索引時使用了批量操作模式,並且我們發現通過threadpool.bulk.queue_size屬性爲批量操作的線程池設置正確的大小,對於防止因批量重試而可能引起的數據丟失是極其關鍵的。

threadpool.bulk.queue_size: 5000
這會告訴ES,當沒有可用線程來執行一個批量請求時,可排隊在該節點執行的分片請求的數量。該值應當根據批量請求的負載來設置。如果批量請求數量大於隊列大小,就會得到一個下文展示的RemoteTransportException異常。

正如上文所述,一個分片包含一個批量操作隊列,所以這個數字需要大於想發送的併發批量請求的數量與這些請求的分片數的乘積。例如,一個單一的批量請求可能包含10個分片的數據,所以即使只發送一個批量請求,隊列大小也必須至少爲10。這個值設置太高,將會吃掉很多JVM堆空間(並且表明正在推送更多集羣無法輕鬆索引的數據),但確實能轉移一些排隊情況到ES,簡化了客戶端。

既要保持屬性值高於可接受的負載,又要平滑地處理客戶端代碼的RemoteTransportException異常。如果不處理該異常,將會丟失數據。我們模擬使用一個大小爲10的隊列來發送大於10個的批處理請求,獲得了以下所示異常。

RemoteTransportException[[][inet[/192.168.76.1:9300]][bulk/shard]]; nested:
EsRejectedExecutionException[rejected execution (queue capacity 10) on
org.elasticsearch.action.support.replication.TransportShardReplicationOperationActionAsyncShardOperationAction 1@13fe9be];
爲2.0版本以前的用戶再贈送一個小貼士:最小化Mapping刷新時間

如果你仍在使用2.0版本以前的ES,且經常會更新屬性mapping,那麼可能會發現集羣的任務等待隊列有一個較大的refresh_mappings請求數。對它自身來說,這並不壞,但可能會有滾雪球效應嚴重影響集羣性能。

如果確實遇到這種情況,ES提供了一個可配置參數來幫助應對。可按下述方式使用該參數:

indices.cluster.send_refresh_mapping: false
那麼,這是怎麼個意思,爲什麼可以湊效?

當索引中出現一個新的屬性時,添加該屬性的數據節點會更新它自己的mapping,然後把新的mapping發送給主節點。如果這個新的mapping還在主節點的等待任務隊列中,同時主節點發布了自己的下一個集羣狀態,那麼數據節點將接收到一個過時的舊版本mapping。通常這會讓它發送一個更新mapping的請求到主節點,因爲直到跟該數據節點有關,主節點一直都擁有錯誤的mapping信息。這是一個糟糕的默認行爲————該節點應該有所行動來保證主節點上擁有正確的mapping信息,而重發新的mapping信息是一個不錯的選擇。

但是,當有很多的mapping更新發生,並且主節點無法持續堅持時,會有一個亂序聚集(stampeding horde)效應,數據節點發給主節點的刷新消息就可能氾濫。

參數indices.cluster.send_refresh_mapping可以禁用掉默認行爲,因此消除這些從數據節點發送到主節點的refresh_mapping請求,可以讓主節點保持最新。即時沒有刷新請求,主節點也最終會看到最初的mapping變更,並會發佈一個包含該變更的集羣狀態更新。

Linux上安裝部署ElasticSearch全程記錄 http://www.linuxidc.com/Linux/2015-09/123241.htm

Elasticsearch安裝使用教程 http://www.linuxidc.com/Linux/2015-02/113615.htm

ElasticSearch 配置文件譯文解析 http://www.linuxidc.com/Linux/2015-02/114244.htm

ElasticSearch集羣搭建實例 http://www.linuxidc.com/Linux/2015-02/114243.htm

分佈式搜索ElasticSearch單機與服務器環境搭建 http://www.linuxidc.com/Linux/2012-05/60787.htm

ElasticSearch的工作機制 http://www.linuxidc.com/Linux/2014-11/109922.htm

Elasticsearch的安裝,運行和基本配置 http://www.linuxidc.com/Linux/2016-07/133057.htm

使用Elasticsearch + Logstash + Kibana搭建日誌集中分析平臺實踐 http://www.linuxidc.com/Linux/2015-12/126587.htm

Ubuntu 14.04搭建ELK日誌分析系統(Elasticsearch+Logstash+Kibana) http://www.linuxidc.com/Linux/2016-06/132618.htm

Elasticsearch1.7升級到2.3實踐總結 http://www.linuxidc.com/Linux/2016-11/137282.htm

ElasticSearch 的詳細介紹:請點這裏
ElasticSearch 的下載地址:請點這裏

總結:ElasticSearch的可配置屬性是其彈性的關鍵

對Loggly來講ElasticSearch可深度配置的屬性是一個巨大的優勢,因爲在我們的使用案例中已經最大限度發揮了ElasticSearch的參數威力(有時更甚)。如果在你自己應用進化的當前階段ES默認配置工作得足夠好了,請放心,隨着應用的發展你還會有很大的優化空間。

譯者介紹:楊振濤(Gentle Yang),搜索引擎架構師。現就職於vivo移動互聯網,負責搜素引擎相關產品和系統的架構設計與開發實施,在廠商移動互聯網領域有4年多的經驗。熱愛開源,樂於分享,目前專注於互聯網系統架構特別是實時分佈式系統的設計與工程實現,關注大數據的存儲、檢索及可視化。之前曾參與創業,先後負責開發母嬰B2C、移動IM、智能手錶等產品;在此之前就職於華大基因,從事基因組學領域的科研工作,專注於基因組數據的存儲、檢索和可視化。審閱了《Circos Data Visualization How-to》一書,參與社區協作翻譯了《ElasticSearch權威指南》一書,待出版。

本文永久更新鏈接地址:http://www.linuxidc.com/Linux/2017-01/139165.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章