Elasticsearch淺析

目錄

Elasticsearch簡介
基本概念
Elasticsearch特點
Elasticsearch節點類型
Elasticsearch集羣狀態
Elasticsearch集羣選舉
Elasticsearch寫操作
Elasticsearch更新和刪除操作
Elasticsearch讀操作
Elasticsearch故障轉移
Elasticsearch優化點
問題
Elasticsearch主要特性
參考文檔

Elasticsearch簡介

Elasticsearch是一個近實時的分佈式搜索分析引擎,常被用作全文搜索,結構化搜索,分析等。它使用 Java 編寫的且開源,它的內部使用 Lucene 做索引與搜索,但是它的目的是使全文檢索變得簡單,通過隱藏 Lucene 的複雜性,取而代之的提供一套簡單一致的 RESTful API。

Lucene 是一個基於Java的全文信息檢索工具庫,它不是一個完整的搜索應用程序,而是爲你的應用程序提供索引和搜索功能。Lucene 目前是Apache Jakarta家族中的一個開源項目。也是目前最爲流行的基於 Java 開源全文檢索工具庫。

然而,Elasticsearch 不僅僅是 Lucene,並且也不僅僅只是一個全文搜索引擎。 它可以被下面這樣準確的形容:

  • 一個分佈式的實時文檔存儲,每個字段可以被索引與搜索
  • 一個分佈式近實時分析搜索引擎
  • 能勝任上百個服務節點的擴展,並支持PB級別的結構化或者非結構化數據

基本概念

cluster集羣:一個或多個節點的集合,通過啓動時指定名字作爲唯一標識,默認cluster-state
node節點:啓動的ES的單個實例,保存數據並具有索引和搜索的能力,通過名字在集羣中唯一標識,默認node-n
index索引:具有相似特點的文檔的集合,可以對應爲關係型數據庫中的數據庫,通過名字在集羣內唯一標識。可以對應爲Mysql中的數據庫。
type文檔類別:索引內部的邏輯分類,ES 6.x 版本中,一個索引只允許一個type,不再支持多個type。7.x版本中,type將廢棄。可以對應爲Mysql數據庫中的表。
document文檔:構成索引的最小單元,屬於一個索引的某個類別,通過id 在Type 內唯一標識。可以對應Mysql數據庫的表中的行。
field字段:構成文檔的單元。可以對應Mysql數據庫的表中的列。
mapping索引映射:用來約束文檔字段的類型,可以理解爲索引內部結構。可以對應Mysql數據庫的表中每列的類型。
shard分片:將索引分爲多個塊,每塊叫做一個分片。索引定義時需要指定分片數且不能更改,默認一個索引有5個分片,每個分片都是一個功能完整的Index,分片帶來規模上(數據水平切分)和性能上(並行執行)的提升,是ES數據存儲的最小單位。
replicas分片的備份:每個分片默認一個備份分片,它可以提升節點的可用性,同時能夠提升搜索時的併發性能(搜索可以在全部分片上並行執行)

Elasticsearch特點

倒排索引

索引是現代搜索引擎的核心,建立索引的過程就是把源數據處理成非常方便查詢的索引文件的過程。

爲什麼索引這麼重要呢,試想你現在要在大量的文檔中搜索含有某個關鍵詞的文檔,那麼如果不建立索引的話你就需要把這些文檔順序的讀入內存,然後檢查這個文章中是不是含有要查找的關鍵詞,這樣的話就會耗費非常多的時間,想想搜索引擎可是在毫秒級的時間內查找出要搜索的結果的。這就是由於建立了索引的原因,你可以把索引想象成這樣一種數據結構,他能夠使你快速的隨機訪問存儲在索引中的關鍵詞,進而找到該關鍵詞所關聯的文檔。

Lucene 採用的是一種稱爲倒排索引(inverted index)的機制。反向索引就是說我們維護了一個詞 / 短語表,對於這個表中的每個詞 / 短語,都有一個鏈表描述了有哪些文檔包含了這個詞 / 短語。這樣在用戶輸入查詢條件的時候,就能非常快的得到搜索結果。我們將在本系列文章的第二部分詳細介紹 Lucene 的索引機制,由於 Lucene 提供了簡單易用的 API,所以即使讀者剛開始對全文本進行索引的機制並不太瞭解,也可以非常容易的使用 Lucene 對你的文檔實現索引。

