Elasticsearch技術分享--基於5.1.1版本
主要內容
o一 簡介
o二 基本概念介紹
o三 底層實現原理&叢集搭建(乾貨)
o四 對搜尋系統的優化&問題解決方式(乾貨)
o五 參考資料
二 基本概念介紹
2.1 叢集、分片、節點概念介紹
2.2 索引、型別、文件概念介紹
2.3 資料的寫入過程
2.4 寫入路由優化(重點)
2.5 分散式查詢
2.6 深度翻頁問題(重點)
2.1 叢集、分片、節點概念介紹
l 叢集:多臺Es伺服器的結合的統稱叫ES叢集。
l 節點:一個節點是你叢集中的一臺伺服器,作為叢集的一部分,它儲存你的資料,參與叢集的索引和搜尋功能。
分片:將資料切分,分佈的放在每個分片中,分片又被放到叢集中
每個分片是獨立索引的概念是,即使某個分片壞了,也不影響其他分片的查詢。這樣做的好處有點兩點。
1、橫向擴充套件,水平分割資料容量。 2、可以在分片上並行的進行操作。
另外:分片數量在創立索引的時候就確定了,一旦建立分片的數量就不能再更改,所以需要在一開始就預估資料規模,設定合理分片數量。資料量過大,分片會無法落到磁碟中(datacenter案例)
另外一種解決方式:自動拆分索引、或者重建索引。
分片:分為主分片和備份分片,副本分片數提高了資料冗餘量,主分片掛掉以後能夠自動由副本分片升為主分片,實現業務方無感知自我修復。備份分片還能夠降低主分片的查詢壓力。但是也會消耗更多的系統性能。
分片數量合理設定:跟業務的實際使用場景有關,千萬級別以下預設五個分片就足夠。億級需要壓測,直至業務方認為查詢延遲已經無法接受,此時認為分片數量已經不夠。一個經驗值就是每個分片不要超過30G,分片大小已經達到效能瓶頸,就需要考慮拆分索引。
l索引: 一個索引就是一個擁有幾分相似特徵的文件的集合(相當於一個數據庫)。
l型別: 在一個索引中,你可以定義一種或多種型別。一個型別是你的索引的一個邏輯上的分類/分割槽,其語義完全由你來定(相當於資料庫中的一個表)。
l文件:是一個可被索引的基礎資訊單元。文件以JSON格式來表示(一條資料)。
Es6.x版本已經移除type的概念,一個索引只對應一個type,思考下為什麼?因為前面說了,分片數量一旦設定,就不能修改,只能通過重建的形式。如果某個type發現分片沒有設定合理,重建索引,就會影響到其他type.
但考細粒度的索引維護和索引重建.看下右邊的圖,found為true代表文字找到了,_version需要著重注意一下,是es自帶的版本號,使用者每當對一條資料更新一次,那版本號加1,如果使用者帶著版本號來更新一條資料,那麼es就丟擲version conflict異常,可以利用這個特點來進行併發控制。
source就是源文字,soucrce設定為false可以降低儲存空間,也就是說這些欄位並不是全部都要顯示,只需要顯示一部分。比如彈幕資料 如果所有的彈幕每個欄位都要儲存,那麼叢集的磁碟佔用空間就會急劇增加,因為索引更重要在於檢索,所以只對id進行了store,檢索出id後,再從mongo里拉取實際的資料顯示給使用者。
2.3 資料寫入索引過程
(1)客戶端向 Node 1 (協調節點)傳送新建、索引或者刪除請求。
(2)node1節點使用文件的 _id 確定文件屬於分片 0 。請求會被轉發到 Node 3
(3)Node 3 在主分片上面執行請求。如果成功了,它將請求並行轉發到 Node 1 和 Node 2 的副本分片上。
(4)一旦所有的副本分片都報告成功, Node 3 將向協調節點報告成功
(5)協調節點向客戶端報告成功。
2.4 寫入路由優化(重點)
(1)預設的路由規則:資料隨機打散將資料路由到不同的分片上,優點是避免了寫入熱點,但搜尋時,需要在所有分片上執行,最後彙總。該方式查詢效率較低。【適用於寫多,查詢少】
(2)指定路由規則:查詢資料時也按路由規則查詢,避免請求轉發至無用的分片,提升了查詢效率。缺點:容易出現寫入熱點,查詢與具體業務耦合,需要根據實際場景優化。【適用於具體業務查詢優化】
2.5 分散式檢索
2.5.1 基本概念
優先佇列:僅僅是一個存有 top-n 匹配文件的有序列表。優先佇列的大小取決於分頁引數 from 和 size 。例如,如下搜尋請求將需要足夠大的優先佇列來放入100條文件:
GET /_search{"from": 90,"size": 10}
2.5.2資料檢索過程
在es中分散式檢索分為兩個階段:查詢階段和取回階段。
查詢階段:
1.客戶端傳送一個 search 請求到 Node 3 , Node 3 會建立一個大小為 from + size 的空優先佇列。
2.Node 3 將查詢請求轉發到索引的每個主分片或副本分片中。每個分片在本地執行查詢並新增結果到大小為 from + size 的本地有序優先佇列中。
3.每個分片返回各自優先佇列中所有文件的 ID 和排序值給協調節點,也就是 Node 3 ,它合併這些值到自己的優先佇列中來產生一個全域性排序後的結果列表。
取回階段:
1.協調節點辨別出哪些文件需要被取回並向相關的分片提交多個 GET 請求。
2.每個分片載入並豐富文件,如果有需要的話,接著返回文件給協調節點。
3.一旦所有的文件都被取回了,協調節點返回結果給客戶端。
2.6 深度翻頁問題
舉例
以2.5節為例,使用者只需要獲取第90到100之間的10條資料,實際執行步驟為:
1.該索引有兩個分片,對兩個分片分別構造size=from+size=90+10=100的優先佇列,協處理節點對兩個優先佇列進行排序彙總,相當於對200條資料進行排序彙總。
2.根據彙總的結果,只取出10條資料,向持有這10條資料的分片發起查詢請求,將查詢結果彙總返回。
現在假設我們請求第 1000 頁--結果從 10001 到 10010 。所有都以相同的方式工作除了每個分片不得不產生前10010個結果以外。 然後協調節點對全部 50050 個結果排序最後丟棄掉這些結果中的 50040 個結果。
結論:
協調節點需要根據 number_of_shards * (from + size) 排序文件,來找到被包含在 size 裡的文件。可以看出,在分散式系統中,對結果排序的成本隨分頁的深度成指數上升。這就是 es預設限制對任何查詢都不要返回超過 10000 個結果的原因。ES針對大規模資料查詢需求,提供了滾動查詢介面。
三 底層實現原理&叢集搭建
3.1 文件索引的過程
3.2 底層資料結構(FST、倒排索引、bitMap)
3.3 機器選擇&叢集搭建
1.Es在公司搜尋頁面suggest功能展示
2.原文本到索引詞的轉化過程
3.1 文件索引的過程
分詞器:一個分詞由詞元分解器和詞元過濾器組成,使用者可以根據自己的需要,通過模板來配置。也可以直接在git上下載使用通用的分詞器如:ik、pinyin、mmseg等。
3.2 ES底層資料結構(倒排索引)
倒排索引:Elasticsearch 使用一種稱為 倒排索引 的結構,它適用於快速的全文搜尋。一個倒排索引由文件中所有不重複詞的列表構成,對於其中每個詞,有一個包含它的文件列表。
3.2 ES底層資料結構(FST)
FST :有窮狀態轉換器。其功能類似於字典樹(Trie)的功能,通過輸入字串構建最小有向無環圖。當Term dictionary資料量較大時,其檢索速度較慢,Term index使用FST作為資料結構,儲存著與Term Dictionary的block之間的對映關係,可以使term index快取到記憶體中。從term index查到對應的term dictionary的block位置之後,再去磁碟上找term,大大減少了磁碟隨機讀的次數。
HashMap、TreeMap與FST在100萬資料下效能測試結果
從hashMap和FST對比來看,FST要比HashMap各方面的效能表現都要差一些,但是lucene為什麼要選擇FST作為其字典的儲存結構呢?
因為FST最大的作用是節省儲存空間,實際佔用的儲存空間大約是HashMap的1/10左右。對於儲存在記憶體的資料來說,節省儲存空間是至關重要的。
對於一個合格的詞典結構來說,度量標準有以下幾點。
目前各種資料庫中比較常使用的資料結構就是B樹、跳躍表、FST,對於資料結構來說沒有最好的,而是針對於各種業務場景更適合的。
MySQL InnoDB索引 使用的資料結構是B+樹,B+樹是一種多路平衡查詢樹,查詢複雜度是log(N),優點是外存索引,更新方便,快但是儲存空間大,查詢速度相對較慢。MySQL 這種關係型資料庫,對實時性要求特別高,要求寫入後能夠立馬檢索到,因此採用B+樹更為合適。
跳躍表:結構簡單,級數可控,但是對模糊查詢支援不太好,lucene3.x以下使用。
FST是es當前使用的資料結構,共享字首支援模糊查詢,但是其構造過程要求輸入有序,索引過程較慢。對於es來說,適用的場景並不要求寫入後能夠立馬能查詢到,而是在滿足業務需求的一定時間範圍內能查詢到,而對資料的查詢速度有更高的要求,因此使用FST作為資料結構。
在我看來,es在效能和對硬體要求之間找到了一個均衡點,首先其在記憶體中使用FST作為儲存結構,降低了記憶體消耗,但是其查詢效能和hashMap也差不了太多,查詢複雜度均為O(n),其次es將記憶體和磁碟結合,將term Index儲存在記憶體中,將term dictionary儲存在磁碟中,先在記憶體中快速定位term dictionary的位置,再term dictionary中利用二分搜尋和倒排索引快速查詢到term所對應的文件,提升了查詢速度。
0.9版本基於Lucene 4.x版本,而5.1.1版本依賴於lucence6版本
針對數值型別資料提出了新的資料結構Block K-D trees,改變了其搜尋和索引的方式,核心思想是將數字型別編碼成定長的位元組陣列,對定長的位元組陣列內容進行編碼排序,然後來構建二叉樹,然後依次遞迴構建,目前底層支援8個維度和最多每個維度16個位元組,基本滿足大部分場景。
啟動doc_vlaues是一種列式儲存結構:es排序、聚合時需要佔用大量的記憶體空間,啟動doc_values後,使用硬碟而非記憶體儲存fielddata,在索引時構建,降低了對記憶體的使用,進而降低了GC壓力。
4.3ES使用優化
3.更改查詢和寫入邏輯:節點除了管理叢集,還儲存著元資料資訊(包含索引id和別名之間的對映關係),之前搜尋系統寫入資料時,每次使用別名獲取indexId,然後使用indexId寫入,使得master節點寫入高峰時負載較高。在大叢集中master節點掛掉後需要長達十幾分鍾選舉出新節點,期間對任何請求請求不做響應。修改後,寫入資料時不再獲取元資料資訊,提高寫入、查詢效能,使得es Master節點cpu平均負載從60%左右降低到5%以下,提高系統穩定性,提升寫入和查詢效能。
•
五 參考資料
1.es中文官網:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
2.es優化建議:http://www.jianshu.com/p/29ffce0850af
3.入門材料:http://blog.csdn.net/leixingbang1989/article/details/75268293
5.elasticsearch中文社群公共號(推送es最新動態):elastic-cn
6.elasticsearch研究會:Lucene_Elasticsearch