elasticsearch面試題(史上最全)

文章很長,建議收藏起來慢慢讀! 總目錄 博客園版 爲您奉上珍貴的學習資源 :


推薦:尼恩Java面試寶典(史上最全 + 面試必備)詳請點擊此鏈接

尼恩Java面試寶典,34個最新pdf,含2000多頁不斷更新、持續迭代 具體詳情,請點擊此鏈接

在這裏插入圖片描述

ElasticSearch基礎:

一、Elasticsearch 的基本概念:

1、什麼是Elasticsearch:

​ Elasticsearch 是基於 Lucene 的 Restful 的分佈式實時全文搜索引擎,每個字段都被索引並可被搜索,可以快速存儲、搜索、分析海量的數據。

全文檢索是指對每一個詞建立一個索引,指明該詞在文章中出現的次數和位置。當查詢時,根據事先建立的索引進行查找,並將查找的結果反饋給用戶的檢索方式。這個過程類似於通過字典中的檢索字表查字的過程。

2、Elasticsearch 的基本概念:

(1)index 索引:索引類似於mysql 中的數據庫,Elasticesearch 中的索引是存在數據的地方,包含了一堆有相似結構的文檔數據。

(2)type 類型:類型是用來定義數據結構,可以認爲是 mysql 中的一張表,type 是 index 中的一個邏輯數據分類

(3)document 文檔:類似於 MySQL 中的一行,不同之處在於 ES 中的每個文檔可以有不同的字段,但是對於通用字段應該具有相同的數據類型,文檔是es中的最小數據單元,可以認爲一個文檔就是一條記錄。

(4)Field 字段:Field是Elasticsearch的最小單位,一個document裏面有多個field

(5)shard 分片:單臺機器無法存儲大量數據,es可以將一個索引中的數據切分爲多個shard,分佈在多臺服務器上存儲。有了shard就可以橫向擴展,存儲更多數據,讓搜索和分析等操作分佈到多臺服務器上去執行,提升吞吐量和性能。

(6)replica 副本:任何服務器隨時可能故障或宕機,此時 shard 可能會丟失,通過創建 replica 副本,可以在 shard 故障時提供備用服務,保證數據不丟失,另外 replica 還可以提升搜索操作的吞吐量。

shard 分片數量在建立索引時設置,設置後不能修改,默認5個;replica 副本數量默認1個,可隨時修改數量;

3、什麼是倒排索引:

​ 在搜索引擎中,每個文檔都有對應的文檔 ID,文檔內容可以表示爲一系列關鍵詞的集合,例如,某個文檔經過分詞,提取了 20 個關鍵詞,而通過倒排索引,可以記錄每個關鍵詞在文檔中出現的次數和出現位置。也就是說,倒排索引是 關鍵詞到文檔 ID 的映射,每個關鍵詞都對應着一系列的文件,這些文件中都出現了該關鍵詞。

要注意倒排索引的兩個細節:

  • 倒排索引中的所有詞項對應一個或多個文檔
  • 倒排索引中的詞項 根據字典順序升序排列

4、doc_values 的作用:

​ 倒排索引雖然可以提高搜索性能,但也存在缺陷,比如我們需要對數據做排序或聚合等操作時,lucene 會提取所有出現在文檔集合的排序字段,然後構建一個排好序的文檔集合,而這個步驟是基於內存的,如果排序數據量巨大的話,容易造成內存溢出和性能緩慢。

​ doc_values 就是 es 在構建倒排索引的同時,會對開啓 doc_values 的字段構建一個有序的 “document文檔 ==> field value” 的列式存儲映射,可以看作是以文檔維度,實現了根據指定字段進行排序和聚合的功能,降低對內存的依賴。另外 doc_values 保存在操作系統的磁盤中,當 doc_values 大於節點的可用內存,ES可以從操作系統頁緩存中加載或彈出,從而避免發生內存溢出的異常,但如果 docValues 遠小於節點的可用內存,操作系統就自然將所有 doc_values 存於內存中(堆外內存),有助於快速訪問。

5、text 和 keyword類型的區別:

​ 兩個類型的區別主要是分詞:keyword 類型是不會分詞的,直接根據字符串內容建立倒排索引,所以keyword類型的字段只能通過精確值搜索到;Text 類型在存入 Elasticsearch 的時候,會先分詞,然後根據分詞後的內容建立倒排索引

6、query 和 filter 的區別?

(1)query:查詢操作不僅僅會進行查詢,還會計算分值,用於確定相關度;

(2)filter:查詢操作僅判斷是否滿足查詢條件,不會計算任何分值,也不會關心返回的排序問題,同時,filter 查詢的結果可以被緩存,提高性能。

二、ES的寫入流程:

1、ES寫數據的整體流程:

img

  • (1)客戶端選擇 ES 的某個 node 發送請求過去,這個 node 就是協調節點 coordinating node
  • (2)coordinating node 對 document 進行路由,將請求轉發給對應的 node(有 primary shard)
  • (3)實際的 node 上的 primary shard 處理請求,然後將數據同步到 replica node
  • (4)coordinating node 等到 primary node 和所有 replica node 都執行成功之後,最後返回響應結果給客戶端。

2、ES主分片寫數據的詳細流程:

Elasticsearch索引文檔的過程

(1)主分片先將數據寫入ES的 memory buffer,然後定時(默認1s)將 memory buffer 中的數據寫入一個新的 segment 文件中,並進入操作系統緩存 Filesystem cache(同時清空 memory buffer),這個過程就叫做 refresh;每個 segment 文件實際上是一些倒排索引的集合, 只有經歷了 refresh 操作之後,這些數據才能變成可檢索的。

ES 的近實時性:數據存在 memory buffer 時是搜索不到的,只有數據被 refresh 到 Filesystem cache 之後才能被搜索到,而 refresh 是每秒一次, 所以稱 es 是近實時的;可以手動調用 es 的 api 觸發一次 refresh 操作,讓數據馬上可以被搜索到;

(2)由於 memory Buffer 和 Filesystem Cache 都是基於內存,假設服務器宕機,那麼數據就會丟失,所以 ES 通過 translog 日誌文件來保證數據的可靠性,在數據寫入 memory buffer 的同時,將數據也寫入 translog 日誌文件中,當機器宕機重啓時,es 會自動讀取 translog 日誌文件中的數據,恢復到 memory buffer 和 Filesystem cache 中去。

ES 數據丟失的問題:translog 也是先寫入 Filesystem cache,然後默認每隔 5 秒刷一次到磁盤中,所以默認情況下,可能有 5 秒的數據會僅僅停留在 memory buffer 或者 translog 文件的 Filesystem cache中,而不在磁盤上,如果此時機器宕機,會丟失 5 秒鐘的數據。也可以將 translog 設置成每次寫操作必須是直接 fsync 到磁盤,但是性能會差很多。

(3)flush 操作:不斷重複上面的步驟,translog 會變得越來越大,不過 translog 文件默認每30分鐘或者 閾值超過 512M 時,就會觸發 commit 操作,即 flush操作,將 memory buffer 中所有的數據寫入新的 segment 文件中, 並將內存中所有的 segment 文件全部落盤,最後清空 translog 事務日誌。

  • ① 將 memory buffer 中的數據 refresh 到 Filesystem Cache 中去,清空 buffer;
  • ② 創建一個新的 commit point(提交點),同時強行將 Filesystem Cache 中目前所有的數據都 fsync 到磁盤文件中;
  • ③ 刪除舊的 translog 日誌文件並創建一個新的 translog 日誌文件,此時 commit 操作完成

更多 ES 的數據寫入流程的說明歡迎閱讀這篇文章:ElasticSearch搜索引擎:數據的寫入流程

三、ES的更新和刪除流程:

​ 刪除和更新都是寫操作,但是由於 Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動以展示其變更;所以 ES 利用 .del 文件 標記文檔是否被刪除,磁盤上的每個段都有一個相應的.del 文件

(1)如果是刪除操作,文檔其實並沒有真的被刪除,而是在 .del 文件中被標記爲 deleted 狀態。該文檔依然能匹配查詢,但是會在結果中被過濾掉。

(2)如果是更新操作,就是將舊的 doc 標識爲 deleted 狀態,然後創建一個新的 doc。

​ memory buffer 每 refresh 一次,就會產生一個 segment 文件 ,所以默認情況下是 1s 生成一個 segment 文件,這樣下來 segment 文件會越來越多,此時會定期執行 merge。每次 merge 的時候,會將多個 segment 文件合併成一個,同時這裏會將標識爲 deleted 的 doc 給物理刪除掉,不寫入到新的 segment 中,然後將新的 segment 文件寫入磁盤,這裏會寫一個 commit point ,標識所有新的 segment 文件,然後打開 segment 文件供搜索使用,同時刪除舊的 segment 文件

