1. 程式人生 > >elasticsearch優化總結

elasticsearch優化總結

 一、 硬體環境選擇: 

如果有條件,儘可能使用SSD硬碟, 不錯的CPU。ES的厲害之處在於ES本身的分散式架構以及lucene的特性。IO的提升,會極大改進ES的速度和效能。 

二、系統拓樸設計: 

ES叢集在架構拓樸時,一般都會採用Hot-Warm的架構模式,即設定3種不同型別的節點:Master節點、Hot 節點和 Warm節點。 

Master節點設定:一般會設定3個專用的maste節點,以提供最好的彈性擴充套件能力。當然,必須注意discovery.zen.minimum_master_nodes 屬性的設定,以防split-brain問題,使用公式設定:N/2+1(N為候選master節點數)。 該節點保持: node.data: false ; 因為master節點不參與查詢、索引操作,僅負責對於叢集管理,所以在CPU、記憶體、磁碟配置上,都可以比資料節點低很多。 

Hot節點設定: 索引節點(寫節點),同時保持近期頻繁使用的索引。 屬於IO和CPU密集型操作,建議使用SSD的磁碟型別,保持良好的寫效能;節點的數量設定一般是大於等於3個。將節點設定為hot型別: 

node.attr.box_type: hot

針對index, 通過設定index.routing.allocation.require.box_type: hot 可以設定將索引寫入hot節點。 

Warm節點設定: 用於不經常訪問的read-only索引。由於不經常訪問,一般使用普通的磁碟即可。記憶體、CPU的配置跟Hot節點保持一致即可;節點數量一般也是大於等於3個。 

當索引不再被頻繁查詢時,可通過index.routing.allocation.require.box_type: warm, 將索引標記為warm, 從而保證索引不寫入hot節點,以便將SSD磁碟資源用在刀刃上。一旦設定這個屬性,ES會自動將索引合併到warm節點。同時,也可以在elasticsearch.yml中設定 index.codec: best_compression 保證warm 節點的壓縮配置 

Coordinating節點:協調節點用於做分散式裡的協調,將各分片或節點返回的資料整合後返回。在ES叢集中,所有的節點都有可能是協調節點,但是,可以通過設定node.master、node.data 、 node.ingest 都為 false 來設定專門的協調節點。需要較好的CPU和較高的記憶體。 

