天天看點

[資料庫]漫談ElasticSearch關于ES性能調優幾件必須知道的事(轉)

[資料庫]漫談ElasticSearch關于ES性能調優幾件必須知道的事(轉)

  ElasticSearch是現在技術前沿的大資料引擎,常見的組合有ES+Logstash+Kibana作為一套成熟的日志系統,其中Logstash是ETL工具,Kibana是資料分析展示平台。ES讓人驚豔的是他強大的搜尋相關能力和災備政策,ES開放了一些接口供開發者研發自己的插件,ES結合中文分詞的插件會給ES的搜尋和分析起到很大的推動作用。ElasticSearch是使用開源全文檢索庫ApacheLucene進行索引和搜尋的,說架構必須和Lucene的一些東西打交道。

關于Lucene:

  ApacheLucene将寫入索引的所有資訊組織成一種反向索引(Inverted Index)的結構之中,該結構是種将詞項映射到文檔的資料結構。其工作方式與傳統的關系資料庫不同,大緻來說反向索引是面向詞項而不是面向文檔的。且Lucene索引之中還存儲了很多其他的資訊,如詞向量等等,每個Lucene都是由多個段構成的,每個段隻會被建立一次但會被查詢多次,段一旦建立就不會再被修改。多個段會在段合并的階段合并在一起,何時合并由Lucene的内在機制決定,段合并後數量會變少,但是相應的段本身會變大。段合并的過程是非常消耗I/O的,且與之同時會有些不再使用的資訊被清理掉。在Lucene中,将資料轉化為反向索引,将完整串轉化為可用于搜尋的詞項的過程叫做分析。文本分析由分析器(Analyzer)來執行,分析其由分詞器(Tokenizer),過濾器(Filter)和字元映射器(Character Mapper)組成,其各個功能顯而易見。除此之外,Lucene有自己的一套完整的查詢語言來幫助我們進行搜尋和讀寫。

   [注]ES中的索引指的是查詢/尋址時URI中的一個字段如:[host]:[port(9200)]/[index]/[type]/[ID]?[option],而Lucene中的索引更多地和ES中的分片的概念相對應。

回到ElasticSearch,ES的架構遵循的設計理念有以下幾個特征:

1. 合理的預設配置:隻需修改節點中的Yaml配置檔案,就可以迅捷配置。這和Spring4中對配置的簡化有相似的地方。

2. 分布式工作模式:ES強大的Zen發現機制不僅支援組廣播也支援點單點傳播,且有“知一點即知天下”之妙。

3. 對等架構:節點之間自動備份分片,且使分片本身和樣本之間盡量”遠離“,可以避免單點故障。且Master節點和Data節點幾乎完全等價。

4. 易于向叢集擴充新節點:大大簡化研發或運維将新節點加入叢集所需的工作。

5. 不對索引中的資料結構增加任何限制:ES支援在一個索引之中存在多種資料類型。

6. 準實時:搜尋和版本同步,由于ES是分布式應用,一個重大的挑戰就是一緻性問題,無論索引還是文檔資料,然而事實證明ES表現優秀。

(一)分片政策

  選擇合适的分片數和副本數。ES的分片分為兩種,主分片(Primary Shard)和副本(Replicas)。預設情況下,ES會為每個索引建立5個分片,即使是在單機環境下,這種備援被稱作過度配置設定(Over Allocation),目前看來這麼做完全沒有必要,僅在散布文檔到分片和處理查詢的過程中就增加了更多的複雜性,好在ES的優秀性能掩蓋了這一點。假設一個索引由一個分片構成,那麼當索引的大小超過單個節點的容量的時候,ES不能将索引分割成多份,是以必須在建立索引的時候就指定好需要的分片數量。此時我們所能做的就是建立一個新的索引,并在初始設定之中指定這個索引擁有更多的分片。反之如果過度配置設定,就增大了Lucene在合并分片查詢結果時的複雜度,進而增大了耗時,是以我們得到了以下結論:

  我們應該使用最少的分片!

  主分片,副本和節點最大數之間數量存在以下關系:

  節點數<=主分片數*(副本數+1)

    控制分片配置設定行為。以上是在建立每個索引的時候需要考慮的優化方法,然而在索引已建立好的前提下,是否就是沒有辦法從分片的角度提高了性能了呢?當然不是,首先能做的是調整分片配置設定器的類型,具體是在elasticsearch.yml中設定cluster.routing.allocation.type屬性,共有兩種分片器even_shard,balanced(預設)。even_shard是盡量保證每個節點都具有相同數量的分片,balanced是基于可控制的權重進行配置設定,相對于前一個配置設定器,它更暴漏了一些參數而引入調整配置設定過程的能力。

  每次ES的分片調整都是在ES上的資料分布發生了變化的時候進行的,最有代表性的就是有新的資料節點加入了叢集的時候。當然調整分片的時機并不是由某個門檻值觸發的,ES内置十一個裁決者來決定是否觸發分片調整,這裡暫不贅述。另外,這些配置設定部署政策都是可以在運作時更新的,更多配置分片的屬性也請大家自行Google。