對文檔建立好索引後,就可以在這些索引上面進行搜索了。搜索引擎首先會對搜索的關鍵詞進行解析,然後再在建立好的索引上面進行查找,最終返回和用戶輸入的關鍵詞相關聯的文檔。

我們來看下如下 2 個文檔是如何被倒排索引的:
文檔 1(Doc 1): Insight Data Engineering Fellows Program
文檔 2(Doc 2): Insight Data Science Fellows Program

詞項 文檔
data Doc1,Doc2
engineering Doc1
fellows Doc1,Doc2
insight Doc1,Doc2
program Doc1,Doc2
science Doc2

全文檢索

全文檢索首先將要查詢的目標文檔中的詞提取出來,組成索引,通過查詢索引達到搜索目標文檔的目的。這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。

全文搜索兩個最重要的方面是:

相關性(Relevance)

它是評價查詢與其結果間的相關程度,並根據這種相關程度對結果排名的一種能力,這種計算方式可以是 TF/IDF 方法(檢索詞頻率/反向文檔頻率)、地理位置鄰近、模糊相似,或其他的某些算法。

分析(Analysis)

它是將文本塊轉換爲有區別的、規範化的token的一個過程,目的是爲了創建倒排索引以及查詢倒排索引。

分析主要包含下面的過程:
1,將一塊文本分成適合於倒排索引的獨立的詞條(例如遇見空格和標點來分詞)
2,將這些詞條統一化爲標準格式(例如小寫化Quick,刪除詞條像 a,and,the等無用詞,增加詞條像jump和leap這種同義詞等)以提高它們的“可搜索性”

結構化搜索

結構化搜索(Structured search)是指有關探詢那些具有內在結構數據的過程。比如日期、時間和數字都是結構化的:它們有精確的格式,我們可以對這些格式進行邏輯操作,例如做大小對比等。

在結構化查詢中,我們得到的結果總是非是即否,要麼存於集合之中,要麼存在集合之外。結構化查詢不關心文件的相關度或評分;它簡單的對文檔包括或排除處理。

面向文檔

Elasticsearch是面向文檔的,意味着它存儲整個對象或文檔,這裏的文檔可以指一個HTML頁面,一封電子郵件,或者是一個文本文件。一個 Document 對象由多個 Field 對象組成的。可以把一個 Document 對象想象成數據庫中的一個記錄,而每個 Field 對象就是記錄的一個字段。Elasticsearch不僅存儲文檔,而且索引每個文檔的內容,使之可以被檢索。在Elasticsearch中,我們對文檔進行索引、檢索、排序和過濾,而不是對行列數據。這是一種完全不同的思考數據的方式,也是 Elasticsearch 能支持複雜全文檢索的原因。

Elasticsearch 使用 JavaScript Object Notation(或者 JSON)作爲文檔的序列化格式。JSON 序列化爲大多數編程語言所支持,並且已經成爲 NoSQL 領域的標準格式。 它簡單、簡潔、易於閱讀。

下面這個 JSON 文檔代表了一個簡單的 user 對象:
{
"email": "[email protected]",
"first_name": "John",
"last_name": "Smith",
"join_date": "2014/05/01"
}

海量數據近實時檢索

雖然 Elasticsearch 中的變更不能立即可見,它還是提供了一個近實時的搜索引擎。 Lucene 的變更到磁盤是一個代價昂貴的操作。爲了避免在文檔對查詢依然有效的時候,提交變更到磁盤,Elasticsearch 在內存緩衝和磁盤之間提供了一個文件系統緩存。內存緩存 (默認情況下) 每 1 秒刷新一次,在文件系統緩存中使用倒排索引創建一個新的段。這個段是開放的並對搜索有效。

文件系統緩存可以擁有文件句柄,文件可以是開放的、可讀的或者是關閉的,但是它存在於內存之中。因爲刷新間隔默認是 1 秒,變更不能立即可見,所以說是近實時的。因爲 translog 是尚未落盤的變更持久化記錄,它能有助於 CRUD 操作方面的近實時性。對於每次請求來說,在查找相關段之前,任何最近的變更都能從 translog 搜索到,因此客戶端可以訪問到所有的近實時變更。

你可以在創建 / 更新 / 刪除操作後顯式地刷新索引,使變更立即可見,但我並不推薦你這樣做,因爲這樣會創建出來非常多的小 segment 而影響搜索性能。