三、ES的記憶體設定:
  由於ES構建基於lucene, 而lucene設計強大之處在於lucene能夠很好的利用作業系統記憶體來快取索引資料,以提供快速的查詢效能。lucene的索引檔案segements是儲存在單檔案中的,並且不可變,對於OS來說,能夠很友好地將索引檔案保持在cache中,以便快速訪問;因此,我們很有必要將一半的實體記憶體留給lucene ; 另一半的實體記憶體留給ES(JVM heap )。所以, 在ES記憶體設定方面,可以遵循以下原則:  1. 當機器記憶體小於64G時,遵循通用的原則,50%給ES,50%留給lucene。  2.  當機器記憶體大於64G時,遵循以下原則:  a. 如果主要的使用場景是全文檢索, 那麼建議給ES Heap分配 4~32G的記憶體即可;其它記憶體留給作業系統, 供lucene使用(segments cache), 以提供更快的查詢效能。  b.  如果主要的使用場景是聚合或排序, 並且大多數是numerics, dates, geo_points 以及not_analyzed的字元型別, 建議分配給ES Heap分配 4~32G的記憶體即可,其它記憶體留給作業系統,供lucene使用(doc values cache),提供快速的基於文件的聚類、排序效能。  c.  如果使用場景是聚合或排序,並且都是基於analyzed 字元資料,這時需要更多的 heap size, 建議機器上執行多ES例項,每個例項保持不超過50%的ES heap設定(但不超過32G,堆記憶體設定32G以下時,JVM使用物件指標壓縮技巧節省空間),50%以上留給lucene。  3. 禁止swap,一旦允許記憶體與磁碟的交換,會引起致命的效能問題。 通過: 在elasticsearch.yml 中 bootstrap.memory_lock: true, 以保持JVM鎖定記憶體,保證ES的效能。  4. GC設定原則:
  a. 保持GC的現有設定,預設設定為:Concurrent-Mark and Sweep (CMS),別換成G1GC,因為目前G1還有很多BUG。  b. 保持執行緒池的現有設定,目前ES的執行緒池較1.X有了較多優化設定,保持現狀即可;預設執行緒池大小等於CPU核心數。如果一定要改,按公式((CPU核心數* 3)/ 2)+ 1 設定;不能超過CPU核心數的2倍;但是不建議修改預設配置,否則會對CPU造成硬傷。  四、 叢集分片設定:  ES一旦建立好索引後,就無法調整分片的設定,而在ES中,一個分片實際上對應一個lucene 索引,而lucene索引的讀寫會佔用很多的系統資源,因此,分片數不能設定過大;所以,在建立索引時,合理配置分片數是非常重要的。一般來說,我們遵循一些原則:  1. 控制每個分片佔用的硬碟容量不超過ES的最大JVM的堆空間設定(一般設定不超過32G,參加上文的JVM設定原則),因此,如果索引的總容量在500G左右,那分片大小在16個左右即可;當然,最好同時考慮原則2。  2. 考慮一下node數量,一般一個節點有時候就是一臺物理機,如果分片數過多,大大超過了節點數,很可能會導致一個節點上存在多個分片,一旦該節點故障,即使保持了1個以上的副本,同樣有可能會導致資料丟失,叢集無法恢復。所以, 一般都設定分片數不超過節點數的3倍。  五、 Mapping建模:  1. 儘量避免使用nested或 parent/child,能不用就不用;nested query慢, parent/child query 更慢,比nested query慢上百倍;因此能在mapping設計階段搞定的(大寬表設計或採用比較smart的資料結構),就不要用父子關係的mapping。  2. 如果一定要使用nested fields,保證nested fields欄位不能過多,目前ES預設限制是50。參考:index.mapping.nested_fields.limit :50 因為針對1個document, 每一個nested field, 都會生成一個獨立的document, 這將使Doc數量劇增,影響查詢效率,尤其是JOIN的效率。  3. 避免使用動態值作欄位(key),  動態遞增的mapping,會導致叢集崩潰;同樣,也需要控制欄位的數量,業務中不使用的欄位,就不要索引。控制索引的欄位數量、mapping深度、索引欄位的型別,對於ES的效能優化是重中之重。以下是ES關於欄位數、mapping深度的一些預設設定:  index.mapping.nested_objects.limit :10000 index.mapping.total_fields.limit:1000 index.mapping.depth.limit: 20 六、 索引優化設定:  1.設定refresh_interval 為-1,同時設定number_of_replicas 為0,通過關閉refresh間隔週期,同時不設定副本來提高寫效能。  2. 修改index_buffer_size 的設定,可以設定成百分數,也可設定成具體的大小,大小可根據叢集的規模做不同的設定測試。 indices.memory.index_buffer_size:10%(預設) indices.memory.min_index_buffer_size: 48mb(預設) indices.memory.max_index_buffer_size 3. 修改translog相關的設定:  a. 控制資料從記憶體到硬碟的操作頻率,以減少硬碟IO。可將sync_interval的時間設定大一些。 index.translog.sync_interval:5s(預設)。 b. 控制tranlog資料塊的大小,達到threshold大小時,才會flush到lucene索引檔案。  index.translog.flush_threshold_size:512mb(預設) 4. _id欄位的使用,應儘可能避免自定義_id, 以避免針對ID的版本管理;建議使用ES的預設ID生成策略或使用數字型別ID做為主鍵。  5. _all欄位及_source欄位的使用,應該注意場景和需要,_all欄位包含了所有的索引欄位,方便做全文檢索,如果無此需求,可以禁用;_source儲存了原始的document內容,如果沒有獲取原始文件資料的需求,可通過設定includes、excludes 屬性來定義放入_source的欄位。  6. 合理的配置使用index屬性,analyzed 和not_analyzed,根據業務需求來控制欄位是否分詞或不分詞。只有 groupby需求的欄位,配置時就設定成not_analyzed, 以提高查詢或聚類的效率。  七、 查詢優化:  1. query_string 或 multi_match的查詢欄位越多, 查詢越慢。可以在mapping階段,利用copy_to屬性將多欄位的值索引到一個新欄位,multi_match時,用新的欄位查詢。  2. 日期欄位的查詢, 尤其是用now 的查詢實際上是不存在快取的,因此, 可以從業務的角度來考慮是否一定要用now, 畢竟利用query cache 是能夠大大提高查詢效率的。  3. 查詢結果集的大小不能隨意設定成大得離譜的值, 如query.setSize不能設定成 Integer.MAX_VALUE, 因為ES內部需要建立一個數據結構來放指定大小的結果集資料。  4. 儘量避免使用script,萬不得已需要使用的話,選擇painless & experssions 引擎。一旦使用script查詢,一定要注意控制返回,千萬不要有死迴圈(如下錯誤的例子),因為ES沒有指令碼執行的超時控制,只要當前的指令碼沒執行完,該查詢會一直阻塞。  如:
{

    “script_fields”:{

        “test1”:{

            “lang”:“groovy”,

            “script”:“while(true){print 'don’t use script'}”

        }

    }

}


5. 避免層級過深的聚合查詢, 層級過深的group by , 會導致記憶體、CPU消耗,建議在服務層通過程式來組裝業務,也可以通過pipeline的方式來優化。 

6. 複用預索引資料方式來提高AGG效能: 