有關segment段合併過程,歡迎閱讀這篇文章:Elasticsearch搜索引擎:ES的segment段合併原理

四、ES的搜索流程:

搜索被執行成一個兩階段過程,即 Query Then Fetch:

1、Query階段:

​ 客戶端發送請求到 coordinate node,協調節點將搜索請求廣播到所有的 primary shard 或 replica,每個分片在本地執行搜索並構建一個匹配文檔的大小爲 from + size 的優先隊列。接着每個分片返回各自優先隊列中 所有 docId 和 打分值 給協調節點,由協調節點進行數據的合併、排序、分頁等操作,產出最終結果。

2、Fetch階段:

​ 協調節點根據 Query階段產生的結果,去各個節點上查詢 docId 實際的 document 內容,最後由協調節點返回結果給客戶端。

  • coordinate node 對 doc id 進行哈希路由,將請求轉發到對應的 node,此時會使用 round-robin 隨機輪詢算法,在 primary shard 以及其所有 replica 中隨機選擇一個,讓讀請求負載均衡。
  • 接收請求的 node 返回 document 給 coordinate node 。
  • coordinate node 返回 document 給客戶端。

​ Query Then Fetch 的搜索類型在文檔相關性打分的時候參考的是本分片的數據,這樣在文檔數量較少的時候可能不夠準確,DFS Query Then Fetch 增加了一個預查詢的處理,詢問 Term 和 Document frequency,這個評分更準確,但是性能會變差。

五、ES在高併發下如何保證讀寫一致性?

(1)對於更新操作:可以通過版本號使用樂觀併發控制,以確保新版本不會被舊版本覆蓋

每個文檔都有一個_version 版本號,這個版本號在文檔被改變時加一。Elasticsearch使用這個 _version 保證所有修改都被正確排序,當一箇舊版本出現在新版本之後,它會被簡單的忽略。

利用_version的這一優點確保數據不會因爲修改衝突而丟失,比如指定文檔的version來做更改,如果那個版本號不是現在的,我們的請求就失敗了。

(2)對於寫操作,一致性級別支持 quorum/one/all,默認爲 quorum,即只有當大多數分片可用時才允許寫操作。但即使大多數可用,也可能存在因爲網絡等原因導致寫入副本失敗,這樣該副本被認爲故障,副本將會在一個不同的節點上重建。

  • one:寫操作只要有一個primary shard是active活躍可用的,就可以執行
  • all:寫操作必須所有的primary shard和replica shard都是活躍可用的,纔可以執行
  • quorum:默認值,要求ES中大部分的shard是活躍可用的,纔可以執行寫操作

(3)對於讀操作,可以設置 replication 爲 sync(默認),這使得操作在主分片和副本分片都完成後纔會返回;如果設置replication 爲 async 時,也可以通過設置搜索請求參數 _preference 爲 primary 來查詢主分片,確保文檔是最新版本。

六、ES集羣如何選舉Master節點:

1、Elasticsearch 的分佈式原理:

​ Elasticsearch 會對存儲的數據進行切分,劃分到不同的分片上,同時每一個分片會生成多個副本,從而保證分佈式環境的高可用。ES集羣中的節點是對等的,節點間會選出集羣的 Master,由 Master 會負責維護集羣狀態信息,並同步給其他節點。

Elasticsearch 的性能會不會很低:不會,ES只有建立 index 和 type 時需要經過 Master,而數據的寫入有一個簡單的 Routing 規則,可以路由到集羣中的任意節點,所以數據寫入壓力是分散在整個集羣的。

2、ES集羣 如何 選舉 Master:

​ Elasticsearch 的選主是 ZenDiscovery 模塊負責的,主要包含Ping(節點之間通過這個RPC來發現彼此)和 Unicast(單播模塊包含一個主機列表以控制哪些節點需要ping通)這兩部分;

  • (1)確認候選主節點的最少投票通過數量(elasticsearch.yml 設置的值 discovery.zen.minimum_master_nodes)
  • (2)選舉時,集羣中每個節點對所有 master候選節點(node.master: true)根據 nodeId 進行字典排序,然後選出第一個節點(第0位),暫且認爲它是master節點。
  • (3)如果對某個節點的投票數達到閾值,並且該節點自己也選舉自己,那這個節點就是master;否則重新選舉一直到滿足上述條件。

補充:master節點的職責主要包括集羣、節點和索引的管理,不負責文檔級別的管理;data節點可以關閉http功能。

3、Elasticsearch是如何避免腦裂現象:

(1)當集羣中 master 候選節點數量不小於3個時(node.master: true),可以通過設置最少投票通過數量(discovery.zen.minimum_master_nodes),設置超過所有候選節點一半以上來解決腦裂問題,即設置爲 (N/2)+1;

(2)當集羣 master 候選節點 只有兩個時,這種情況是不合理的,最好把另外一個node.master改成false。如果我們不改節點設置,還是套上面的(N/2)+1公式,此時discovery.zen.minimum_master_nodes應該設置爲2。這就出現一個問題,兩個master備選節點,只要有一個掛,就選不出master了

七、建立索引階段性能提升方法:

  • (1)如果是大批量導入,可以設置 index.number_of_replicas: 0 關閉副本,等數據導入完成之後再開啓副本
  • (2)使用批量請求並調整其大小:每次批量數據 5–15 MB 大是個不錯的起始點。
  • (3)如果搜索結果不需要近實時性,可以把每個索引的 index.refresh_interval 改到30s
  • (4)增加 index.translog.flush_threshold_size 設置,從默認的 512 MB 到更大一些的值,比如 1 GB
  • (5)使用 SSD 存儲介質
  • (6)段和合並:Elasticsearch 默認值是 20 MB/s。但如果用的是 SSD,可以考慮提高到 100–200 MB/s。如果你在做批量導入,完全不在意搜索,你可以徹底關掉合併限流。

聊聊:什麼是ElasticSearch?

Elasticsearch是一個基於Lucene的全文搜索引擎,也可稱分佈式搜索引擎,用於Java開發的,且開源,具有Http Web和無框架Json文檔的分佈式。

2、ElasticSearch中的集羣、節點、索引、文檔、類型是什麼?

集羣:是一個或多個服務器的集合,共同保存數據並提供所有節點的聯合索引和搜索功能。集羣有唯一標誌,爲"ElasticSearch"。

節點:節點是屬於集羣一部分的單體服務器,儲存有數據並參與集羣索引和搜索功能。如果節點設置爲按名稱加入集羣,則該節點只能是集羣的一部分。

索引:類似關係型數據庫中的數據庫,有一個定義多重類型的映射。索引是邏輯名稱空間,可映射到一個或多個主分片,並且可以有不限個數的副本分片。

文檔:文檔類似關係型數據庫中的數據行,不同的是處在索引中的文檔可以有不同的結構或字段,但是通用字段應該具有相同的數據類型。

聊聊:列出 10 家使用 Elasticsearch 作爲其應用程序的搜索引擎和數據庫的公司?

參與過Elastic中文社區活動或者經常關注社區動態的人都知道,使用的公司太多了,列舉如下(排名不分先後):

阿里、騰訊、字節跳動、百度、京東、美團、小米、滴滴、攜程、貝殼找房、360、IBM、順豐快遞等等,幾乎能想到的互聯網公司都在使用Elasticsearch。

聊聊:ElasticSearch中的分片是什麼?

​ 談到分片需要談到索引,索引是類似關係型數據庫中的數據庫,有一個定義多重類型的映射。索引是邏輯名稱空間,可映射到一個或多個主分片,並且可以有不限個數的副本分片。因此分片是索引被分割成分佈在多個節點上的元素。

聊聊:ElasticSearch特點

1、Elasticsearch 是一個分佈式的 RESTful 風格的搜索和數據分析引擎

(1)查詢:搜索方式隨心而變。

(2)分析:可探索數據的趨勢和模式。

(3)速度:速度快。

(4)可擴展性:個人和企業服務器上都可用。

(5)彈性:Elasticsearch 運行在一個分佈式的環境中。

(6)靈活性:具備多個案例場景,支持所有數據類型

(7)HADOOP & SPARK : Elasticsearch + Hadoop

2、Elasticsearch是一個高度可伸縮的開源全文搜索和分析引擎。它允許您快速和接近實時地存儲、搜索和分析大量數據。

這裏有一些使用Elasticsearch的用例:

(1)網上商店。

(2)分析、調研日誌或事務數據。

(3)實時調度用戶關注信息的推送。

(4)結合Kibana (Elasticsearch/ loghide /Kibana堆棧的一部分)來構建自定義儀表板,以可視化自定義數據。此外,還可以使用Elasticsearch聚合功能對數據執行復雜的業務智能查詢。

聊聊:談談分詞與倒排索引的原理

