ElasticSearch 億級數據檢索深度優化!

ElasticSearch 億級數據檢索深度優化!

1、前言

數據平臺已迭代三個版本,從頭開始遇到不少常見的難題,終於有片斷時間整理一些已完善的文檔,在此分享以供所需朋友的實現參考,少走些彎路,在此篇幅中偏重於ES的優化,關於HBase,Hadoop的設計優化估計有不少文章能夠參考,再也不贅述。html

2、需求說明

項目背景:

在一業務系統中,部分表天天的數據量過億,已按天分表,但業務上受限於按天查詢,而且DB中只能保留3個月的數據(硬件高配),分庫代價較高。apache

改進版本目標:
  1. 數據能跨月查詢,而且支持1年以上的歷史數據查詢與導出。緩存

  2. 按條件的數據查詢秒級返回。

3、Elasticsearch檢索原理

3.1 關於ES和Lucene基礎結構

談到優化必須能瞭解組件的基本原理,才容易找到瓶頸所在,以避免走多種彎路,先從ES的基礎結構提及(以下圖):安全

ElasticSearch 億級數據檢索深度優化!

一些基本概念:網絡

  • Cluster: 包含多個Node的集羣數據結構

  • Node: 集羣服務單元多線程

  • Index: 一個ES索引包含一個或多個物理分片,它只是這些分片的邏輯命名空間elasticsearch

  • Type: 一個index的不一樣分類,6.x後只能配置一個type,之後將移除ide

  • Document: 最基礎的可被索引的數據單元,如一個JSON串工具

  • Shards : 一個分片是一個底層的工做單元,它僅保存所有數據中的一部分,它是一個Lucence實例 (一個Lucene: 索引最大包含2,147,483,519 (= Integer.MAX_VALUE - 128)個文檔數量)

  • Replicas: 分片備份,用於保障數據安全與分擔檢索壓力

    ES依賴一個重要的組件Lucene,關於數據結構的優化一般來講是對Lucene的優化,它是集羣的一個存儲於檢索工做單元,結構以下圖:

ElasticSearch 億級數據檢索深度優化!

在Lucene中,分爲索引(錄入)與檢索(查詢)兩部分,索引部分包含分詞器、過濾器、字符映射器等,檢索部分包含查詢解析器等。

一個Lucene索引包含多個segments,一個segment包含多個文檔,每一個文檔包含多個字段,每一個字段通過分詞後造成一個或多個term。

經過Luke工具查看ES的lucene文件以下,主要增長了_id和_source字段:

ElasticSearch 億級數據檢索深度優化!

3.2 Lucene索引實現

Lucene 索引文件結構主要的分爲:詞典、倒排表、正向文件、DocValues等,以下圖:

ElasticSearch 億級數據檢索深度優化!

ElasticSearch 億級數據檢索深度優化!

Lucene隨機三次磁盤讀取比較耗時。其中.fdt文件保存數據值損耗空間大,.tim和.doc則須要SSD存儲提升隨機讀寫性能。另一個比較消耗性能的是打分流程,不須要則可屏蔽。

關於DocValues

倒排索引解決從詞快速檢索到相應文檔ID, 但若是須要對結果進行排序、分組、聚合等操做的時候則須要根據文檔ID快速找到對應的值。

經過倒排索引代價缺很高:需迭代索引裏的每一個詞項並收集文檔的列裏面 token。這很慢並且難以擴展:隨着詞項和文檔的數量增長,執行時間也會增長。Solr docs對此的解釋以下:

在lucene 4.0版本前經過FieldCache,原理是經過按列逆轉倒排表將(field value ->doc)映射變成(doc -> field value)映射,問題爲逐步構建時間長而且消耗大量內存,容易形成OOM。

DocValues是一種列存儲結構,能快速經過文檔ID找到相關須要排序的字段。在ES中,默認開啓全部(除了標記需analyzed的字符串字段)字段的doc values,若是不須要對此字段作任何排序等工做,則可關閉以減小資源消耗。

3.3 關於ES索引與檢索分片

ES中一個索引由一個或多個lucene索引構成,一個lucene索引由一個或多個segment構成,其中segment是最小的檢索域。

數據具體被存儲到哪一個分片上:shard = hash(routing) \% number_of_primary_shards

默認狀況下 routing參數是文檔ID (murmurhash3),可經過 URL中的 _routing 參數指定數據分佈在同一個分片中,index和search的時候都須要一致才能找到數據,若是能明確根據_routing進行數據分區,則可減小分片的檢索工做,以提升性能。

4、優化案例

在咱們的案例中,查詢字段都是固定的,不提供全文檢索功能,這也是幾十億數據能秒級返回的一個大前提:

  1. ES僅提供字段的檢索,僅存儲HBase的Rowkey不存儲實際數據。

  2. 實際數據存儲在HBase中,經過Rowkey查詢,以下圖。

  3. 提升索引與檢索的性能建議,可參考官方文檔(如 https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-indexing-speed.html)。