如通過 terms aggregations 替代 range aggregations, 如要根據年齡來分組,分組目標是: 少年(14歲以下) 青年(14-28) 中年(29-50) 老年(51以上), 可以在索引的時候設定一個age_group欄位,預先將資料進行分類。從而不用按age來做range aggregations, 通過age_group欄位就可以了。 

7. Cache的設定及使用: 

a) QueryCache: ES查詢的時候,使用filter查詢會使用query cache, 如果業務場景中的過濾查詢比較多,建議將querycache設定大一些,以提高查詢速度。 

indices.queries.cache.size: 10%(預設),可設定成百分比,也可設定成具體值,如256mb。

當然也可以禁用查詢快取(預設是開啟), 通過index.queries.cache.enabled:false設定。 

b) FieldDataCache: 在聚類或排序時,field data cache會使用頻繁,因此,設定欄位資料快取的大小,在聚類或排序場景較多的情形下很有必要,可通過indices.fielddata.cache.size:30% 或具體值10GB來設定。但是如果場景或資料變更比較頻繁,設定cache並不是好的做法,因為快取載入的開銷也是特別大的。 

c) ShardRequestCache: 查詢請求發起後,每個分片會將結果返回給協調節點(Coordinating Node), 由協調節點將結果整合。 
如果有需求,可以設定開啟;  通過設定index.requests.cache.enable: true來開啟。

不過,shard request cache只快取hits.total, aggregations, suggestions型別的資料,並不會快取hits的內容。也可以通過設定indices.requests.cache.size: 1%(預設)來控制快取空間大小。

億級規模的ES查詢優化實戰

  • 能用filter就不用query 
    filter拿到相應的doc後不計算score不用排序 
    query會對符合條件的doc計算score並進行排序 
    filter的查詢速度比query快很多

  • 增加相關cache的配置 
    indices.cache.filter.size: 30% 
    indices.fielddata.cache.size: 60% 
    index.cache.field.type: soft 
    indices.breaker.fielddata.limit: 70%

  • 優化方案——總結 
    能用filter就不用query 
    增加冗餘欄位將部分range aggregation查詢變成terms aggregation 
    為常用欄位增加配置,將fielddata的loading設成eager,儘量多載入到記憶體 
    增加叢集的快取資源,把記憶體儘量多的用起來 
    Global ordinals 
    Index warmer 
    調整aggregation的collect_mode 
    上SSD

elasticsearch一些使用經驗以及優化方法

  • Elasticsearch索引速度優化 
    index.refresh_interval :-1 
    index.number_of_shards : X 
    index.number_of_replicas : 0 
    index.translog.sync_interval : 30s 
    index.translog.durability : “async” 
    index.translog.flush_threshold_size: 4g 
    index.translog.flush_threshold_ops: 50000

  • 其它 
    去掉_all欄位可節省一半空間 
    開啟索引壓縮可節省空間,但會有10%-20%的效能損耗 

    不需分詞的字串欄位設成not_analyzed

  • ElasticSearch架構概述

    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。其中各者具體區別,這裡暫不贅述,只是拋磚引玉。

  • ES 手冊

    如何提高ES的效能

    不要返回較大的結果集

    ES是設計成一個搜尋引擎的,只擅長返回匹配查詢較少文件,如果需要返回非常多的文件需要使用Scroll。

    避免稀疏

    因為ES是基於Lucene來索引和儲存資料的,所以對稠密的資料更有效。Lucene能夠有效的確定文件是通過一個整數的文件id,無論有沒有資料都會話費一個位元組儲存id。稀疏主要影響norms和doc_values,一些可以避免稀疏的推薦:

    避免將不相關的資料放到相同的索引中

    規範的文件結構

    使用相同的欄位名來儲存同樣的資料。

    避免型別

    不用norms和doc_values在稀疏欄位

    調整索引速度

    使用bulk請求

    並且每個請求不超過幾十M,因為太大會導致記憶體使用過大

    使用 multiple workers/threads傳送資料到ES

    多程序或者執行緒,如果看到TOO_MANY_REQUESTS (429)EsRejectedExecutionException則說明ES跟不上索引的速度,當叢集的I/O或者CPU飽和就得到了工作者的數量。

    增加重新整理間隔

    index.refresh_interval預設是1s,可以改成30s以減少合併壓力。

    在載入大量資料時候可以暫時不用refresh和repliccas

    index.refresh_interval to -1 and index.number_of_replicas to 0

    禁用swapping

    禁用swapping

    給檔案快取分配記憶體

    快取是用來快取I/O操作的,至少用一般的記憶體來執行ES檔案快取。

    使用更快的硬體

    • 使用SSD作為儲存裝置。
    • 使用本地儲存,避免使用NFS或者SMB
    • 注意使用虛擬儲存,比如亞馬遜的EBS

    索引緩衝大小

    indices.memory.index_buffer_size通常是JVM的0.1,確保他足夠處理至多512MB的索引。

    調整搜尋速度

    給檔案系統快取大記憶體

    至少給可用記憶體的一半到檔案系統快取。

    使用更快的硬體

    • 使用SSD作為儲存裝置。
    • 使用效能更好的CPU,高併發
    • 使用本地儲存,避免使用NFS或者SMB
    • 注意使用虛擬儲存,比如亞馬遜的EBS

    文件建模

    避免連結,巢狀會使查詢慢幾倍,而親自關係能使查詢慢幾百倍,所以如果同樣的問題可以通過沒有連結的非規範回答就可以提升速度。

    預索引資料

    不明覺厲

    對映

    數值型資料不一定要對映成整形或者長整型

    避免scripts

    如果實在要使用,就用painless和expressions

    強勢合併只讀索引

    https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-forcemerge.html
    不要強勢合併正在寫的索引

    準備全域性順序

    準備檔案系統快取

    index.store.preload,如果記憶體不是很大會使搜尋變得緩慢。

    調整磁碟使用

    禁用不需要的功能

    • 不需要過濾時可以禁用索引“index”:false
    • 如果你不需要text欄位的score,可以禁用”norms”:false
    • 如果不需要短語查詢可以不索引positions"indexe_options":"freqs"

    不用預設的動態字串匹配

    不要使用_all

    使用best_compression

    使用最小的足夠用的數值型別

    byte,short,integer,long
    half_float,float,double

    https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-create-index.html#mappings
    https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules.html#dynamic-index-settings
    https://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html