分詞:分詞用於檢索,英文的分詞是按單詞之間空格區分,中文要考慮效率和準確分詞率,防止出現歧義。

倒排:根據文檔內容找文檔,從關鍵字去找文檔。

倒排索引是搜索引擎的核心。搜索引擎的主要目標是在查找發生搜索條件的文檔時提供快速搜索。區別於傳統的正向索引,倒排索引會再存儲數據時將關鍵詞和數據進行關聯,保存到倒排表中,然後查詢時,將查詢內容進行分詞後在倒排表中進行查詢,最後匹配數
據即可。Elasticsearch 使用一種稱爲倒排索引的結構,ES中的倒排索引其實就是 lucene 的倒排索引,它適用於快速的全文搜索。正向索引(forward index),就是搜索引擎會將待搜索的文件都對應一個文件 ID,搜索時將這個ID 和搜索關鍵字進行對應,形成 K-V 對,然後對關鍵字進行統計計數。但是互聯網上收錄在搜索引擎中的文檔的數目是個天文數字,這樣的索引結構根本無法滿足實時返回排名結果的要求。所以,搜索引擎會將正向索引重新構建爲反向索引(inverted index,倒排索引),即把文件ID對應到關鍵詞的映射,轉換爲關鍵詞到文件ID的映射,每個關鍵詞都對應着一系列的文件,並保存到倒排表中,查詢時會將內容進行分詞後在倒排表中進行查詢,最後匹配數據即可。這些文件中都出現這個關鍵詞。

聊聊:elasticsearch 的倒排索引是什麼

我們傳統的檢索方式是通過遍歷整篇文章,逐個比對找到對應的關鍵詞位置,

而倒排索引是通過分詞策略,形成詞和文章的關係映射表,這種詞典+映射表的方式就是倒排索引,有點類似於我們以前使用的新華字典。倒排索引可極大的提高查詢效率。

聊聊:elasticsearch 索引數據多了怎麼辦,如何調優,部署

1.在設計的時候可以基於模板+時間滾動方式創建索引,每天遞增數據,避免單個索引很大的情況出現。

2.在存儲的時候,冷熱數據分開存儲,比如最近3天的數據作爲熱數據,其他的作爲冷數據,冷數據的話,由於不會再寫入新數據了,可以考慮定期force_merge(強制合併)和shrink(壓縮)的方式進行處理,節約空間和檢索效率

3.由於es支持動態擴展,所有可以多加幾臺機器來緩解集羣壓力。

聊聊:什麼是近實時搜索?

在 Elasticsearch 和磁盤之間是文件系統緩存。在內存索引緩衝區中的文檔會被寫入到一個新的段中。 但是這裏新段會被先寫入到文件系統緩存,這一步代價會比較低,稍後再被刷寫到磁盤—這一步代價比較高。不過只要文件已經在緩存中,就可以像其它文件一樣被打開和讀取了。在 Elasticsearch 中,寫入和打開一個新段的輕量的過程叫做 refresh 。 默認情況下每個分片會每秒自動刷新一次,即刷新文件系統緩存。這就是爲什麼我們說 Elasticsearch 是 近實時搜索:文檔的變化並不是立即對搜索可見,但會在一秒之內變爲可見。這些行爲可能會對新用戶造成困惑:他們索引了一個文檔然後嘗試搜索它,但卻沒有搜到。這個問題的解決辦法是用 refresh API 執行一次手動刷新:/users/_refresh。

聊聊:如何理解 Elasticsearch 的近實時的性質,並改善它的不足?

並不是所有的情況都需要每秒刷新。可能你正在使用 Elasticsearch 索引大量的日誌文件,你可能想優化索引速度而不是近實時搜索, 可以通過設置 refresh_interval , 降低每個索引的刷新頻率。refresh_interval 可以在既存索引上進行動態更新。 在生產環境中,當你正在建立一個大的新索引時,可以先關閉自動刷新,待開始使用該索引時,再把它們調回來。

# 關閉自動刷新
PUT /users/_settings
{ "refresh_interval": -1 } 
# 每一秒刷新
PUT /users/_settings
{ "refresh_interval": "1s" }

聊聊:Elasticsearch 中索引在設計階段如何調優?

1)根據業務增量需求,採取基於日期模板創建索引,通過roll over API滾動索引;

2)使用別名進行索引管理;

3)每天凌晨定時對索引做force_merge操作,以釋放空間;

4)採取冷熱分離機制,熱數據存儲到SSD,提高檢索效率;冷數據定期進行shrink操作,以縮減存儲;

5)採取curator進行索引的生命週期管理;

5)僅針對需要分詞的字段,合理的設置分詞器;

6)Mapping階段充分結合各個字段的屬性,是否需要檢索、是否需要存儲等。

聊聊:解釋一下 Elasticsearch Node?

節點是Elasticsearch的實例。實際業務中,會說:ES集羣包含3個節點、7個節點。

這裏節點實際就是:一個獨立的Elasticsearch進程,一般將一個節點部署到一臺獨立的服務器或者虛擬機、容器中。

不同節點根據角色不同,可以劃分爲:

主節點

幫助配置和管理在整個集羣中添加和刪除節點。

數據節點

存儲數據並執行諸如CRUD(創建/讀取/更新/刪除)操作,對數據進行搜索和聚合的操作。

1、 客戶端節點(或者說:協調節點) 將集羣請求轉發到主節點,將與數據相關的請求轉發到數據節點

2、 攝取節點

用於在索引之前對文檔進行預處理。

聊聊:Elasticsearch 中分析器由哪幾部分組成?

分析器由三部分構成:

1、字符過濾器(Character Filters)

2、分詞器(Tokenizers)

3、分詞過濾器(Token Filters)

一個分析器不一定這三個部分都有,但是一般會包含分詞器。ES自帶的分析器有如下幾種:

Standard Analyzer、Simple Analyzer、Whitespace Analyzer、Stop Analyzer、Keyword Analyzer、Pattern Analyzer、Language Analyzers 和 Fingerprint Analyzer。

Elasticsearch內置了若干分析器類型,其中常用的是標準分析器,叫做”standard”。其中Standard Analyzer是ES默認的分析器,如果沒有指定任何分析器的話,ES將默認使用這種分析器。

分析器(Analyzer)通常由一個Tokenizer(怎麼分詞),以及若干個TokenFilter(過濾分詞)、Character Filter(過濾字符)組成。

聊聊:Elasticsearch中的 Ingest 節點如何工作?

ingest節點可以看作是數據前置處理轉換的節點,支持pipeline管道設置,可以使用ingest對數據進行過濾、轉換等操作,類似於logstash中filter的作用,功能相當強大。

聊聊:Elasticsearch 中的分析器是什麼?

分析(analysis)機制用於進行全文文本(Full Text)的分詞,以建立供搜索用的反向索引。

1、在ElasticSearch中索引數據時,數據由爲索引定義的Analyzer在內部進行轉換。分析器由一個Tokenizer和零個或多個TokenFilter組成。

編譯器可以在一個或多個CharFilter之前。分析模塊允許您在邏輯名稱下注冊分析器,然後可以在映射定義或某些API中引用它們。

2、Elasticsearch附帶了許多可以隨時使用的預建分析器。或者可以組合內置的字符過濾器,編譯器和過濾器器來創建自定義分析器。

聊聊:Elasticsearch 支持哪些配置管理工具?

Ansible、Chef、Puppet和Salt Stack是DevOps團隊使用的Elasticsearch支持的配置工具。

聊聊:ElasticSearch 的節點類型有什麼區別?

節點是指ElasticSearch的實例。當啓動Elasticsearch的實例,就會啓動至少一個節點。

相同集羣名的多個節點的連接就組成了一個集羣,在默認情況下,集羣中的每個節點都可以處理http請求和集羣節點間的數據傳輸,集羣中所有的節點都知道集羣中其他所有的節點,可以將客戶端請求轉發到適當的節點。

節點有以下類型:

主(master)節點:在一個節點上當node.master設置爲True(默認)的時候,它有資格被選作爲主節點,控制整個集羣。

數據(data)節點:在一個節點上node.data設置爲True(默認)的時候。該節點保存數據和執行數據相關的操作,如增刪改查,搜索,和聚合。

客戶端節點:當一個節點的node.master和node.data都設置爲false的時候,它既不能保持數據也不能成爲主節點,該節點可以作爲客戶端節點,可以響應用戶的情況,並把相關操作發送到其他節點。

部落節點:當一個節點配置tribe.*的時候,它是一個特殊的客戶端,它可以連接多個集羣,在所有連接的集羣上執行搜索和其他操作。

聊聊:Elasticsearch瞭解多少,聊聊你們公司ES的集羣架構,索引數據大小,分片有多少,以及一些調優手段 。

面試官:

想了解應聘者之前公司接觸的ES使用場景、規模,有沒有做過比較大規模的索引設計、規劃、調優。

解答策略:

如實結合自己的實踐場景回答即可。

比如:ES集羣架構13個節點,索引根據通道不同共20+索引,根據日期,每日遞增20+

索引:10分片,每日遞增1億+數據,每個通道每天索引大小控制:150GB之內。

索引層面調優手段

1、設計階段調優

1)根據業務增量需求,採取基於日期模板創建索引,通過roll over API滾動索引;
2)使用別名進行索引管理;
3)每天凌晨定時對索引做force_merge操作,以釋放空間;
4)採取冷熱分離機制,熱數據存儲到SSD,提高檢索效率;冷數據定期進行shrink操作,以縮減存儲;
5)採取curator進行索引的生命週期管理;
6)僅針對需要分詞的字段,合理的設置分詞器;
7)Mapping階段充分結合各個字段的屬性,是否需要檢索、是否需要存儲等。

2、寫入調優

1)寫入前副本數設置爲0;
2)寫入前關閉refresh_interval設置爲-1,禁用刷新機制;
3)寫入過程中:採取bulk批量寫入;
4)寫入後恢復副本數和刷新間隔;
5)儘量使用自動生成的id。

img

6)當寫入數據時,確保bulk請求時輪詢訪問所有節點。不要發送所有請求到一個節點,導致這一個節點要在內存存儲所有請求的數據去處理

3、查詢調優

1、filesystem cache越大越好 爲了使得搜索速度更快, es嚴重依賴filesystem cache

一般來說,需要至少一半的 可用內存作爲filesystem cache,這樣es可以在物理內存中 保有 索引的熱點區域(hot regions of the index)

2、用更好的硬件 搜索一般是I/O bound的,此時,你需要

  1. 爲filesystem cache分配更多的內存
  2. 使用SSD硬盤
  3. 使用local storage(不要使用NFS、SMB 等remote filesystem)
  4. 亞馬遜的 彈性塊存儲(Elastic Block Storage)也是極好的,當然,和local storage比起來,它還是要慢點 如果你的搜索是 CPU-bound,買好的CPU吧

3、文檔模型(document modeling) 文檔需要使用合適的類型,從而使得 search-time operations 消耗更少的資源。咋作呢?

答:避免 join操作。具體是指 a.nested 會使得查詢慢 好幾倍 b.parent-child關係 更是使得查詢慢幾百倍 如果 無需join 能解決問題,則查詢速度會快很多

4、預索引 數據 根據“搜索數據最常用的方式”來最優化索引數據的方式

舉個例子:所有文檔都有price字段,大部分query 在 fixed ranges 上運行 range aggregation。你可以把給定範圍的數據 預先索引下。然後,使用 terms aggregation

5、Mappings(能用 keyword 最好了) 數字類型的數據,並不意味着一定非得使用numeric類型的字段。

一般來說,存儲標識符的 字段(書號ISBN、或來自數據庫的 標識一條記錄的 數字),使用keyword更好(integer,long 不好哦)

6、避免運行腳本 一般來說,腳本應該避免。如果他們是絕對需要的,你應該使用painless和expressions引擎。

7、搜索rounded 日期 日期字段上使用now,一般來說不會被緩存。但,rounded date則可以利用上query cache rounded到分鐘等

8、強制merge只讀的index 只讀的index可以從“merge成 一個單獨的 大segment”中收益

9、預熱 全局序數(global ordinals)。全局序數用於在keyword字段上運行terms aggregations。es不知道哪些fields將用於/不用於 term aggregation

因此全局序數在需要時才加載進內存,但可以在mapping type上,定義 eager_global_ordinals==true。這樣,refresh時就會加載 全局序數

10、預熱 filesystem cache 機器重啓時,filesystem cache就被清空。

OS將index的熱點區域(hot regions of the index)加載進filesystem cache是需要花費一段時間的。設置 index.store.preload 可以告知OS 這些文件需要提早加載進入內存

11、使用索引排序來加速連接 索引排序對於以較慢的索引爲代價來加快連接速度非常有用。在索引分類文檔中閱讀更多關於它的信息。

12、使用preference來優化高速緩存利用率 有多個緩存可以幫助提高搜索性能,例如文件系統緩存,請求緩存或查詢緩存。

然而,所有這些緩存都維護在節點級別,這意味着如果連續運行兩次相同的請求,則有一個或多個副本,並使用循環(默認路由算法),那麼這兩個請求將轉到不同的分片副本,阻止節點級別的緩存幫助。

由於搜索應用程序的用戶一個接一個地運行類似的請求是常見的,例如爲了分析索引的較窄的子集,使用標識當前用戶或會話的優選值可以幫助優化高速緩存的使用。

13、副本可能有助於吞吐量,但不會一直存在 除了提高彈性外,副本可以幫助提高吞吐量。例如,如果您有單個分片索引和三個節點,則需要將副本數設置爲2,以便共有3個分片副本,以便使用所有節點。

現在假設你有一個2-shards索引和兩個節點。

在一種情況下,副本的數量是0,這意味着每個節點擁有一個分片。在第二種情況下,副本的數量是1,這意味着每個節點都有兩個碎片。

哪個設置在搜索性能方面表現最好?通常情況下,每個節點的碎片數少的設置將會更好。

原因在於它將可用文件系統緩存的份額提高到了每個碎片,而文件系統緩存可能是Elasticsearch的1號性能因子。

同時,要注意,沒有副本的設置在發生單個節點故障的情況下會出現故障,因此在吞吐量和可用性之間進行權衡。

那麼複製品的數量是多少?如果您有一個具有num_nodes節點的羣集,那麼num_primaries總共是主分片,如果您希望能夠一次處理max_failures節點故障,那麼正確的副本數是max(max_failures,ceil(num_nodes / num_primaries) - 1)。

14、打開自適應副本選擇 當存在多個數據副本時,elasticsearch可以使用一組稱爲自適應副本選擇的標準,根據包含分片的每個副本的節點的響應時間,服務時間和隊列大小來選擇數據的最佳副本。這可以提高查詢吞吐量並減少搜索量大的應用程序的延遲。

4、其他調優

部署調優,業務調優等。

上面的提及一部分,面試者就基本對你之前的實踐或者運維經驗有所評估了。

聊聊:客戶端在和ES集羣連接時,如何選擇特定的節點執行請求的?

客戶端是通過transport 模塊遠程連接一個 elasticsearch 集羣。它並不加入到集羣中,只是簡單的獲得一個或者多個初始化的 transport 地址,並以 輪詢 的方式與這些地址進行通信。

聊聊: Elasticsearch 中,是怎麼根據一個詞找到對應的倒排索引的?

首先我們應該瞭解一下什麼是倒排索引,倒排索引就是通過分詞策略把分詞和文章形成一個關係映射表,這種詞典和映射表的方式就是我們的倒排索引,所以當我們去檢索一個詞語的時候,會根據文檔id去整個索引庫中去查詢到匹配的索引,然後返回給客戶端。

聊聊:Elasticsearch的倒排索引與Mysql正排索引的區別?

一切設計都是爲了提高搜索的性能

倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引。通俗地來講,正向索引是通過key找value,反向索引則是通過value找key。

先來回憶一下我們是怎麼插入一條索引記錄的:

curl -X PUT "localhost:9200/user/_doc/1" -H 'Content-Type: application/json' -d'
{
    "name" : "Jack",
    "gender" : 1,
    "age" : 20
}
'

其實就是直接PUT一個JSON的對象,這個對象有多個字段,在插入這些數據到索引的同時,Elasticsearch還爲這些字段建立索引——倒排索引,因爲Elasticsearch最核心功能是搜索。

那麼,倒排索引是個什麼樣子呢?

img

首先,來搞清楚幾個概念,爲此,舉個例子:

假設有個user索引,它有四個字段:分別是name,gender,age,address。

畫出來的話,大概是下面這個樣子,跟關係型數據庫一樣

img

Term(單詞):一段文本經過分析器分析以後就會輸出一串單詞,這一個一個的就叫做Term(直譯爲:單詞)

Term Dictionary(單詞字典):顧名思義,它裏面維護的是Term,可以理解爲Term的集合

Term Index(單詞索引):爲了更快的找到某個單詞,我們爲單詞建立索引

Posting List(倒排列表):倒排列表記錄了出現過某個單詞的所有文檔的文檔列表及單詞在該文檔中出現的位置信息,每條記錄稱爲一個倒排項(Posting)。根據倒排列表,即可獲知哪些文檔包含某個單詞。(PS:實際的倒排列表中並不只是存了文檔ID這麼簡單,還有一些其它的信息,比如:詞頻(Term出現的次數)、偏移量(offset)等,可以想象成是Python中的元組,或者Java中的對象)