一些細節優化項官方與其餘的一些文章都有描述,在此文章中僅提出一些本案例的重點優化項。

ElasticSearch 億級數據檢索深度優化!

4.1 優化索引性能

  1. 批量寫入,看每條數據量的大小,通常都是幾百到幾千。

  2. 多線程寫入,寫入線程數通常和機器數至關,能夠配多種狀況,在測試環境經過Kibana觀察性能曲線。

  3. 增長segments的刷新時間,經過上面的原理知道,segment做爲一個最小的檢索單元,好比segment有50個,目的須要查10條數據,但須要從50個segment分別查詢10條,共500條記錄,再進行排序或者分數比較後,截取最前面的10條,丟棄490條。在咱們的案例中將此 "refresh_interval": "-1" ,程序批量寫入完成後進行手工刷新(調用相應的API便可)。

  4. 內存分配方面,不少文章已經提到,給系統50\%的內存給Lucene作文件緩存,它任務很繁重,因此ES節點的內存須要比較多(好比每一個節點能配置64G以上最好)。

  5. 磁盤方面配置SSD,機械盤作陣列RAID5 RAID10雖然看上去很快,可是隨機IO仍是SSD好。

  6. 使用自動生成的ID,在咱們的案例中使用自定義的KEY,也就是與HBase的ROW KEY,是爲了能根據rowkey刪除和更新數據,性能降低不是很明顯。

  7. 關於段合併,合併在後臺按期執行,比較大的segment須要很長時間才能完成,爲了減小對其餘操做的影響(如檢索),elasticsearch進行閾值限制,默認是20MB/s,可配置的參數:"indices.store.throttle.max_bytes_per_sec" : "200mb" (根據磁盤性能調整)合併線程數默認是:Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),若是是機械磁盤,能夠考慮設置爲1:index.merge.scheduler.max_thread_count: 1,在咱們的案例中使用SSD,配置了6個合併線程。

4.2 優化檢索性能

  1. 關閉不須要字段的doc values。

  2. 儘可能使用keyword替代一些long或者int之類,term查詢總比range查詢好 (參考lucene說明 http://lucene.apache.org/core/7\_4\_0/core/org/apache/lucene/index/PointValues.html)。

  3. 關閉不須要查詢字段的_source功能,不將此存儲僅ES中,以節省磁盤空間。

  4. 評分消耗資源,若是不須要可以使用filter過濾來達到關閉評分功能,score則爲0,若是使用constantScoreQuery則score爲1。

  5. 關於分頁:
  • from + size: 每分片檢索結果數最大爲 from + size,假設from = 20, size = 20,則每一個分片須要獲取20 * 20 = 400條數據,多個分片的結果在協調節點合併(假設請求的分配數爲5,則結果數最大爲 400*5 = 2000條) 再在內存中排序後而後20條給用戶。這種機制致使越日後分頁獲取的代價越高,達到50000條將面臨沉重的代價,默認from + size默認以下:index.max_result_window :10000

  • search_after: 使用前一個分頁記錄的最後一條來檢索下一個分頁記錄,在咱們的案例中,首先使用from+size,檢索出結果後再使用search_after,在頁面上咱們限制了用戶只能跳5頁,不能跳到最後一頁。

  • scroll 用於大結果集查詢,缺陷是須要維護scroll_id
  1. 關於排序:咱們增長一個long字段,它用於存儲時間和ID的組合(經過移位便可),正排與倒排性能相差不明顯。

  2. 關於CPU消耗,檢索時若是須要作排序則須要字段對比,消耗CPU比較大,若是有可能儘可能分配16cores以上的CPU,具體看業務壓力。

  3. 關於合併被標記刪除的記錄,咱們設置爲0表示在合併的時候必定刪除被標記的記錄,默認應該是大於10\%才刪除:"merge.policy.expunge_deletes_allowed": "0"

5、性能測試

優化效果評估基於基準測試,若是沒有基準測試沒法瞭解是否有性能提高,在這全部的變更前作一次測試會比較好。在咱們的案例中:

  1. 單節點5千萬到一億的數據量測試,檢查單點承受能力。

  2. 集羣測試1億-30億的數量,磁盤IO/內存/CPU/網絡IO消耗如何。

  3. 隨機不一樣組合條件的檢索,在各個數據量狀況下表現如何。

  4. 另外SSD與機械盤在測試中性能差距如何。

性能的測試組合有不少,一般也很花時間,不過做爲評測標準時間上的投入有必要,不然生產出現性能問題很難定位或很差改善。對於ES的性能研究花了很多時間,最多的關注點就是lucene的優化,能深刻了解lucene原理對優化有很大的幫助。

6、生產效果

目前平臺穩定運行,幾十億的數據查詢100條都在3秒內返回,先後翻頁很快,若是後續有性能瓶頸,可經過擴展節點分擔數據壓力。

*原文來自:https://www.jianshu.com/p/a6b875ff250d

相關文章
相關標籤/搜索