[译]9条关于高性能ElasticSearch的配置建议
原文鏈接:https://www.loggly.com/blog/nine-tips-configuring-elasticsearch-for-high-performance/
Loggy使用ES作為其很多核心功能的搜索引擎. 如Jon Gifford在最近的文章ElasticSearch vs Solr中所述, 日志管理系統對搜索引擎有特別需求, 具體如下:
對于大規模的數據索引具有可靠的性能及準實時的表現--在我們場景中,每秒有接近100000條日志記錄
同時對于大量的搜索處理能維護較高的性能和效率.
在構建我們的Gen2日志管理服務時, 我們希望能設置最優的參數以最大程序的發揮ElasticSearch的索引和搜索性能. 不幸的時, 很難在一個地方收集到完善的ElasticSearch設置文檔. 這篇文章總結了我們學習到的一些知識, 同時可以作為你部署和配置自己的ES應用的一個參考列表.
本文檔最新更新于09/2016
1: 提前規劃indices, shards和cluster state的增長趨勢
在ES中創建indices和shards非常簡單, 但需要記住的是每個indiex和shard都有相應的資源開銷.如果有太多的indices和shards, 單單是對他們管理上的開銷就可能大大降低你的ES集群性能, 甚至極端場景下使服務不可用.
我們發現對管理系統開銷影響最大的因素是cluster state, 包含了集群中每個索引的mappings信息.曾經某段時間, 我們單個集群的cluster state信息占用了900MB的空間. 集群雖然還存活著, 但已處于不可用狀態.
下面我們通過一些數據來感受下其中都發生了事情...
假設你有一個索引, 其mappings大小為50K(在我們的集群中, 大約有700個字段). 如果你每小時生成一個索引, 那么一天下來將會有24 x 50K的cluster state數據增量, 大約是1.2MB. 如果你的系統中保存了1年的數據, cluster state信息將達到438MB(8760個indices, 53800個shards). 如果每天一個索引的話, cluster state信息會減少到18.25MB(365個indices, 1825個shards). 可以看到,每小時一個索引會把你置于一個完全不同的處境.
如果你的系統有實時索引數據的需求, 最好先為之做些規劃, 并清楚的意識到你的系統中會存儲多少cluster state信息以及將包含多少indices和shards. 在部署到生產環境之前, 應該先多做些測試和演練, 避免在凌晨3點因集群不可用而被叫起.
在集群配置方面, 為避免把自己置于險境, 你需要對系統中能容納的indices和shards數量有全面的掌控.
2: 配置之前,先認識集群拓撲結構
在Loggly, 我們把ES的master節點和data節點分開部署.現在我們要說的不是這些細節, 而是強調在你做出正常的配置之前, 先選擇正常的拓撲.
另外, 我們對于索引請求和查詢請求也使用了不同的客戶端程序. 這樣不但可以為data節點減輕負載, 更重要的是我們的執行隊列可以先提交給本地客戶端, 再由其與集群的其他節點交互.
設置節點為master或data節點由以下兩個參數的值來決定:
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的默認配置已經足夠, 但如果你的使用場景正如我們經常看到的日志類系統, 請一定不要錯過下面的部分.
3: 設置mlockall是提升性能的最有效手段
Linux把它的物理內存劃分為很多塊, 稱為頁. 而Swapping則是把內存中的一頁復制到磁盤上預定義空間的過程, 以釋放更多的內存頁, 而磁盤上的這部分空間稱為交換區. 物理內存和交換區空間的總和稱為虛擬內存空間.
交換區并不總是有利的. 因為下內存相比, 磁盤總是慢太多. 通常內存的存儲速度在納秒級, 而磁盤卻要毫秒級別. 所以磁盤的訪問速度比直接訪問內存要慢上萬倍. 使用的交換空間越多, 系統會越多, 所以要避免交換區的使用.
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同時要注意, 如果設置了mlockall為true, 要確認通過-DXmx或ES_HEAP_SIZE給你的ES設置了足夠的堆空間.
4: 通過discovery.zen控制ES的節點發現管理
Zen discovery是ES集群中節點發現連接的默認機制, 另外還有一些其他的發現機制, 如Azure, EC2和GCE. Zen discovery通過discovery.zen.*的一系列參數進行設置和控制.
在0.x和1.x版本中, 可以設置單播或多播方式, 并且多播是作為ES的默認方式使用的. 如果在這兩個版本中想使用單播, 需要設置discovery.zen.ping.multicast.enable為false.
但自從ES 2.0以來, 單播是Zen discovery唯一可用的選擇.
首先, 你需要通過discovery.zen.ping.unicast.hosts參數指定一組用于發現和連接節點的hosts. 為了簡單, 可以為集群中的每個節點設置相同的值. 我們的集群中使用了所有master節點的地址.
discovery.zen.minimum_master_nodes參數用于控制最小的合理master節點數, 使得集群中其他節點可被發現和操作. 通常, 在多于2個節點的集群中建議該參數設置的值不小于2. 另外一種計算方式是(master節點數/2 + 1).
Data節點和master節點之前有兩種檢測方式:
master向所有其他節點發起ping請求, 以確認該節點是否存活
其他的節點向master節點發現ping請求,以確認master是否存活,并決定是否需要開始新一輪的選舉
節點檢測過程由discovery.zen.fd.ping_timeout參數設置, 默認值為30s, 決定了一個發起ping請求的節點的響應等待時間. 如果你的集群帶寬不足或網絡擁堵, 則需要合理的重新調整該參數. 如果網絡較差,該參數要相應的設置大一些, 值越大, 節點發現的失敗的風險也就越低.
Loggly的discovery.zen參數設置如下:
discovery.zen.df.ping_timeout: 30s discovery.zen.mininum_master_nodes: 2 discovery.zen.ping.unicast.hosts: ["esmaster01", "esmaster02", "esmaster03"]就是說30s內需要有節點檢測響應返回(通過discovery.zen.df.ping_timeout設置的).另外,其他節點至少要檢測到2個master節點(我們總共有3個master節點), 第三個參數是說我們的單播主機分別為esmaster01, esmaster02和esmaster03.
5: 提防"DELETE_all"
ES的DELETE API允許你通過一個請求(使用通配符或_all)刪除所有的索引數據, 意識到這一點非常重要.如下:
curl -XDELETE 'http://localhost:9200/*/' curl -XDELETE 'http://localhost:9200/_all'雖然這個功能很強大,卻也極為危險,特別是在生產環境. 在我們所有的集群中, 我們都通過action.destructive_requires_name:true參數禁用了該刪除功能.
這個參數由ES 1.0并入, 并替換掉了0.90版本中使用的action.disable_delete_all_indices參數.
6: 使用Doc Values
在ES2.0及以上版本中, Doc Values是默認使用的.而在較早的版本中則需要顯示指定.Doc Values通過少量額外的索引和磁盤開銷, 提供了比在normal字段上更高效的排序和聚合操作.本質上, Doc Values通過把ES轉變為列式存儲, 進而使得ES大量的分詞特性比預想的更高效.
為了深入理解Doc Values帶來的好處, 下面將把Doc Values與normal字段進行對比.
當在normal字段上進行排序或聚合操作時, 將導致大量的fielddata cache.因為當字段第一次被緩存時, ES需要為該字段每個可能的取值分配大量的堆空間, 并從每個文檔中獲取字段值數據. 因為這個過程可能需要從磁盤中讀取數據, 因為將會十分耗時.一旦數據緩存完成, 以后再對該字段值的使用都會使用先前緩存的數據, 所以速度也會更快.但當有過多的字段被載入到緩存中時, 就會觸發緩存淘汰機制, 一些字段將被汰出, 相應的再次使用被汰出的字段時, 就是又一次的耗時載入過程. 為了高效, 你可能想減少或降低緩存汰出, 這意味著你要減少或限制將被緩存的字段數量.
與之不同, Doc Values使用基于磁盤的數據結構, 并映射到進程的內存空間, 從而減少對堆空間的占用, 并具有與fielddata cache相匹敵的性能. 雖然在數據第一次從硬盤讀取并載入時依然會有起始開銷, 然而這一些都有操作系統的文件系統緩存進行處理, 所以只有你真正需要的數據才會被讀入.
簡而言之, Doc Values減少了堆空間使用(相應的降低了GC影響), 并通過文件系統緩存減少讀取的數據, 從而提高了整體性能.
7: ES shard分配相關的參數設置
shard分配就是把shard分散到不同節點的過程,可以發生在初始化備份階段, 副本分配階段或者節點再平衡過程中.也就是說它發生在任何節點增加或移除的過程中.
參數cluster.routing.allocation.cluster_concurrent_rebalance決定了在shard再平衡過程中允許并發的shard數.合適的設置由你使用的硬件性能決定, 如集群節點使用的CPU核數, IO性能等.如果參數設置的不合理,將會對ES索引過程的性能帶來一定的影響.
cluster.routing.allocation.cluster_concurrent_rebalance:2ES默認設置的值為2, 也就是說在任何時候最多只允許同時移動2個shards的數據.設置一個不太高的合理數值總是值得的,雖然shard再平衡的并發數受到制約, 但卻不會對索引數據造成影響.
另外一個值得一提的參數是cluster.routing.allocation.disk.threshold_enabled.如果這個參數設置為true, 則在shard分配過程中為shard預留空閑的磁盤空間, 相反如果設置為false,則分配到該節點上的shard數據的未來增加將受到限制--沒有足夠的空間.
當threshold_enabled設置為true, 有兩個相應的指標可以配置:low 和 high.
low 定義了當磁盤使用量超過該指標后,ES將不再為該節點分配shard, 默認值為85%
high 定義了當磁盤使用量超過該指標后,將有shard從該節點中移出, 默認值為90%
這兩個參數即可按已使用量的百分比定義(例如,80%是說使用了80%的磁盤,尚有20%空閑), 也可以按最小可用磁盤空間定義(例如,20GB是說該節點尚有20GB空閑空間).
如果你有大量的小shards, ES使用的默認值可能會有些保守. 例如你有1TB的存儲空間,而每個shard的大小僅為10GB, 理論上該節點能容納100個數據shards.如果采用上面的默認設置, 在ES認為節點飽和前, 你最多只能存儲80個shards.
所以為了找出一個合理設置, 你需要仔細觀察在shard生命周期中的容量變化, 同時為之預留一定的安全空間.在上面的例子中, 假如有5個數據shards, 則需要確認在任何時候都要有50GB的可用空間(不是空閑空間, 是5個shards將占用的總空間).對于1TB的設備, 如果不考慮安全空間, low的值可設置為95%. 然而乘以50%的安全系數, 則需要至少預留75GB的空閑空間, 相應的合理的low值應為92.5%.
8: 合理的恢復設置幫你提升節點重啟速度
ES提供了幾個屬性用于提高集群恢復速度,縮短節點重啟時間.合理的取值依賴于你的硬件能力(硬盤和網絡速度通常會是瓶頸), 所以能給出的最好的建議就是嘗試,嘗試,再嘗試.
-
控制單個節點并發恢復數據的shard數:
cluster.routing.allocation.node_concurrent_recoveriesshard數據恢復是一個IO密集型操作, 因此需要根據實際情形設置參數.在ES 5.x版本中, 這個參數分拆成兩個新的設置:
-
控制單個節點上初始的主shard并發數:
cluster.routing.allocation.node_initial_primaries_recoveries -
控制一個shard恢復數據時并行打開的數據流個數:
indices.recovery.concurrent_streams -
與數據流緊密相關的是可用的帶寬限制:
indices.recovery.max_bytes_per_sec實際使用的硬件配置直接決定了以上幾個參數的最優值設置.使用SSD硬盤以及高速的(10G)以太網結構和使用機械硬盤以及1G的以太網結構將有巨大的差別.
只有在集群重啟的時候,才會使用以上數據恢復相關的參數設置.
9: 合理的線程池設置避免數據丟失
為了提高節點內的線程管理, ES維護了多個線程池.
在Loggly, 我們在使用_bulk操作來處理索引請求時發現, 設置合適的threadpool.bulk.queue_size對避免_bulk重試以及由其可能引起的數據丟失至關重要.
threadpool.bulk.queue_size: 5000上面的參數用于設置bulk的隊列長度, 即當節點的每個shard在處理bulk請求時, 如果無可用線程時, 能為每個shard排隊等待的請求數量.這個參數應該與你的bulk請求負載相匹配, 如果設置過小, 而bulk請求較多時, ES會返回一個RemoteTransportException.
如上所述, bulk請求涉及到的每個shard的數據都在這個隊列里, 因此合理的設置是bulk的并發數乘以這些請求相關的shard數. 比如說: 單個bulk請求包含的數據分布在10個shards上, 即便只有一次bulk請求, 你也要有一個至少長度為10的隊列設置.話說回來, 如果設置過大則會消耗更多的JVM堆空間(同時意味你正提交的數據量可能超出你實際能索引的能力), 然而卻能減化你的客戶端處理邏輯.
要么設置一個相對合適的較大的隊列值, 要么在你的代碼中合理的處理掉RemoteTransportException. 如果處理不當, 則會面臨數據丟失的風險. 下面的異常模仿的是隊列長度為10,而并發發起了超過10個bulk請求的場景:
RemoteTransportException[[<Bantam>][inet[/192.168.76.1:9300]][bulk/shard]]; nested: EsRejectedExecutionException[rejected execution (queue capacity 10) on org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction$1@13fe9be];總結
以上是生活随笔為你收集整理的[译]9条关于高性能ElasticSearch的配置建议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法小白——基本排序算法入门
- 下一篇: 玩一玩微信公众号开发(一) 接入系统