(PS:如果類比現代漢語詞典的話,那麼Term就相當於詞語,Term Dictionary相當於漢語詞典本身,Term Index相當於詞典的目錄索引)

我們知道,每個文檔都有一個ID,如果插入的時候沒有指定的話,Elasticsearch會自動生成一個,因此ID字段就不多說了

上面的例子,Elasticsearch建立的索引大致如下:

name字段:

img

age字段:

img
gender字段:

img

address字段:

img

Elasticsearch分別爲每個字段都建立了一個倒排索引。

比如,在上面“張三”、“北京市”、22 這些都是Term,而[1,3]就是Posting List。Posting list就是一個數組,存儲了所有符合某個Term的文檔ID。

只要知道文檔ID,就能快速找到文檔。可是,要怎樣通過我們給定的關鍵詞快速找到這個Term呢?

當然是建索引了,爲Terms建立索引,最好的就是B-Tree索引(PS:MySQL就是B樹索引最好的例子)。

首先,讓我們來回憶一下MyISAM存儲引擎中的索引是什麼樣的:

img

img

我們查找Term的過程跟在MyISAM中記錄ID的過程大致是一樣的

MyISAM中,索引和數據是分開,通過索引可以找到記錄的地址,進而可以找到這條記錄

倒排索引是區別於正排索引的概念:

  • 正排索引:是以文檔對象的唯一 ID 作爲索引,以文檔內容作爲記錄。
  • 倒排索引:Inverted index,指的是將文檔內容中的單詞作爲索引,將包含該詞的文檔 ID 作爲記錄。

在這裏插入圖片描述

在倒排索引中,通過Term索引可以找到Term在Term Dictionary中的位置,進而找到Posting List,有了倒排列表就可以根據ID找到文檔了

(PS:可以這樣理解,類比MyISAM的話,Term Index相當於索引文件,Term Dictionary相當於數據文件)

(PS:其實,前面我們分了三步,我們可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以這樣理解倒排索引:通過單詞找到對應的倒排列表,根據倒排列表中的倒排項進而可以找到文檔記錄)

爲了更進一步理解,下面從網上摘了兩張圖來具現化這一過程:

imgimg

倒排索引的生成過程

下面通過一個例子來說明下倒排索引的生成過程。

假設目前有以下兩個文檔內容:

蘇州街維亞大廈
桔子酒店蘇州街店

其處理步驟如下:

1、正排索引給每個文檔進行編號,作爲其唯一的標識。

文檔 id content
1 蘇州街維亞大廈
2 桔子酒店蘇州街店

2、生成倒排索引:

  • 首先要對字段的內容進行分詞,分詞就是將一段連續的文本按照語義拆分爲多個單詞,這裏兩個文檔包含的關鍵詞有:蘇州街、維亞大廈…
  • 然後按照單詞來作爲索引,對應的文檔 id 建立一個鏈表,就能構成上述的倒排索引結構。
Word 文檔 id
蘇州街 1,2
維亞大廈 1
維亞 1
桔子 2
酒店 2
大賽 1

有了倒排索引,能快速、靈活地實現各類搜索需求。整個搜索過程中我們不需要做任何文本的模糊匹配。

例如,如果需要在上述兩個文檔中查詢 蘇州街桔子 ,可以通過分詞後 蘇州街 查到 1、2,通過 桔子 查到 2,然後再進行取交取並等操作得到最終結果。

在這裏插入圖片描述

倒排索引的結構

根據倒排索引的概念,我們可以用一個 Map來簡單描述這個結構。這個 Map 的 Key 的即是分詞後的單詞,這裏的單詞稱爲 Term,這一系列的 Term 組成了倒排索引的第一個部分 —— Term Dictionary (索引表,可簡稱爲 Dictionary)。

倒排索引的另一部分爲 Postings List(記錄表),也對應上述 Map 結構的 Value 部分集合。

記錄表由所有的 Term 對應的數據(Postings) 組成,它不僅僅爲文檔 id 信息,可能包含以下信息:

  • 文檔 id(DocId, Document Id),包含單詞的所有文檔唯一 id,用於去正排索引中查詢原始數據。
  • 詞頻(TF,Term Frequency),記錄 Term 在每篇文檔中出現的次數,用於後續相關性算分。
  • 位置(Position),記錄 Term 在每篇文檔中的分詞位置(多個),用於做詞語搜索(Phrase Query)。
  • 偏移(Offset),記錄 Term 在每篇文檔的開始和結束位置,用於高亮顯示等。

在這裏插入圖片描述

Lucene 倒排索引實現

全文搜索引擎在海量數據的情況下是需要存儲大量的文本,所以面臨以下問題:

  • Dictionary 是比較大的(比如我們搜索中的一個字段可能有上千萬個 Term)
  • Postings 可能會佔據大量的存儲空間(一個Term多的有幾百萬個doc)

因此上面說的基於 Map 的實現方式幾乎是不可行的。

在海量數據背景下,倒排索引的實現直接關係到存儲成本以及搜索性能。

爲此,Lucene 引入了多種巧妙的數據結構和算法。其倒排索引實現擁有以下特性:

  • 以較低的存儲成本存儲在磁盤 (索引大小大約爲被索引文本的20-30%)
  • 快速讀寫

下面將根據倒排索引的結構,按 Posting List 和 Terms Dictionary 兩部分來分析 Lucene 中的實現。

Posting List 實現

PostingList 包含文檔 id、詞頻、位置等多個信息,這些數據之間本身是相對獨立的,因此 Lucene 將 Postings List 被拆成三個文件存儲:

  • doc後綴文件:記錄 Postings 的 docId 信息和 Term 的詞頻
  • pay後綴文件:記錄 Payload 信息和偏移量信息
  • pos後綴文件:記錄位置信息

基本所有的查詢都會用 .doc 文件獲取文檔 id,且一般的查詢僅需要用到 .doc 文件就足夠了,只有對於近似查詢等位置相關的查詢則需要用位置相關數據。

三個文件整體實現差不太多,這裏以.doc 文件爲例分析其實現。

.doc 文件存儲的是每個 Term 對應的文檔 Id 和詞頻。每個 Term 都包含一對 TermFreqs 和 SkipData 結構。

其中 TermFreqs 存放 docId 和詞頻信息,SkipData 爲跳錶信息,用於實現 TermFreqs 內部的快速跳轉。

在這裏插入圖片描述

Term Dictionary 實現

Terms Dictionary(索引表)存儲所有的 Term 數據,同時它也是 Term 與 Postings 的關係紐帶,存儲了每個 Term 和其對應的 Postings 文件位置指針。

在這裏插入圖片描述

聊聊:Elasticsearch索引數據多了怎麼辦,如何調優,部署?

答:

面試官:想了解大數據量的運維能力。

解答:索引數據的規劃,應在前期做好規劃,正所謂“設計先行,編碼在後”,這樣纔能有效的避免突如其來的數據激增導致集羣處理能力不足引發的線上客戶檢索或者其他業務受到影響。

如何調優,正如問題1所說,這裏細化一下:

3.1 動態索引層面

基於模板+時間+rollover api滾動創建索引,舉例:設計階段定義:blog索引的模板格式爲:blog_index_時間戳的形式,每天遞增數據。

這樣做的好處:不至於數據量激增導致單個索引數據量非常大,接近於上線2的32次冪-1,索引存儲達到了TB+甚至更大。
一旦單個索引很大,存儲等各種風險也隨之而來,所以要提前考慮+及早避免。

3.2 存儲層面

冷熱數據分離存儲,熱數據(比如最近3天或者一週的數據),其餘爲冷數據。對於冷數據不會再寫入新數據,可以考慮定期 force_merge 加 shrink 壓縮操作,節省存儲空間和檢索效率。

3.3 部署層面

一旦之前沒有規劃,這裏就屬於應急策略。結合ES自身的支持動態擴展的特點,動態新增機器的方式可以緩解集羣壓力,注意:如果之前主節點等規劃合理,不需要重啓集羣也能完成動態新增的。

聊聊:Elasticsearch是如何實現master選舉的?

答:

面試官:想了解ES集羣的底層原理,不再只關注業務層面了。

解答:

前置前提:

1、只有候選主節點(master:true)的節點才能成爲主節點。

2、最小主節點數(min_master_nodes)的目的是防止腦裂。

這個我看了各種網上分析的版本和源碼分析的書籍,雲裏霧裏。

覈對了一下代碼,核心入口爲findMaster,選擇主節點成功返回對應Master,否則返回null。

選舉流程大致描述如下:

第一步:確認候選主節點數達標,elasticsearch.yml設置的值

discovery.zen.minimum_master_nodes;

第二步:比較:先判定是否具備master資格,具備候選主節點資格的優先返回;若兩節點都爲候選主節點,則id小的值會主節點。注意這裏的id爲string類型。

