Elasticsearch 集羣優化篇java
這篇文章的做者很認真,分析的很好。node
轉載請註明出處@http://blog.csdn.net/gamer_gytgit
http://blog.csdn.net/gamer_gyt/article/details/62217053 github
轉載請註明出處:http://blog.csdn.net/gamer_gyt
博主微博:http://weibo.com/234654758
Github:https://github.com/thinkgamer算法
ES5.2.1 集羣部署參考:http://blog.csdn.net/gamer_gyt/article/details/59077189api
對於集羣的監控和優化是很重要的一部分,若是想持久維護集羣,單單靠增長物理內存,cpu,硬盤是不夠的,必須經過一些方法來進行優化。緩存
在以前得文章中咱們介紹到es集羣中得三個角色 master ,data,client安全
master結點:node.master: true node.data: false服務器
該node服務器只做爲一個主節點,但不存儲任何索引數據,該node服務器將使用自身空閒得資源,來協調各類建立索引請求或者查詢請求,將這些請求合理分發到相關得node服務器上。數據結構
data結點:node.master: false node.data: true
該node服務器只做爲一個數據節點,只用於存儲索引數據。使該node服務器功能 單一,只用於數據存儲和數據查詢,下降其資源消耗率。
client結點(負載均衡結點):node.master: false node.data: false
該node服務器即不會被選做主節點,也不會存儲任何索引數據。該服務器主要用 於查詢負載均衡。在查詢的時候,一般會涉及到從多個node服務器上查詢數據,並請 求分發到多個指定的node服務器,並對各個node服務器返回的結果進行一個彙總處理, 最終返回給客戶端。
針對ElasticSearch集羣中的全部數據節點,不用開啓http服務。將其中的配置 參數這樣設置:http.enabled: false,同時也不要安裝head, bigdesk, marvel等監控 插件,這樣保證data節點服務器只需處理建立/更新/刪除/查詢索引數據等操做。
http功能能夠在非數據節點服務器上開啓,上述相關的監控插件也安裝到這些服 務器上,用於監控ElasticSearch集羣狀態等數據信息。這樣作一來出於數據安全考慮,二來出於服務性能考慮。
一臺物理服務器上能夠啓動多個Node服務器節點(經過設置不一樣的啓動port),但一臺服務器上的CPU,內存,硬盤等資源畢竟有限,從服務器性能考慮,不建議一臺服務器上啓動多個node節點。
在大規模局點,好比100個點,能夠專門配備3個Master,可以使用3臺具備內存的刀片便可,即參數配置爲node.master: true,node.data: false;能夠按比例配備數據匯聚節點,好比10個,即參數配置爲node.master: false ,node.data: false;小規模節點,能夠不用如此設置,固然若是依然有性能問題,也是一個優化的措施
Elasticsearch 默認採用的是Lucene,至於爲何es採用這個,緣由多是由於Lucene是一個成熟的、高性能的、可擴展的、輕量級的,並且功能強大的搜索引擎包。Lucene的核心jar包只有一個文件,並且不依賴任何第三方jar包。更重要的是,它提供的索引數據和檢索數據的功能開箱即用。固然,Lucene也提供了多語言支持,具備拼寫檢查、高亮等功能。固然es使用Lucene做爲分詞搜索包,勢必會形成很大程度上的內存消耗。
一個常見的問題是配置堆太大。你有一個64 GB的機器,以爲JVM內存越大越好,想給Elasticsearch全部64 GB的內存。
固然,內存對於Elasticsearch來講絕對是重要的,用於更多的內存數據提供更快的操做。並且還有一個內存消耗大戶-Lucene
Lucene的設計目的是把底層OS裏的數據緩存到內存中。Lucene的段是分別存儲到單個文件中的,這些文件都是不會變化的,因此很利於緩存,同時操做系統也會把這些段文件緩存起來,以便更快的訪問。
Lucene的性能取決於和OS的交互,若是你把全部的內存都分配給Elasticsearch,不留一點給Lucene,那你的全文檢索性能會不好的。
最後標準的建議是把50%的內存給elasticsearch,剩下的50%也不會沒有用處的,Lucene會很快吞噬剩下的這部份內存。
在Java中,全部的對象都分配在堆上,而後有一個指針引用它。指向這些對象的指針大小一般是CPU的字長的大小,不是32bit就是64bit,這取決於你的處理器,指針指向了你的值的精確位置。
對於32位系統,你的內存最大可以使用4G。對於64系統可使用更大的內存。可是64位的指針意味着更大的浪費,由於你的指針自己大了。浪費內存不算,更糟糕的是,更大的指針在主內存和緩存器(例如LLC, L1等)之間移動數據的時候,會佔用更多的帶寬。
java 使用一個叫內存指針壓縮的技術來解決這個問題。它的指針再也不表示對象在內存中的精確位置,而是表示偏移量。這意味着32位的指針能夠引用40億個對象,而不是40億個字節。最終,也就是說堆內存長到32G的物理內存,也能夠用32bit的指針表示。
一旦你越過那個神奇的30-32G的邊界,指針就會切回普通對象的指針,每一個對象的指針都變長了,就會使用更多的CPU內存帶寬,也就是說你實際上失去了更多的內存。事實上當內存到達40-50GB的時候,有效內存才至關於使用內存對象指針壓縮技術時候的32G內存。
這段描述的意思就是說:即使你有足夠的內存,也儘可能不要超過32G,由於它浪費了內存,下降了CPU的性能,還要讓GC應對大內存。
你能夠考慮一臺機器上建立兩個或者更多ES節點,而不要部署一個使用32+GB內存的節點。仍然要 堅持50%原則,假設 你有個機器有128G內存,你能夠建立兩個node,使用32G內存。也就是說64G內存給ES的堆內存,剩下的64G給Lucene。
若是你選擇第二種,你須要配置
cluster.routing.allocation.same_shard.host:true
這會防止同一個shard的主副本存在同一個物理機上(由於若是存在一個機器上,副本的高可用性就沒有了)
所謂的heap即數據緩存的內存大小,ES集羣中消耗內存的有如下幾個:
Lucene 把每次生成的倒排索引,叫作一個段(segment)。而後另外使用一個 commit 文件,記錄索引內全部的 segment。而生成 segment 的數據來源,則是內存中的 buffer。因爲詞典的size會很大,所有裝載到heap裏不現實,所以Lucene爲詞典作了一層前綴索引(Term Index),這個索引在Lucene4.0之後採用的數據結構是FST (Finite State Transducer)。這種數據結構佔用空間很小,Lucene打開索引的時候將其全量裝載到內存中,加快磁盤上詞典查詢速度的同時減小隨機磁盤訪問次數。因此ES的data node存儲數據並不是只是耗費磁盤空間的,爲了加速數據的訪問,每一個segment都有會一些索引數據駐留在heap裏。所以segment越多,瓜分掉的heap也越多,而且這部分heap是沒法被GC掉的! 理解這點對於監控和管理集羣容量很重要,當一個node的segment memory佔用過多的時候,就須要考慮刪除、歸檔數據,或者擴容了。
Filter cache是用來緩存使用過的filter的結果集的,須要注意的是這個緩存也是常駐heap,沒法GC的。默認的10% heap size設置工做得夠好了,若是實際使用中heap沒什麼壓力的狀況下,才考慮加大這個設置。
對搜索結果作排序或者聚合操做,須要將倒排索引裏的數據進行解析,而後進行一次倒排。在有大量排序、數據聚合的應用場景,能夠說field data cache是性能和穩定性的殺手。這個過程很是耗費時間,所以ES2.0之前的版本主要依賴這個cache緩存已經計算過的數據,提高性能。可是因爲heap空間有限,當遇到用戶對海量數據作計算的時候,就很容易致使heap吃緊,集羣頻繁GC,根本沒法完成計算過程。ES2.0之後,正式默認啓用Doc Values特性(1.x須要手動更改mapping開啓),將field data在indexing time構建在磁盤上,通過一系列優化,能夠達到比以前採用field data cache機制更好的性能。所以須要限制對field data cache的使用,最好是徹底不用,能夠極大釋放heap壓力。這裏須要注意的是,排序、聚合字段必須爲not analyzed。設想若是有一個字段是analyzed過的,排序的實際對象實際上是詞典,在數據量很大狀況下這種狀況很是致命。
Bulk Queue是作什麼用的?當全部的bulk thread都在忙,沒法響應新的bulk request的時候,將request在內存裏排列起來,而後慢慢清掉。通常來講,Bulk queue不會消耗不少的heap,可是見過一些用戶爲了提升bulk的速度,客戶端設置了很大的併發量,而且將bulk Queue設置到難以想象的大,好比好幾千。這在應對短暫的請求爆發的時候有用,可是若是集羣自己索引速度一直跟不上,設置的好幾千的queue都滿了會是什麼情況呢? 取決於一個bulk的數據量大小,乘上queue的大小,heap頗有可能就不夠用,內存溢出了。通常來講官方默認的thread pool設置已經能很好的工做了,建議不要隨意去「調優」相關的設置,不少時候都是拔苗助長的效果。
Indexing Buffer是用來緩存新數據,當其滿了或者refresh/flush interval到了,就會以segment file的形式寫入到磁盤。這個參數的默認值是10% heap size。根據經驗,這個默認值也可以很好的工做,應對很大的索引吞吐量。但有些用戶認爲這個buffer越大吞吐量越高,所以見過有用戶將其設置爲40%的。到了極端的狀況,寫入速度很高的時候,40%都被佔用,致使OOM。
ES被設計成每一個Node均可以響應用戶的api請求,所以每一個Node的內存裏都包含有一份集羣狀態的拷貝。這個Cluster state包含諸如集羣有多少個Node,多少個index,每一個index的mapping是什麼?有少shard,每一個shard的分配狀況等等(ES有各種stats api獲取這類數據)。在一個規模很大的集羣,這個狀態信息可能會很是大的,耗用的內存空間就不可忽視了。而且在ES2.0以前的版本,state的更新是由Master Node作完之後全量散播到其餘結點的。頻繁的狀態更新都有可能給heap帶來壓力。在超大規模集羣的狀況下,能夠考慮分集羣並經過tribe node鏈接作到對用戶api的透明,這樣能夠保證每一個集羣裏的state信息不會膨脹得過大。
ES是分佈式搜索引擎,搜索和聚合計算除了在各個data node並行計算之外,還須要將結果返回給彙總節點進行彙總和排序後再返回。不管是搜索,仍是聚合,若是返回結果的size設置過大,都會給heap形成很大的壓力,特別是數據匯聚節點。
通常分配主機1/4-1/2的內存
編輯:elasticsearch/bin/ elasticsearch
加上(10g換成你本身設置的內存數):
ES_MIN_MEM=10g
ES_MAX_MEM=10g
ES_HEAP_NEWSIZE=1g
硬盤對集羣很是重要,特別是建索引多的狀況。磁盤是一個服務器最慢的系統,對於寫比較重的集羣,磁盤很容易成爲集羣的瓶頸。若是能夠承擔的器SSD盤,最好使用SSD盤。若是使用SSD,最好調整I/O調度算法。RAID0是加快速度的不錯方法。
在2.0.0以前,elasticsearch會限制合併速度(merges),默認爲20MB/sec。可是這個速率常常是顯得過小,致使合併速度落後於索引速度,進而限制了索引速度。
如今Elasticsearch2.0.0以後,使用了自動調整合並IO速度方式:若是合併落於索引速度,合併IO速度會逐漸增大,而且隨着合併的持續進行會減少。在索引吞吐量小的時候,即便忽然來了一個大的合併任務,這種狀況也不會吞噬整個節點可用的IO,極小化的下降對正在進行的查詢和索引的影響。
可是對索引請求大的狀況下,容許的合併速度會自動調整到跟上索引的速度。有了2.0.0這個特性,意味着咱們不須要管任何的限制值了,只要用默認的就行了。
若是磁盤空間和IO性能是Elasticsearch的瓶頸的話,使用多個IO設備(經過設置多個path.data路徑)存儲shards,可以增長總的存儲空間和提高IO性能。
在Elasticsearch2.0以前的版本,也是配置多個path.data路徑,可是其至關於RAID 0,每一個shards的數據會分佈在全部的磁盤上。當一個節點上有一塊盤壞了的狀況下,該節點上全部的shards都會損壞了。須要恢復該節點上的全部shards。
在2.0.0版本,把這個實現改爲了:每一個shards全部的數據只會在一塊磁盤上面。這樣即便一個節點的一塊磁盤損壞了,也只是損失了該磁盤上的shards,其它磁盤上的shards安然無事。只須要恢復該塊盤上的shards便可。
升級到2.0.0版本時,舊版本一個shard分佈到全部磁盤上的數據,會拷貝到一塊盤上。
對應這個改變,在設計shards時,若是一個節點有10塊磁盤,共3個節點,則shards至少30個,才能分佈在30塊盤上(即最大限度使用磁盤空間)。
分片(Shard)
一個索引會分紅多個分片存儲,分片數量在索引創建後不可更改
分片數是與檢索速度很是相關的的指標,若是分片數過少或過多都會致使檢索比較慢。分片數過多會致使檢索時打開比較多的文件別外也會致使多臺服務器之間通信。而分片數過少會致使單個分片索引過大,因此檢索速度慢。基於索引分片數=數據總量/單分片數的計算公式,在肯定分片數以前須要進行單服務單索引單分片的測試,目前咱們測試的結果單個分片的內容爲10G。
副本(replicas)
每一個索引的數據備份數量。
ElasticSearch在建立索引數據時,最好指定相關的shards數量和replicas, 不然會使用服務器中的默認配置參數shards=5,replicas=1。
由於這兩個屬性的設置直接影響集羣中索引和搜索操做的執行。假設你有足夠的機器來持有碎片和副本,那麼能夠按以下規則設置這兩個值:
1) 擁有更多的碎片能夠提高索引執行能力,並容許經過機器分發一個大型的索引;
2) 擁有更多的副本可以提高搜索執行能力以及集羣能力。
對於一個索引來講,number_of_shards只能設置一次,而number_of_replicas可使用索引更新設置API在任什麼時候候被增長或者減小。
這兩個配置參數在配置文件的配置以下:
index.number_of_shards: 5
number_of_replicas: 1
Elastic官方文檔建議:一個Node中一個索引最好不要多於三個shards.配置total_shards_per_node參數,限制每一個index每一個節點最多分配多少個發片.
1:Java jdk版本儘可能高一點,不然容易出現bug 2:es集羣結點規劃好,master,client,data node 分開,關閉data node 的http功能 3:合理利用內存 4:根據機器數,磁盤數,索引大小等硬件環境,根據測試結果,設置最優的分片數和備份數,單個分片最好不超過10GB,按期刪除不用的索引,作好冷數據的遷移。 5:保守配置內存限制參數,儘可能使用doc value存儲以減小內存消耗,查詢時限制size、from參數。 6:結合實際場景,作好集羣監控