20大進階架構(gòu)專題每日送達 來源: https://www.cnblogs.com/mikevictor07/p/10006553.html 一,、前言數(shù)據(jù)平臺已迭代三個版本,,從頭開始遇到很多常見的難題,終于有片段時間整理一些已完善的文檔,,在此分享以供所需朋友的 實現(xiàn)參考,,少走些彎路,在此篇幅中偏重于ES的優(yōu)化,,關(guān)于HBase,,Hadoop的設(shè)計優(yōu)化估計有很多文章可以參考,不再贅述,。 二,、需求說明項目背景: 在一業(yè)務(wù)系統(tǒng)中,部分表每天的數(shù)據(jù)量過億,,已按天分表,,但業(yè)務(wù)上受限于按天查詢,并且DB中只能保留3個月的數(shù)據(jù)(硬件高配),,分庫代價較高,。 改進版本目標:
三、elasticsearch檢索原理3.1 關(guān)于ES和Lucene基礎(chǔ)結(jié)構(gòu)談到優(yōu)化必須能了解組件的基本原理,,才容易找到瓶頸所在,,以免走多種彎路,先從ES的基礎(chǔ)結(jié)構(gòu)說起(如下圖): 一些基本概念:
ES依賴一個重要的組件Lucene,,關(guān)于數(shù)據(jù)結(jié)構(gòu)的優(yōu)化通常來說是對Lucene的優(yōu)化,它是集群的一個存儲于檢索工作單元,,結(jié)構(gòu)如下圖: 在Lucene中,,分為索引(錄入)與檢索(查詢)兩部分,索引部分包含 分詞器,、過濾器、字符映射器等,,檢索部分包含 查詢解析器 等,。 一個Lucene索引包含多個segments,,一個segment包含多個文檔,每個文檔包含多個字段,,每個字段經(jīng)過分詞后形成一個或多個term,。 通過Luke工具查看ES的lucene文件如下,主要增加了_id和_source字段: 3.2 Lucene索引實現(xiàn)Lucene 索引文件結(jié)構(gòu)主要的分為:詞典,、倒排表,、正向文件、DocValues等,,如下圖: 注:整理來源于lucene官方:
Lucene 隨機三次磁盤讀取比較耗時,。其中.fdt文件保存數(shù)據(jù)值損耗空間大,.tim和.doc則需要SSD存儲提高隨機讀寫性能,。 另外一個比較消耗性能的是打分流程,,不需要則可屏蔽。 關(guān)于DocValues: 倒排索引解決從詞快速檢索到相應(yīng)文檔ID, 但如果需要對結(jié)果進行排序,、分組,、聚合等操作的時候則需要根據(jù)文檔ID快速找到對應(yīng)的值。 通過倒排索引代價缺很高:需迭代索引里的每個詞項并收集文檔的列里面 token,。這很慢而且難以擴展:隨著詞項和文檔的數(shù)量增加,,執(zhí)行時間也會增加。Solr docs對此的解釋如下:
在lucene 4.0版本前通過FieldCache,,原理是通過按列逆轉(zhuǎn)倒排表將(field value ->doc)映射變成(doc -> field value)映射,,問題為逐步構(gòu)建時間長并且消耗大量內(nèi)存,容易造成OOM,。 DocValues是一種列存儲結(jié)構(gòu),,能快速通過文檔ID找到相關(guān)需要排序的字段。在ES中,,默認開啟所有(除了標記需analyzed的字符串字段)字段的doc values,,如果不需要對此字段做任何排序等工作,則可關(guān)閉以減少資源消耗,。 3.3 關(guān)于ES索引與檢索分片ES中一個索引由一個或多個lucene索引構(gòu)成,,一個lucene索引由一個或多個segment構(gòu)成,其中segment是最小的檢索域,。 數(shù)據(jù)具體被存儲到哪個分片上:
默認情況下 routing參數(shù)是文檔ID (murmurhash3),可通過 URL中的 _routing 參數(shù)指定數(shù)據(jù)分布在同一個分片中,,index和search的時候都需要一致才能找到數(shù)據(jù) 如果能明確根據(jù)_routing進行數(shù)據(jù)分區(qū),則可減少分片的檢索工作,,以提高性能,。 四、優(yōu)化案例在我們的案例中,查詢字段都是固定的,,不提供全文檢索功能,,這也是幾十億數(shù)據(jù)能秒級返回的一個大前提:
一些細節(jié)優(yōu)化項官方與其他的一些文章都有描述,在此文章中僅提出一些本案例的重點優(yōu)化項,。 4.1 優(yōu)化索引性能1,、批量寫入,看每條數(shù)據(jù)量的大小,,一般都是幾百到幾千,。 2、多線程寫入,,寫入線程數(shù)一般和機器數(shù)相當,,可以配多種情況,在測試環(huán)境通過Kibana觀察性能曲線,。 3,、增加segments的刷新時間,通過上面的原理知道,,segment作為一個最小的檢索單元,,比如segment有50個,目的需要查10條數(shù)據(jù),,但需要從50個segment分別查詢10條,,共500條記錄,再進行排序或者分數(shù)比較后,,截取最前面的10條,,丟棄490條。 在我們的案例中將此 'refresh_interval': '-1' ,,程序批量寫入完成后進行手工刷新(調(diào)用相應(yīng)的API即可),。 4、內(nèi)存分配方面,,很多文章已經(jīng)提到,,給系統(tǒng)50%的內(nèi)存給Lucene做文件緩存,它任務(wù)很繁重,,所以ES節(jié)點的內(nèi)存需要比較多(比如每個節(jié)點能配置64G以上最好),。 5,、磁盤方面配置SSD,機械盤做陣列RAID5 RAID10雖然看上去很快,,但是隨機IO還是SSD好,。 6、 使用自動生成的ID,,在我們的案例中使用自定義的KEY,也就是與HBase的ROW KEY,,是為了能根據(jù)rowkey刪除和更新數(shù)據(jù),,性能下降不是很明顯。 7,、關(guān)于段合并,,合并在后臺定期執(zhí)行,比較大的segment需要很長時間才能完成,,為了減少對其他操作的影響(如檢索),,elasticsearch進行閾值限制,默認是20MB/s,, 可配置的參數(shù):'indices.store.throttle.max_bytes_per_sec' : '200mb' (根據(jù)磁盤性能調(diào)整) 合并線程數(shù)默認是:Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),, 如果是機械磁盤,可以考慮設(shè)置為1:index.merge.scheduler.max_thread_count: 1,,在我們的案例中使用SSD,,配置了6個合并線程。 4.2 優(yōu)化檢索性能1,、關(guān)閉不需要字段的doc values,。 2、盡量使用keyword替代一些long或者int之類,,term查詢總比range查詢好 (參考lucene說明 ),。
3、關(guān)閉不需要查詢字段的_source功能,,不將此存儲僅ES中,,以節(jié)省磁盤空間。 4,、評分消耗資源,,如果不需要可使用filter過濾來達到關(guān)閉評分功能,score則為0,,如果使用constantScoreQuery則score為1,。 5、關(guān)于分頁:
6,、關(guān)于排序:我們增加一個long字段,,它用于存儲時間和ID的組合(通過移位即可),正排與倒排性能相差不明顯,。 7,、關(guān)于CPU消耗,檢索時如果需要做排序則需要字段對比,,消耗CPU比較大,,如果有可能盡量分配16cores以上的CPU,具體看業(yè)務(wù)壓力,。 8,、關(guān)于合并被標記刪除的記錄,我們設(shè)置為0表示在合并的時候一定刪除被標記的記錄,,默認應(yīng)該是大于10%才刪除:'merge.policy.expunge_deletes_allowed': '0',。 { 五,、性能測試優(yōu)化效果評估基于基準測試,如果沒有基準測試無法了解是否有性能提升,,在這所有的變動前做一次測試會比較好,。在我們的案例中:
性能的測試組合有很多,通常也很花時間,,不過作為評測標準時間上的投入有必要,,否則生產(chǎn)出現(xiàn)性能問題很難定位或不好改善。 對于ES的性能研究花了不少時間,,最多的關(guān)注點就是lucene的優(yōu)化,,能深入了解lucene原理對優(yōu)化有很大的幫助。 六,、生產(chǎn)效果目前平臺穩(wěn)定運行,幾十億的數(shù)據(jù)查詢100條都在3秒內(nèi)返回,,前后翻頁很快,,如果后續(xù)有性能瓶頸,可通過擴展節(jié)點分擔數(shù)據(jù)壓力,。
|
|
來自: 一劍e屋 > 《大數(shù)據(jù)》