聊聊:Elasticsearch 的 master 選舉流程?

  • Elasticsearch 的選主是 ZenDiscovery 模塊負責的,主要包含 Ping(節點之間通過這個 RPC 來發現彼此)和 Unicast(單播模塊包含一個主機列表以控制哪些節點需要 ping 通)這兩部分
  • 對所有可以成爲 master 的節點(node.master: true)根據 nodeId 字典排序,每次選舉每個節點都把自己所知道節點排一次序,然後選出第一個(第 0 位)節點,暫且認爲它是 master 節點
  • 如果對某個節點的投票數達到一定的值(可以成爲 master 節點數 n/2+1)並且該節點自己也選舉自己,那這個節點就是 master。否則重新選舉一直到滿足上述條件。
  • master 節點的職責主要包括集羣、節點和索引的管理,不負責文檔級別的管理data 節點可以關閉 http功能

聊聊:詳細描述一下Elasticsearch索引文檔的過程。

面試官:想了解ES的底層原理,不再只關注業務層面了。

解答:

首先客戶端向集羣發出索引文檔的請求,它會選擇任何一個節點

這個節點當接收到請求後會根據路由算法找到應該放的那個主分片的位置,從而索引數據,請添加圖片描述

之後爲了保證數據的完整性,它會將它的副本數據進行同步,同步完成後客戶端就可以進行訪問了。

細節方面:

請添加圖片描述

用戶的索引請求發過來之後,首先協調結點默認使用文檔ID參與哈希計算(也支持通過routing),

shard = hash(document_id) % (num_of_primary_shards)

分片位置索引 = 將文檔ID或路由ID進行哈希計算後的值 % 所有分片總數

隨後會在內存(memory)中建立一個索引(Index),這個Index會在內存中形成一個分段對象(Segment),

爲了防止數據出現問題,會同時在索引數據之後寫入到日誌(Translog)當中,

在此過程中,每隔1秒鐘,會向Segment會將數據刷新到系統文件緩存區(OS Cache),以方便接收用戶的查詢,

因爲如果讓用戶查詢直接訪問內存或磁盤,會使速度變慢。

當過了30分鐘或者Translog中的數據超過了512M,Os Cache中的Segment會將數據刷寫(flush)到磁盤當中,刷寫後內存中的緩衝將被清除。

此時一旦刷寫的數據比較多了的話(磁盤中有多個Segment),磁盤就會將這些分段進行合併。

聊聊:詳細描述一下Elasticsearch索引文檔的過程。

答:

協調節點默認使用文檔ID參與計算(也支持通過routing),以便爲路由提供合適的分片。

shard = hash(document_id) % (num_of_primary_shards)

1、當分片所在的節點接收到來自協調節點的請求後,會將請求寫入到Memory Buffer,然後定時(默認是每隔1秒)寫入到 Filesystem Cache,這個從MomeryBuffer到Filesystem Cache的過程就叫做refresh;

2、當然在某些情況下,存在Momery Buffer和Filesystem Cache的數據可能會丟失,ES是通過translog的機制來保證數據的可靠性的。其實現機制是接收到請求後,同時也會寫入到translog中,當 Filesystem cache中的數據寫入到磁盤中時,纔會清除掉,這個過程叫做flush;

3、在 flush 過程中,內存中的緩衝將被清除,內容被寫入一個新段,段的fsync將創建一個新的提交點,並將內容刷新到磁盤,舊的translog將被刪除並開始一個新的translog。

4、flush觸發的時機是定時觸發(默認30分鐘)或者translog變得太大(默認爲512M)時
img
補充:關於Lucene 的 Segement:

1、Lucene索引是由多個段組成,段本身是一個功能齊全的倒排索引。

2、段是不可變的,允許Lucene將新的文檔增量地添加到索引中,而不用從頭重建索引。

3、對於每一個搜索請求而言,索引中的所有段都會被搜索,並且每個段會消耗CPU的時鐘周、文件句柄和內存。這意味着段的數量越多,搜索性能會越低。

4、爲了解決這個問題,Elasticsearch會合並小段到一個較大的段,提交新的合併段到磁盤,並刪除那些舊的小段。

聊聊:詳細描述一下Elasticsearch搜索的過程?

面試官:想了解ES搜索的底層原理,不再只關注業務層面了。

解答:

請添加圖片描述

  • 搜索被執行成一個兩階段過程,我們稱之爲 Query Then Fetch(查詢後取回);
  • 在初始查詢階段時,查詢會廣播到索引中每一個分片拷貝(主分片或者副本分片)。 每個分片在本
    地執行搜索並構建一個匹配文檔的大小爲 from + size 的優先隊列。PS:在搜索的時候是會查詢
    Filesystem Cache 的,但是有部分數據還在 Memory Buffer,所以搜索是近實時的
  • 每個分片返回各自優先隊列中 所有文檔的 ID 和排序值協調節點,它合併這些值到自己的優先隊
    列中來產生一個全局排序後的結果列表
  • 接下來就是取回階段,協調節點辨別出哪些文檔需要被取回,並向相關的分片提交多個 GET 請求。每
    個分片加載並豐富文檔,如果有需要的話,接着返回文檔給協調節點。一旦所有的文檔都被取回了,
    協調節點返回結果給客戶端。
  • Query Then Fetch 的搜索類型在文檔相關性打分的時候參考的是本分片的數據,這樣在文檔數量較少
    的時候可能不夠準確,DFS Query Then Fetch 增加了一個預查詢的處理,詢問 Term 和 Document
    frequency,這個評分更準確,但是性能會變差。

聊聊:詳細描述一下Elasticsearch搜索的過程。

答:

1、搜索被執行成一個兩階段過程,我們稱之爲Query Then Fetch;

2、在初始查詢階段時,查詢會廣播到索引中每一個分片拷貝(主分片或者副本分片)。 每個分片在本地執行搜索並構建一個匹配文檔的大小爲from + size的優先隊列。

PS:在搜索的時候是會查詢Filesystem Cache的,但是有部分數據還在MemoryBuffer,所以搜索是近實時的。

3、每個分片返回各自優先隊列中 所有文檔的ID和排序值 給協調節點,它合併這些值到自己的優先隊列中來產生一個全局排序後的結果列表。

4、接下來就是 取回階段,協調節點辨別出哪些文檔需要被取回並向相關的分片提交多個GET請求。每個分片加載並 豐富 文檔,如果有需要的話,接着返回文檔給協調節點。一旦所有的文檔都被取回了,協調節點返回結果給客戶端。

5、補充:Query Then Fetch的搜索類型在文檔相關性打分的時候參考的是本分片的數據,這樣在文檔數量較少的時候可能不夠準確,DFS Query Then Fetch增加了一個預查詢的處理,詢問Term 和 Document frequency,這個評分更準確,但是性能會變差。

img

聊聊:詳細描述一下Elasticsearch更新和刪除文檔的過程。

答:

1、刪除和更新也都是寫操作,但是Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動以展示其變更;

2、磁盤上的每個段都有一個相應的del文件。當刪除請求發送後,文檔並沒有真的被刪除,而是在del文件中被標記爲刪除。該文檔依然能匹配查詢,但是會在結果中被過濾掉。當段合併時,在del文件中被標記爲刪除的文檔將不會被寫入新段。

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

聊聊:Elasticsearch在部署時,對Linux的設置有哪些優化方法?

面試官:想了解對ES集羣的運維能力。

解答:

1、關閉緩存swap

2、堆內存設置爲:Min(節點內存/2, 32GB)

3、設置最大文件句柄數

4、線程池+隊列大小根據業務需要做調整

5、磁盤存儲raid方式——存儲有條件使用RAID10,增加單節點性能以及避免單節點存儲故障

聊聊:lucence內部結構是什麼?

面試官:想了解你的知識面的廣度和深度。

解答:
img
Lucene是有索引和搜索的兩個過程,包含索引創建,索引,搜索三個要點。可以基於這個脈絡展開一些。

最近面試一些公司,被問到的關於Elasticsearch和搜索引擎相關的問題,以及自己總結的回答。

聊聊:Elasticsearch是如何實現Master選舉的?

1、Elasticsearch的選主是ZenDiscovery 模塊負責的,主要包含Ping(節點之間通過這個RPC來發現彼此)和Unicast(單播模塊包含一個主機列表以控制哪些節點需要ping通)這兩部分;

2、對所有可以成爲master的節點(node.master:true)根據nodeId字典排序,每次選舉每個節點都把自己所知道節點排一次序,然後選出第一個(第0位)節點,暫且認爲它是master節點。

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

4、補充:master節點的職責主要包括集羣、節點和索引的管理,不負責文檔級別的管理;data節點可以關閉http 功能*。