Elasticsearch節點類型

一個 Elasticsearch實例是一個節點,一組節點組成了集羣。Elasticsearch 集羣中的節點可以配置爲 3 種不同的角色:

  • 主節點:控制 Elasticsearch 集羣,負責集羣中的操作,比如創建 / 刪除一個索引,跟蹤集羣中的節點,分配分片到節點。主節點處理集羣的狀態並廣播到其他節點,並接收其他節點的確認響應。每個節點都可以通過設定配置文件elasticsearch.yml中的node.master屬性爲true(默認) 成爲主節點。對於大型的生產集羣來說,推薦使用一個專門的主節點來控制集羣,該節點將不處理任何用戶請求。

  • 數據節點:持有數據和倒排索引。默認情況下,每個節點都可以通過設定配置文件elasticsearch.yml中的node.data屬性爲true(默認) 成爲數據節點。如果我們要使用一個專門的主節點,應將其node.data屬性設置爲false。

  • 客戶端節點:如果我們將node.master屬性和node.data屬性都設置爲false,那麼該節點就是一個客戶端節點,扮演一個負載均衡的角色,將到來的請求路由到集羣中的各個節點。

Elasticsearch集羣狀態

green:所有的主分片和副本分片都正常運行。
yellow:所有的主分片都正常運行,但不是所有的副本分片都正常運行。
red:有主分片沒能正常運行。

Elasticsearch集羣選舉

Elasticsearch使用自己開發的zen discovery算法來選舉集羣的master。大概原理如下:
1,對所有可以成爲master的節點根據nodeId排序,每次選舉每個節點都把自己所知道節點排一次序,然後選出第一個(第0位)節點,暫且認爲它是master節點。

2,如果對某個節點的投票數達到一定的值(可以成爲master節點數n/2+1)並且該節點自己也選舉自己,那這個節點就是master。否則重新選舉。

3,對於腦裂問題,需要把候選master節點最小值設置爲可以成爲master節點數n/2+1(quorum )

Elasticsearch寫操作

write

當我們發送索引一個新文檔的請求到協調節點後,將發生如下一組操作:

  • Elasticsearch集羣中的每個節點都包含了改節點上分片的元數據信息。協調節點 (默認)使用文檔ID參與計算,以便爲路由提供合適的分片。Elasticsearch使用MurMurHash3函數對文檔ID進行哈希,其結果再對分片數量取模,得到的結果即是索引文檔的分片。
    公式:shard = hash(document_id) % (num_of_primary_shards)
  • 當分片所在的節點接收到來自協調節點的請求後,會將該請求寫入 translog(我們將在本系列接下來的文章中講到),並將文檔加入內存緩衝。如果請求在主分片上成功處理,該請求會並行發送到該分片的副本上。當translog 被同步( fsync ) 到全部的主分片及其副本上後,客戶端纔會收到確認通知。
  • 內存緩衝會被週期性刷新 (默認是 1 秒),內容將被寫到文件系統緩存的一個新段上。雖然這個段並沒有被同步 (fsync),但它是開放的,內容可以被搜索到。
  • 每 30 分鐘,或者當 translog 很大的時候,translog 會被清空,文件系統緩存會被同步。這個過程在 Elasticsearch 中稱爲沖洗 (flush)。在沖洗過程中,內存中的緩衝將被清除,內容被寫入一個新段。段的 fsync 將創建一個新的提交點,並將內容刷新到磁盤。舊的 translog 將被刪除並開始一個新的 translog。

Elasticsearch更新和刪除操作

刪除和更新也都是寫操作。但是 Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動以展示其變更。那麼,該如何刪除和更新文檔呢?

磁盤上的每個段都有一個相應的.del文件。當刪除請求發送後,文檔並沒有真的被刪除,而是在.del文件中被標記爲刪除。該文檔依然能匹配查詢,但是會在結果中被過濾掉。當段合併 (我們將在本系列接下來的文章中講到) 時,在.del文件中被標記爲刪除的文檔將不會被寫入新段。

接下來我們看更新是如何工作的。在新的文檔被創建時,Elasticsearch 會爲該文檔指定一個版本號。當執行更新時,舊版本的文檔在.del文件中被標記爲刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,但是會在結果中被過濾掉。

Elasticsearch讀操作

write