=======================================================================================

叢集結點角色分配

在之前得文章中我們介紹到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伺服器返回的結果進行一個彙總處理, 最終返回給客戶端。

1:關閉data結點得http功能

    針對ElasticSearch叢集中的所有資料節點,不用開啟http服務。將其中的配置 引數這樣設定:http.enabled: false,同時也不要安裝head, bigdesk, marvel等監控 外掛,這樣保證data節點伺服器只需處理建立/更新/刪除/查詢索引資料等操作。

    http功能可以在非資料節點伺服器上開啟,上述相關的監控外掛也安裝到這些服 務器上,用於監控ElasticSearch叢集狀態等資料資訊。這樣做一來出於資料安全考慮,二來出於服務效能考慮。

2:一臺伺服器上最好只部署一個node

    一臺物理伺服器上可以啟動多個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作為分詞搜尋包,勢必會造成很大程度上的記憶體消耗。

1:預留一半記憶體給Lucene使用

    一個常見的問題是配置堆太大。你有一個64 GB的機器,覺得JVM記憶體越大越好,想給Elasticsearch所有64 GB的記憶體。

    當然,記憶體對於Elasticsearch來說絕對是重要的,用於更多的記憶體資料提供更快的操作。而且還有一個記憶體消耗大戶-Lucene

    Lucene的設計目的是把底層OS裡的資料快取到記憶體中。Lucene的段是分別儲存到單個檔案中的,這些檔案都是不會變化的,所以很利於快取,同時作業系統也會把這些段檔案快取起來,以便更快的訪問。

    Lucene的效能取決於和OS的互動,如果你把所有的記憶體都分配給Elasticsearch,不留一點給Lucene,那你的全文檢索效能會很差的。

    最後標準的建議是把50%的記憶體給elasticsearch,剩下的50%也不會沒有用處的,Lucene會很快吞噬剩下的這部分記憶體。

2:32GB限制

    在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應對大記憶體。

3:機器記憶體大於64GB

    你可以考慮一臺機器上建立兩個或者更多ES節點,而不要部署一個使用32+GB記憶體的節點。仍然要 堅持50%原則,假設 你有個機器有128G記憶體,你可以建立兩個node,使用32G記憶體。也就是說64G記憶體給ES的堆記憶體,剩下的64G給Lucene。
    如果你選擇第二種,你需要配置

cluster.routing.allocation.same_shard.host:true

這會防止同一個shard的主副本存在同一個物理機上(因為如果存在一個機器上,副本的高可用性就沒有了)

4:ES叢集的heap引數優化

    所謂的heap即資料快取的記憶體大小,ES叢集中消耗記憶體的有以下幾個:

1):segment Memory

    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佔用過多的時候,就需要考慮刪除、歸檔資料,或者擴容了。

2):Filter Cache

    Filter cache是用來快取使用過的filter的結果集的,需要注意的是這個快取也是常駐heap,無法GC的。預設的10% heap size設定工作得夠好了,如果實際使用中heap沒什麼壓力的情況下,才考慮加大這個設定。

3):Field Data cache

    對搜尋結果做排序或者聚合操作,需要將倒排索引裡的資料進行解析,然後進行一次倒排。在有大量排序、資料聚合的應用場景,可以說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過的,排序的實際物件其實是詞典,在資料量很大情況下這種情況非常致命。