聊聊:Elasticsearch中的節點(比如共20個),其中的10個選了一個master,另外10個選了另一個master,怎麼辦?

1、當集羣master候選數量不小於3個時,可以通過設置最少投票通過數量(discovery.zen.minimum_master_nodes)超過所有候選節點一半以上來解決腦裂問題;

2、當候選數量爲兩個時,只能修改爲唯一的一個master候選,其他作爲data節點,避免腦裂問題

聊聊:客戶端在和集羣連接時,如何選擇特定的節點執行請求的?

答:

1、TransportClient利用transport模塊遠程連接一個elasticsearch集羣。它並不加入到集羣中,只是簡單的獲得一個或者多個初始化的transport地址,並以 輪詢 的方式與這些地址進行通信。

聊聊:Elasticsearch在部署時,對Linux的設置有哪些優化方法?

答:

1、64GB內存的機器是非常理想的, 但是32GB和16GB機器也是很常見的。少於8GB會適得其反。

2、如果你要在更快的CPUs和更多的核心之間選擇,選擇更多的核心更好。多個內核提供的額外併發遠勝過稍微快一點點的時鐘頻率。

3、如果你負擔得起SSD,它將遠遠超出任何旋轉介質。 基於SSD的節點,查詢和索引性能都有提升。如果你負擔得起,SSD 是一個好的選擇。

4、即使數據中心們近在咫尺,也要避免集羣跨越多個數據中心。絕對要避免集羣跨越大的地理距離。

5、請確保運行你應用程序的JVM和服務器的JVM是完全一樣的。 在Elasticsearch的幾個地方,使用Java的本地序列化。

6、通過設置 gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time 可以在集羣重啓的時候避免過多的分片交換,這可能會讓數據恢復從數個小時縮短爲幾秒鐘。

7、Elasticsearch 默認被配置爲使用單播發現,以防止節點無意中加入集羣。只有在同一臺機器上運行的節點纔會自動組成集羣。最好使用單播代替組播。

8、不要隨意修改垃圾回收器(CMS)和各個線程池的大小。

9、把你的內存的(少於)一半給Lucene(但不要超過32GB!),通過ES_HEAP_SIZE 環境變量設置。

10、內存交換到磁盤對服務器性能來說是致命的。如果內存交換到磁盤上,一個100微秒的操作可能變成10毫秒。 再想想那麼多10微秒的操作時延累加起來。 不難看出swapping對於性能是多麼可怕。

11、Lucene使用了大量的文件。同時,Elasticsearch在節點和HTTP客戶端之間進行通信也使用了大量的套接字。 所有這一切都需要足夠的文件描述符。你應該增加你的文件描述符,設置一個很大的值,如64,000。

補充:索引階段性能提升方法

1、使用批量請求並調整其大小:每次批量數據5–15 MB大是個不錯的起始點。

2、存儲:使用 SSD

3、段和合並:Elasticsearch 默認值是20MB/s,對機械磁盤應該是個不錯的設置。如果你用的是SSD,可以考慮提高到 100–200 MB/s。

如果你在做批量導入,完全不在意搜索,你可以徹底關掉合併限流。另外還可以增加index.translog.flush_threshold_size設置,從默認的512MB到更大一些的值,比如1GB,這可以在一次清空觸發的時候在事務日誌裏積累出更大的段。

4、如果你的搜索結果不需要近實時的準確度,考慮把每個索引的index.refresh_interval 改到30s。

5、如果你在做大批量導入,考慮通過設置 index.number_of_replicas: 0 關閉副本。

聊聊:對於GC方面,在使用Elasticsearch時要注意什麼?

答:

1、官方資料:https://elasticsearch.cn/article/32

2、倒排詞典的索引需要常駐內存,無法GC,需要監控data node 上segmentmemory增長趨勢。

3、各類緩存,field cache, filter cache, indexing cache, bulk queue 等等,要設置合理的大小,並且要應該根據最壞的情況來看heap是否夠用,也就是各類緩存全部佔滿的時候,還有heap空間可以分配給其他任務嗎?避免採用clear cache等“自欺欺人”的方式來釋放內存。

4、避免返回大量結果集的搜索與聚合。確實需要大量拉取數據的場景,可以採用scan & scroll api來實現。

5、cluster stats駐留內存並無法水平擴展,超大規模集羣可以考慮分拆成多個集羣通過tribe node連接。

6、想知道heap夠不夠,必須結合實際應用場景,並對集羣的heap使用情況做持續的監控。

聊聊:Elasticsearch對於大數據量(上億量級)的聚合如何實現?

答:

Elasticsearch提供的首個近似聚合是cardinality度量。它提供一個字段的基數,即該字段的distinct或者unique值的數目。

它是基於HLL算法的。HLL會先對我們的輸入作哈希運算,然後根據哈希運算的結果中的bits做概率估算從而得到基數。

其特點是:可配置的精度,用來控制內存的使用(更精確 = 更多內存);

小的數據集精度是非常高的;我們可以通過配置參數,來設置去重需要的固定內存使用量。無論數千還是數十億的唯一值,內存使用量只與你配置的精確度相關。

聊聊:在併發情況下,Elasticsearch如果保證讀寫一致?

答:

1、可以通過版本號使用樂觀併發控制,以確保新版本不會被舊版本覆蓋,由應用層來處理具體的衝突;

2、另外對於寫操作,一致性級別支持quorum/one/all,默認爲quorum,即只有當大多數分片可用時才允許寫操作。但即使大多數可用,也可能存在因爲網絡等原因導致寫入副本失敗,這樣該副本被認爲故障,分片將會在一個不同的節點上重建。

3、對於讀操作,可以設置replication爲sync(默認),這使得操作在主分片和副本分片都完成後纔會返回;如果設置replication 爲async時,也可以通過設置搜索請求參數_preference 爲 primary來查詢主分片,確保文檔是最新版本。

聊聊:併發情況下,Elasticsearch 如果保證讀寫一致?

  • 可以通過版本號使用樂觀鎖併發控制,以確保新版本不會被舊版本覆蓋,由應用層來處理具體的衝突;
  • 對於寫操作:一致性級別支持 quorum/one/all,默認爲 quorum。
    • quorum:即只有當大多數(一半以上)分片可用時才允許寫操作。但即使大多數可用,也可能存在因爲網絡等原因導致寫入副本失敗,這樣該副本被認爲故障,分片將會在一個不同的節點上重建。
    • one:即只要主分片數據保存成功,那麼客戶端就可以進行查詢操作了。
    • all:是最高的一致性級別,要求所有分片的數據要全部保存成功,纔可以繼續進行。
  • 對於讀操作:可以設置 replication 爲 sync(默認爲同步),這使得操作在主分片和副本分片都完成後纔會返回;設置 replication 爲 async(異步)時,也可以通過設置搜索請求參數_preference 爲 primary 來查詢主分片,確保文檔是最新版本。

聊聊:Elasticsearch 中的節點(比如共 20 個),其中的 10 個選了一個master,另外 10 個選了另一個 master,怎麼辦?

1、當集羣master候選數量不小於3個時,可以通過設置最少投票通過數量(discovery.zen.minimum_master_nodes)超過所有候選節點一半以上來解決腦裂問題;

2、當候選數量爲兩個時,只能修改爲唯一的一個master候選,其他作爲data節點,避免腦裂問題。

聊聊:Elasticsearch 集羣腦裂問題?有哪些解決方法?

“腦裂”問題可能的成因:(有兩個master)

  • 網絡問題:集羣間的網絡延遲導致一些節點訪問不到 master,認爲 master 掛掉了從而選舉出新的master,並對 master 上的分片和副本標紅,分配新的主分片
  • 節點負載:主節點的角色既爲 master 又爲 data,訪問量較大時可能會導致 ES 停止響應造成大面積延遲,此時其他節點得不到主節點的響應認爲主節點掛掉了,會重新選取主節點。
  • 內存回收:data 節點上的 ES 進程佔用的內存較大,引發 JVM 的大規模內存回收,造成 ES 進程失去響應

腦裂問題解決方案

  • 減少誤判:discovery.zen.ping_timeout 節點狀態的響應時間(超過這個時間就會重新選舉master),默認爲 3s,可以適當調大,如果 master在該響應時間的範圍內沒有做出響應應答,判斷該節點已經掛掉了。調大參數(如 6s,discovery.zen.ping_timeout:6),可適當減少誤判。
  • 選舉觸發:discovery.zen.minimum_master_nodes:1

該參數是用於控制選舉行爲發生的最小集羣主節點數量。當備選主節點的個數大於等於該參數的值,
且備選主節點中有該參數個節點認爲主節點掛了,進行選舉。官方建議爲(n/2)+1,n 爲主節點個數
(即有資格成爲主節點的節點個數)

  • 角色分離:即 master 節點與 data 節點分離,限制角色
    主節點配置爲:node.master: true node.data: false
    從節點配置爲:node.master: false node.data: true