讀操作包含 2 部分內容:
1,查詢階段
2,提取階段

查詢階段

在這個階段,協調節點會將查詢請求路由到索引的全部分片 (主分片或者其副本) 上。每個分片獨立執行查詢,併爲查詢結果創建一個優先隊列,以相關性得分排序 (我們將在本系列的後續文章中講到)。全部分片都將匹配文檔的 ID 及其相關性得分返回給協調節點。協調節點創建一個優先隊列並對結果進行全局排序。會有很多文檔匹配結果,但是,默認情況下,每個分片只發送前 10 個結果給協調節點,協調節點爲全部分片上的這些結果創建優先隊列並返回前 10 個作爲 hit。

提取階段

當協調節點在生成的全局有序的文檔列表中,爲全部結果排好序後,它將向包含原始文檔的分片發起請求。全部分片填充文檔信息並將其返回給協調節點。

Elasticsearch故障轉移

故障檢測原理

master 節點會 ping所有其他節點,以檢查它們是否還活着;然後所有節點 ping 回去,告訴 master 他們還活着。

故障轉移

前面
後面

  • 我們關閉一個主節點Node1。而集羣必須擁有一個主節點來保證正常工作,所以發生的第一件事情就是選舉一個新的主節點:Node 2。
    在我們關閉 Node 1的同時也失去了主分片1和2,並且在缺失主分片的時候索引也不能正常工作。如果此時來檢查集羣的狀況,我們看到的狀態將會爲 red :不是所有主分片都在正常工作。

  • 我看看到在其它節點上存在着這兩個主分片的完整副本, 所以新的主節點立即將這些分片在 Node 2 和 Node 3 上對應的副本分片提升爲主分片, 此時集羣的狀態將會爲 yellow 。 這個提升主分片的過程是瞬間發生的,如同按下一個開關一般。爲什麼我們集羣狀態是yellow而不是green呢?雖然我們擁有所有的三個主分片,但是同時設置了每個主分片需要對應2份副本分片,而此時只存在一份副本分片。所以集羣不能爲 green 的狀態。(如果我們設置的副本爲1,則集羣狀態會變爲green)

  • 如果我們重新啓動 Node 1 ,集羣可以將缺失的副本分片再次進行分配,那麼集羣的狀態也將完全正常,恢復green狀態。 如果 Node 1 依然擁有着之前的分片,它將嘗試去重用它們,同時僅從主分片複製發生了修改的數據文件。

Elasticsearch優化點

1,單節點內存不超過32G,使用jvm壓縮指針
2,合理設置索引template,包括settings和mappings
3,使用ssd提升磁盤io
4,數據量大的時候,使用用from,size來深層分頁非常消耗性能,應該禁止使用
5,關閉不使用的索引
6,留一半的系統內存供文件系統緩存使用
7,使用bulk寫入
8,增大實時性要求不高的索引refresh時間
9,關閉系統swap
10,整個集羣重啓情況下,延遲分片策略按照需要調整

問題

整個集羣重啓,恢復慢問題

原因:
1,需要加載所有active狀態index的translog,保證主shard數據完整性主shard恢復之後,rep從主shard複製缺少的部分
2,shard過多

緩解:
1,關閉不需要的索引
2,重啓前flush集羣的translog
3,集羣恢復的時候,關閉集羣寫入,降低集羣系統壓力

無法分配的shard

原因:
1,文件損壞或者文件系統問題
2,機器壓力大導致,allocation分配超時

工具:
1,可以使用explain API具體查看分配失敗的原因

解決:
1,開啓關閉索引,觸發重新分配
2,設置rep爲0
3,使用rerouting API,可能有丟數據風險

Elasticsearch主要特性

高級特性

1,支持類似SQL查詢
2,機器學習

最新穩定7.x新特性

1,默認分片調整爲1
2,無type索引結構
3,kibana支持暗黑模式
4,使用Term查詢性能提升3700%
5,對內存管理更加健壯,降低OOM發生
6,時間戳支持納秒級別

參考文檔

https://www.elastic.co/guide/cn/elasticsearch/guide/cn/getting-started.html
https://www.ibm.com/developerworks/cn/java/j-lo-lucene1/
https://www.infoq.cn/article/analysis-of-elasticsearch-cluster-part01/?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=articles_link&utm_content=link_text
https://www.elastic.co/cn/elasticsearch/features
https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章