(二)路由優化

  ES中所謂的路由和IP網絡不同,是一個類似于Tag的東西。在建立文檔的時候,可以通過字段為文檔增加一個路由屬性的Tag。ES内在機制決定了擁有相同路由屬性的文檔,一定會被配置設定到同一個分片上,無論是主分片還是副本。那麼,在查詢的過程中,一旦指定了感興趣的路由屬性,ES就可以直接到相應的分片所在的機器上進行搜尋,而避免了複雜的分布式協同的一些工作,進而提升了ES的性能。于此同時,假設機器1上存有路由屬性A的文檔,機器2上存有路由屬性為B的文檔,那麼我在查詢的時候一旦指定目标路由屬性為A,即使機器2故障癱瘓,對機器1構不成很大影響,是以這麼做對災況下的查詢也提出了解決方案。所謂的路由,本質上是一個分桶(Bucketing)操作。當然,查詢中也可以指定多個路由屬性,機制大同小異。

(三)ES上的GC調優

  ElasticSearch本質上是個Java程式,是以配置JVM垃圾回收器本身也是一個很有意義的工作。我們使用JVM的Xms和Xmx參數來提供指定記憶體大小,本質上提供的是JVM的堆空間大小,當JVM的堆空間不足的時候就會觸發緻命的OutOfMemoryException。這意味着要麼記憶體不足,要麼出現了記憶體洩露。處理GC問題,首先要确定問題的源頭,一般有兩種方案:

  1. 開啟ElasticSearch上的GC日志

  2. 使用jstat指令

  3. 生成記憶體Dump

  第一條:在ES的配置檔案elasticsearch.yml中有相關的屬性可以配置,關于每個屬性的用途這裡當然說不完。

  第二條:jstat指令可以幫助我們檢視JVM堆中各個區的使用情況和GC的耗時情況。

  第三條:最後的辦法就是将JVM的堆空間轉儲到檔案中去,實質上是對JVM堆空間的一個快照。

  想了解更多關于JVM本身GC調優方法請參考:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

  另外,通過修改ES節點的啟動參數,也可以調整GC的方式,但是實質上和上述方法是等同的。

(四)避免記憶體交換

  這一點很簡單,由于作業系統的虛拟記憶體頁交換機制,會給性能帶來障礙,如資料寫滿記憶體會寫入Linux中的Swap分區。

  可以通過在elasticsearch.yml檔案中的bootstrap.mlockall設定為true來實作,但是需要管理者權限,需要修改作業系統的相關配置檔案。

(五)控制索引合并

  上文提到過,ES中的分片和副本本質上都是Lucene索引,而Lucene索引又基于多個索引段建構(至少一個),索引檔案中的絕大多數都是隻被寫一次,讀多次,在Lucene内在機制控制下,當滿足某種條件的時候多個索引段會被合并到一個更大的索引段,而那些舊的索引段會被抛棄并移除磁盤,這個操作叫做段合并。 

  Lucene要執行段合并的理由很簡單充分:索引段粒度越小,查詢性能越低且耗費的記憶體越多。頻繁的文檔更改操作會導緻大量的小索引段,進而導緻檔案句柄打開過多的問題,如修改系統配置,增大系統允許的最大檔案打開數。總的來講,當索引段由多一個合并為一個的時候,會減少索引段的數量進而提高ES性能。對于研發者來講,我們所能做的就是選擇合适的合并政策,盡管段合并完全是Lucene的任務,但随着Lucene開放更多配置借口,新版本的ES還是提供了三種合并的政策tiered,log_byte_size,log_doc。另外,ES也提供了兩種Lucene索引段合并的排程器:concurrent和serial。其中各者具體差別,這裡暫不贅述,隻是抛磚引玉。