聊聊:如何監控Elasticsearch集羣狀態?

答:

Marvel讓你可以很簡單的通過Kibana監控Elasticsearch。你可以實時查看你的集羣健康狀態和性能,也可以分析過去的集羣、索引和節點指標。

聊聊:介紹下你們電商搜索的整體技術架構。

答:
img

聊聊:字典樹的大致思想和性質?

很多數據結構均能完成字典功能,總結如下。

數據結構 優缺點
排序列表Array/List 使用二分法查找,不平衡
HashMap/TreeMap 性能高,內存消耗大,幾乎是原始數據的三倍
Skip List 跳躍表,可快速查找詞語,在lucene、redis、Hbase等均有實現。相對於TreeMap等結構,特別適合高併發場景
Trie 適合英文詞典,如果系統中存在大量字符串且這些字符串基本沒有公共前綴,則相應的trie樹將非常消耗內存
Double Array Trie 適合做中文詞典,內存佔用小,很多分詞工具均採用此種算法
Ternary Search Tree 三叉樹,每一個node有3個節點,兼具省空間和查詢快的優點
Finite State Transducers (FST) 一種有限狀態轉移機,Lucene 4有開源實現,並大量使用

Trie的核心思想是空間換時間,利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的。

它有3個基本性質:

1、根節點不包含字符,除根節點外每一個節點都只包含一個字符。

2、從根節點到某一節點,路徑上經過的字符連接起來,爲該節點對應的字符串。

3、每個節點的所有子節點包含的字符都不相同。

img

1、可以看到,trie樹每一層的節點數是26^i 級別的。所以爲了節省空間,我們還可以用動態鏈表,或者用數組來模擬動態。而空間的花費,不會超過單詞數×單詞長度。

2、實現:對每個結點開一個字母集大小的數組,每個結點掛一個鏈表,使用左兒子右兄弟表示法記錄這棵樹;

3、對於中文的字典樹,每個節點的子節點用一個哈希表存儲,這樣就不用浪費太大的空間,而且查詢速度上可以保留哈希的複雜度O(1)

聊聊:是否瞭解字典樹?

常用字典數據結構

  • 排序列表Array/List:使用二分法查找,不平衡

  • HashMap/TreeMap:性能高,內存消耗大,幾乎是原始數據的三倍

  • Skip List 跳躍表:可快速查找詞語,在lucene、redis、Hbase等均有實現。相對於TreeMap等結構,特別

    適合高併發場景(Skip List介紹)

  • Trie:適合英文詞典,如果系統中存在大量字符串且這些字符串基本沒有公共前級,則相應的trie樹將非常消耗內存(數據結構之trie樹)

  • Double Array Trie:適合做中文詞典,內存佔用小。很多分詞工具均採用此種算法(深入雙數組Trie)

  • Ternary Search Tree 三叉樹:每一個node有3個節點,兼具省空間和查詢快的優點(Ternary Search Tree)

  • Finite State Transducers(FST) :一種有限狀態轉移機,Lucene4有開源實現,並大量使用

字典樹又稱單詞查找樹,Trie 樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用於統計,排序和保存大量的字符串(但不僅限於字符串),所以經常被搜索引擎系統用於文本詞頻統計。

它的優點是:利用字符串的公共前綴來減少查詢時間,最大限度地減少無謂的字符串比較,查詢效率比哈希樹高(空間換時間)。

Trie 的核心思想是空間換時間,利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的。

它有 3 個基本性質:

  • 根節點不包含字符,除根節點外每一個節點都只包含一個字符。
  • 從根節點到某一節點,路徑上經過的字符連接起來,爲該節點對應的字符串。
  • 每個節點的所有子節點包含的字符都不相同。

對於中文的字典樹,每個節點的子節點用一個哈希表存儲,這樣就不用浪費太大的空間,而且查詢速度上可以保留哈希的複雜度 O(1)

聊聊: FST原理

Finite State Transducers(FST) :一種有限狀態轉移機,Lucene4有開源實現,並大量使用.

lucene從4開始大量使用的數據結構是FST(Finite State Transducer)。

FST有兩個優點:

1)空間佔用小。通過對詞典中單詞前綴和後綴的重複利用,壓縮了存儲空間;

2)查詢速度快。O(len(str))的查詢時間複雜度。

下面簡單描述下FST的構造過程。

我們對“cat”、 “deep”、 “do”、 “dog” 、“dogs”這5個單詞進行插入構建FST(注:必須已排序)。

1)插入“cat”

插入cat,每個字母形成一條邊,其中t邊指向終點。

img

2)插入“deep”

與前一個單詞“cat”進行最大前綴匹配,發現沒有匹配則直接插入,P邊指向終點。

img

3)插入“do”

與前一個單詞“deep”進行最大前綴匹配,發現是d,則在d邊後增加新邊o,o邊指向終點。

img

4)插入“dog”

與前一個單詞“do”進行最大前綴匹配,發現是do,則在o邊後增加新邊g,g邊指向終點。

img

5)插入“dogs”

與前一個單詞“dog”進行最大前綴匹配,發現是dog,則在g後增加新邊s,s邊指向終點。

img

最終我們得到了如上一個有向無環圖。利用該結構可以很方便的進行查詢,如給定一個term “dog”,我們可以通過上述結構很方便的查詢存不存在,甚至我們在構建過程中可以將單詞與某一數字、單詞進行關聯,從而實現key-value的映射。

聊聊:拼寫糾錯是如何實現的?

答:

1、拼寫糾錯是基於編輯距離來實現;編輯距離是一種標準的方法,它用來表示經過插入、刪除和替換操作從一個字符串轉換到另外一個字符串的最小操作步數;

2、編輯距離的計算過程:比如要計算 batyu 和 beauty 的編輯距離,先創建一個7×8 的表(batyu長度爲5,coffee長度爲6,各加2),接着,在如下位置填入黑色數字。其他格的計算過程是取以下三個值的最小值:

如果最上方的字符等於最左方的字符,則爲左上方的數字。否則爲左上方的數字+1。

(對於3,3 來說爲 0)

左方數字+1(對於3,3格來說爲2)

上方數字+1(對於3,3格來說爲2)

最終取右下角的值即爲編輯距離的值3。
img

對於拼寫糾錯,我們考慮構造一個度量空間(Metric Space),該空間內任何關係滿足以下三條基本條件:

d(x,y) = 0 – 假如 x 與 y 的距離爲 0,則 x=y

d(x,y) = d(y,x) – x 到 y 的距離等同於 y 到 x 的距離

d(x,y) + d(y,z) >= d(x,z) – 三角不等式

1、根據三角不等式,則滿足與query距離在n範圍內的另一個字符轉B,其與A的距離最大爲d+n,最小爲d-n。

2、BK樹的構造就過程如下:

每個節點有任意個子節點,每條邊有個值表示編輯距離。所有子節點到父節點的邊上標註n表示編輯距離恰好爲n。
比如,我們有棵樹父節點是”book”和兩個子節點”cake”和”books”,”book”到”books”的邊標號1,”book”到”cake”的邊上標號4。

從字典裏構造好樹後,無論何時你想插入新單詞時,計算該單詞與根節點的編輯距離,並且查找數值爲d(neweord, root)的邊。遞歸得與各子節點進行比較,直到沒有子節點,你就可以創建新的子節點並將新單詞保存在那。

比如,插入”boo”到剛纔上述例子的樹中,我們先檢查根節點,查找 d(“book”, “boo”) =1的邊,然後檢查標號爲1的邊的子節點,得到單詞”books”。我們再計算距離 d(“books”, “boo”)=2,則將新單詞插在”books”之後,邊標號爲2。

3、查詢相似詞如下:計算單詞與根節點的編輯距離d,然後遞歸查找每個子節點標號爲d-n到d+n(包含)的邊。假如被檢查的節點與搜索單詞的距離d小於n,則返回該節點並繼續查詢。

比如輸入cape且最大容忍距離爲1,則先計算和根的編輯距離 d(“book”, “cape”)=4,然後接着找和根節點之間編輯距離爲3到5 的,這個就找到了cake這個節點,計算d(“cake”,“cape”)=1,滿足條件所以返回cake,然後再找和cake節點編輯距離是0到2 的,分別找到cape和cart節點,這樣就得到cape這個滿足條件的結果。
img

參考文獻:

https://www.infoq.cn/article/database-timestamp-02?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk

https://www.cnblogs.com/sha0830/p/8000242.html

https://blog.csdn.net/andy_wcl/article/details/81631609

https://cloud.tencent.com/developer/news/329497

https://blog.csdn.net/qq_39144436/article/details/124509108

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