4):Bulk Queue

    Bulk Queue是做什麼用的?當所有的bulk thread都在忙,無法響應新的bulk request的時候,將request在記憶體裡排列起來,然後慢慢清掉。一般來說,Bulk queue不會消耗很多的heap,但是見過一些使用者為了提高bulk的速度,客戶端設定了很大的併發量,並且將bulk Queue設定到不可思議的大,比如好幾千。這在應對短暫的請求爆發的時候有用,但是如果叢集本身索引速度一直跟不上,設定的好幾千的queue都滿了會是什麼狀況呢? 取決於一個bulk的資料量大小,乘上queue的大小,heap很有可能就不夠用,記憶體溢位了。一般來說官方預設的thread pool設定已經能很好的工作了,建議不要隨意去“調優”相關的設定,很多時候都是適得其反的效果。

5):Indexing Buffer

    Indexing Buffer是用來快取新資料,當其滿了或者refresh/flush interval到了,就會以segment file的形式寫入到磁碟。這個引數的預設值是10% heap size。根據經驗,這個預設值也能夠很好的工作,應對很大的索引吞吐量。但有些使用者認為這個buffer越大吞吐量越高,因此見過有使用者將其設定為40%的。到了極端的情況,寫入速度很高的時候,40%都被佔用,導致OOM。

6):Cluster State Buffer

    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資訊不會膨脹得過大。

7):超大搜索聚合結果集的fetch

    ES是分散式搜尋引擎,搜尋和聚合計算除了在各個data node平行計算以外,還需要將結果返回給彙總節點進行彙總和排序後再返回。無論是搜尋,還是聚合,如果返回結果的size設定過大,都會給heap造成很大的壓力,特別是資料匯聚節點。

5:優化建議:

一般分配主機1/4-1/2的記憶體
編輯:elasticsearch/bin/ elasticsearch
加上(10g換成你自己設定的記憶體數):

ES_MIN_MEM=10g
ES_MAX_MEM=10g
ES_HEAP_NEWSIZE=1g


叢集的硬碟和CPU設定

1:硬碟選型:

    硬碟對叢集非常重要,特別是建索引多的情況。磁碟是一個伺服器最慢的系統,對於寫比較重的叢集,磁碟很容易成為叢集的瓶頸。如果可以承擔的器SSD盤,最好使用SSD盤。如果使用SSD,最好調整I/O排程演算法。RAID0是加快速度的不錯方法。

2:自動調整儲存頻寬

    在2.0.0之前,elasticsearch會限制合併速度(merges),預設為20MB/sec。但是這個速率經常是顯得太小,導致合併速度落後於索引速度,進而限制了索引速度。

    現在Elasticsearch2.0.0之後,使用了自動調整合並IO速度方式:如果合併落於索引速度,合併IO速度會逐漸增大,並且隨著合併的持續進行會減小。在索引吞吐量小的時候,即使突然來了一個大的合併任務,這種情況也不會吞噬整個節點可用的IO,極小化的降低對正在進行的查詢和索引的影響。
但是對索引請求大的情況下,允許的合併速度會自動調整到跟上索引的速度。有了2.0.0這個特性,意味著我們不需要管任何的限制值了,只要用預設的就好了。

3:多個path.data 路徑

    如果磁碟空間和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:結合實際場景,做好叢集監控

======================================================

一. 索引效能(Index Performance)

 


 

首先要考慮的是,索引效能是否有必要做優化?

索引速度提高與否?主要是看瓶頸在什麼地方,若是 Read DB(產生DOC)的速度比較慢,那瓶頸不在 ElasticSearch 時,優化就沒那麼大的動力。實際上 Elasticsearch 的索引速度還是非常快的。

我們有一次遇到 Elasticsearch 升級後索引速度很慢,查下來是新版 IK 分詞的問題,修改分詞外掛後得到解決。

如果需要優化,應該如何優化?

SSD 是經濟壓力能承受情況下的不二選擇。減少碎片也可以提高索引速度,每天進行優化還是很有必要的。在初次索引的時候,把 replica 設定為 0,也能提高索引速度。

bulk 是不是一定需要呢?

若是 Elasticsearch 普通索引已經導致高企的 LA,IO 壓力已經見頂,這時候 bulk 也無法提供幫助,SSD 應該是很好的選擇。

在 create doc 速度能跟上的時候,bulk 是可以提高速度的。

記得 threadpool.index.queue_size ++,不然會出現索引時佇列不夠用的情況。

indices.memory.index_buffer_size:10% 這個引數可以進行適當調整。

調整如下引數也可以提高索引速度:index.translog.flush_threshold_ops:50000 和 refresh_interval。

二. 查詢效能(Query Perofrmance)


王道是什麼?routing,routing,還是 routing。

我們為了提高查詢速度,減少慢查詢,結合自己的業務實踐,使用多個叢集,每個叢集使用不同的 routing。比如,使用者是一個routing維度。

在實踐中,這個routing 非常重要。

我們碰到一種情況,想把此維度的查詢(即使用者查詢)引到非使用者routing 的叢集,結果叢集完全頂不住!

在大型的本地分類網站中,城市、類目也是一個不錯的維度。我們使用這種維度進行各種搭配。然後在前端分析查詢,把各個不同查詢分別引入合適的叢集。這樣做以後,每個叢集只需要很少的機器,而且保持很小的 CPU Usage 和 LA。從而查詢速度夠快,慢查詢幾乎消滅。

分合?

分別(索引和routing)查詢和合並(索引和routing)查詢,即此分合的意思。

索引越來越大,單個 shard 也很巨大,查詢速度也越來越慢。這時候,是選擇分索引還是更多的shards?

在實踐過程中,更多的 shards 會帶來額外的索引壓力,即 IO 壓力。

我們選擇了分索引。比如按照每個大分類一個索引,或者主要的大城市一個索引。然後將他們進行合併查詢。如:http://cluster1:9200/shanghai,beijing/_search?routing=fang,自動將查詢中城市屬性且值為上海或北京的查詢,且是房類目的,引入叢集 cluster1,並且routing等於fang。

http://cluster1:9200/other/_search?routing=jinan,linyi。小城市的索引,我們使用城市做 routing,如本例中同時查詢濟南和臨沂城市。

http://cluster1:9200/_all/_search,全部城市查詢。

再如: http://cluster2:9200/fang,che/_search?routing=shanghai_qiche,shanghai_zufang,beijing_qiche,beijing_zufang。查詢上海和北京在小分類汽車、整租的資訊,那我們進行如上合併查詢。並將其引入叢集 cluster2。

使用更多的 shards?

除了有 IO 壓力,而且不能進行全部城市或全部類目查詢,因為完全頂不住。

Elastic 官方文件建議:一個 Node 最好不要多於三個 shards。

若是 "more shards”,除了增加更多的機器,是沒辦法做到這一點的。

分索引,雖然一個 Node 總的shards 還是挺多的,但是一個索引可以保持3個以內的shards。

我們使用分索引時,全量查詢是可以頂住的,雖然壓力有點兒高。

索引越來越大,資源使用也越來越多。若是要進行更細的叢集分配,大索引使用的資源成倍增加。

有什麼辦法能減小索引?顯然,建立 doc 時,把不需要的 field 去掉是一個辦法;但是,這需要對業務非常熟悉。

有啥立竿見影的辦法?

根據我們資訊的特點,內容(field:description)佔了索引的一大半,那我們就不把 description 索引進 ES,doc 小了一倍,叢集也小了一倍,所用的資源(Memory, HD or SSD, Host, snapshot儲存,還有時間)大大節省,查詢速度自然也更快。

那要查 description 怎麼辦?

上面的例項中,我們可以把查詢引入不同叢集,自然我們也可以把 description 查詢引入一個非實時(也可以實時)叢集,這主要是我們業務特點決定的,因為description查詢所佔比例非常小,使得我們可以這樣做。

被哪些查詢搞過?第一位是 Range 查詢,這貨的效能真不敢恭維。在最熱的查詢中,若是有這貨,肯定是非常痛苦的,網頁變慢,查詢速度變慢,叢集 LA 高企,嚴重的時候會導致叢集 shard 自動下線。所以,建議在最熱的查詢中避免使用 Range 查詢。

Facet 查詢,在後續版本這個被 aggregations 替代,我們大多數時候讓它在後端進行運算。

三. 其他

1)執行緒池

執行緒池我們預設使用 fixed,使用 cached 有可能控制不好。主要是比較大的分片 relocation時,會導致分片自動下線,叢集可能處於危險狀態。在叢集高壓時,若是 cached ,分片也可能自動下線。自 1.4 版本後,我們就一直 fixed,至於新版是否還存在這個問題,就沒再試驗了。

兩個原因:一是 routing王道帶來的改善,使得叢集一直低壓執行;二是使用fixed 後,已經極少遇到自動下線shard了。

我們前面說過,user 是一個非常好的維度。這個維度很重要,routing 效果非常明顯。其他維度,需要根據業務特點,進行組合。

所以我們的叢集一直是低壓執行,就很少再去關注新版本的 使用 cached 配置問題。

hreadpool.search.queue_size 這個配置是很重要的,一般預設是夠用了,可以嘗試提高。

2)優化

每天優化是有好處的,可以大大改善查詢效能。max_num_segments 建議配置為1。雖然優化時間會變長,但是在高峰期前能完成的話,會對查詢效能有很大好處。

3) JVM GC的選擇:選擇 G1還是 CMS?

應該大多數人還是選擇了 CMS,我們使用的經驗是 G1 和 CMS 比較接近;但和 CMS 相比,還是有一點距離,至少在我們使用經驗中是如此。

JVM 32G 現象?

128G記憶體的機器配置一個 JVM,然後是巨大的 heapsize (如64G)?

還是配多個 JVM instance,較小的 heapsize(如32G)?

我的建議是後者。實際使用中,後者也能幫助我們節省不少資源,並提供不錯的效能。具體請參閱 “Don’t Cross 32 GB!" (https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html#compressed_oops)

跨 32G 時,有一個現象,使用更多的記憶體,比如 40G,效果還不如31G!

這篇文件值得大家仔細閱讀。

JVM 還有一個配置 bootstrap.mlockall: true,比較重要。這是讓 JVM 啟動的時候就 鎖定 heap 記憶體。

有沒有用過 較小的 heapsize,加上SSD?我聽說有人使用過,效果還不錯,當然,我們自己還沒試過。

Q&A


Q1:您建議生產環境JVM採用什麼樣的引數設定?FULL GC頻率和時間如何?

CMS 標準配置。

ES_HEAP_NEWSIZE=?G

JAVA_OPTS="$JAVA_OPTS -XX:+UseCondCardMark"

JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=250"

JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC"

JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC"

JAVA_OPTS="$JAVA_OPTS -XX:CMSInitiatingOccupancyFraction=75"

JAVA_OPTS="$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly"

Full GC 很少去care 它了。我們使用 Elasticsearch 在JVM上花的時間很少。

Q2:生產環境伺服器如何配置價效比較高?單機CPU核數、主頻?記憶體容量?磁碟容量?

記憶體大一些,CPU 多核是必要的,JVM 和 Elasticsearch 會充分使用記憶體和多核的。 關於記憶體容量的問題,很多是 JVM Tunning 的問題。 磁碟容量沒啥要求。

Q3: 分組統計(Facet 查詢或 aggregations )大多數時候讓它在後端進行運算,怎麼實現?應用如果需要實時進行統計而且併發量較大,如何優化?

因為我們是網站系統,所以對於 Facet 請求,引導到後端慢慢計算,前端初始的時候可能沒資料,但是此後就會有了。

如果是精確要求的話,那就只能從 提高 facet 查詢效能去下手,比如 routing、filter、cache、更多的記憶體...

Q4:存進Elasticsearch的資料,timestamp是UTC時間,Elasticsearch叢集會在UTC 0點,也就是北京時間早上8點自動執行優化?如何改引數設定這個時間?

我們沒有使用Elasticsearch的自動優化設定。自己控制優化時間。

Q5:我的Java程式,log4j2 Flume appender,然後機器上的Flume agent ,直接Elasticsearch 的sink avro到 es節點上,多少個agent 連在單個Elasticsearch節點比較合適 ?

ElasticSearch本身是一個分散式計算叢集,所以,請求平均分配到每個 node 即可。

Q6:我程式碼裡直接用 Java API 生成Flume appender 格式,Flume agent 裡interceptor去拆分幾個欄位,這樣是不是太累了?比較推薦的做法是不是還是各業務點自己控制欄位,呼叫Elasticsearch API 生成索引內容?

業務點自己控制生成的文件吧?如果需要產生不同routing,並且分了索引,這些其實是業務相關的。routing和不同索引,都是根據業務情況哪些查詢比較集中而進行處理的。

Q7:您見過或管理過的生產環境的Elasticsearch資料量多大?

我們使用 Elasticsearch 進行某些業務處理,資料量過億。

Q8:SSD效能提升多少?

SSD 對索引幫助非常大,效果噹噹的,提高几十倍應該是沒問題。不過,我們沒有試過完全使用SSD頂查詢,而是使用記憶體,記憶體價效比還是不錯的。

Q9:我們現在有256個shard,用uid做routing,所有查詢都是走routing。每個shard有30多G,每次擴容很慢,有什麼建議?

可以考慮使用分合查詢嗎? 或者使用更多的維度? 256個 shard 確實比較難以控制。但是如果是分索引和查詢,比more shards(256) 效果應該會好不少。

Q10:Elasticsearch排序等聚合類的操作需要用到fielddata,查詢時很慢。新版本中doc values聚合查詢操作效能提升很大,你們有沒有用過?

Facet 查詢需要更大的記憶體,更多的 CPU 資源。可以考慮routing、filter、cache等多種方式提高效能。

Aggs 將來是要替換 Facet,建議儘快替換原來的facet API。

Q11:Elasticsearch配置bootstrap.mlockall,我們在使用中發現會導致啟動很慢,因為Elasticsearch要獲取到足夠的記憶體才開始啟動。

啟動慢是可以接受的,啟動慢的原因也許是記憶體沒有有效釋放過,比如檔案 cached了。 記憶體充足的情況下,啟動速度還是蠻快的,可以接受。 JVM 和 Lucene 都需要記憶體,一般是JVM 50%, 剩下的50% 檔案cached 為Lucene 使用。

Q12:優化是一個開銷比較大的操作,每天優化的時候是否會導致查詢不可用?如何優化這塊?

優化是開銷很大的。不會導致查詢不可用。優化是值得的,大量的碎片會導致查詢效能大大降低。 如果非常 care 查詢,可以考慮多個叢集。在優化時,查詢 skip 這個叢集就可以。

Q13:Elasticsearch適合做到10億級資料查詢,每天千萬級的資料實時寫入或更新嗎?

10億是可以做到的,如果文件輕量,10億所佔的資源還不是很多。

ELK 使用 Elasticsearch ,進行日誌處理每天千萬是小case吧?

不過我們除了使用 ELK 進行日誌處理,還進行業務處理,10億級快速查詢是可以做到,不過,需要做一些工作,比如索引和shards的分分合合

Q14:Elasticsearch相比Solr有什麼優勢嗎?

我們當年使用 Solr 的時候,Elasticsearch 剛出來。他們都是基於 Lucene的。 Elasticsearch 相對於 solr ,省事是一個優點。而且現在 Elasticsearch 相關的應用軟體也越來越多。Solr 和 Lucene 整合度很高,更新版本是和Lucene一起的,這是個優點。

Q15:分詞用的什麼元件?Elasticsearch自帶的嗎?

我們使用 IK 分詞,不過其他分詞也不錯。IK分詞更新還是很及時的。而且它可以遠端更新詞典。

Q16: reindex有沒有好的方法?

reindex 這個和 Lucene 有關,它的 update 就是 delete+ add。

Q17:以上面的兩個例子為例 : 是儲存多份同樣的資料麼?

是兩個叢集。第一個叢集使用大城市分索引,不過,還有大部分小城市合併一個索引。大城市還是用類目進行routing,小城市合併的索引就使用城市進行routing 。

第二個叢集,大類分得索引,比如fang、che,房屋和車輛和其他類目在一個叢集上,他們使用 city+二級類目做routing。

Q18:叢集部署有沒有使用 Docker ? 我們使用的時候 ,同一個伺服器 節點之間的互相發現沒有問題 ,但是跨機器的時候需要強制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解決叢集互相發現問題。

我們使用puppet進行部署。暫沒使用 Docker。 強制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解決叢集,跨IP段的時候是有這個需要。

Q19:您建議採用什麼樣的資料匯流排架構來保證業務資料按routing寫入多個Elasticsearch叢集,怎麼保證多叢集Elasticsearch中的資料與資料庫中資料的一致性?

我們以前使用 php在web程式碼中進行索引和分析 query,然後引導到不同叢集。 現在我們開發了一套go rest系統——4sea,使用 redis + elastic 以綜合提高效能。

索引時,更新db的同時,提交一個文件 ID 通知4sea 進行更新,然後根據配置更新到不同叢集。

資料提交到查詢時,就是分析 query 並引導到不同叢集。

這套 4sea 系統,有機會的可以考慮開源,不算很複雜的。

Q20: 能介紹一下Elasticsearch的叢集rebanlance、段合併相關的原理和經驗嗎?

“段”合併?,我們是根據業務特點,產生幾個不一樣的叢集,主要還是 routing 不一樣。

shards 比較平均很重要的,所以選擇routing 維度是難點,選擇城市的話,大城市所在分片會非常大,此時可以考慮 分索引,幾個大城市幾個索引,然後小城市合併一個索引。

如果 shards 大小分佈平均的話,就不關心如何 allocation 了。

Q21:關於叢集rebalance,其實就是cluster.routing.allocation配置下的那些rebalance相關的設定,比如allow_rebalance/cluster_concurrent_rebalance/node_initial_primaries_recoveries,推薦怎麼配置?

分片多的情況下,這個才是需要的吧。

分片比較少時,allow_rebalance disable,然後手動也可以接受的。

分片多,一般情況會自動平衡。我們對主從不太關心。只是如果一臺機器多個 JVM instance (多個 Elasticsearch node)的話,我們寫了個指令碼來避免同一shard 在一臺機器上。

cluster_concurrent_rebalance 在恢復的時候根據情況修改。正常情況下,再改成預設就好了。

node_initial_primaries_recoveries,在保證叢集低壓的情況下,不怎麼care。

kopf 上面有好多這種配置,你可以多試試。

Q22:合併查詢是非同步請求還是同步請求?做快取嗎?

合併查詢是 Elasticsearch 自帶 API。

Q23:用httpurlconnection請求的時候,會發現返回請求很耗時,一般怎麼處理?

儘可能減少慢查詢吧?我們很多工作就是想辦法如何減少慢查詢,routing和分分合合,就是這個目的。

Q24:生產環境單