Elasticsearch 面試專題

文章目錄

1、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。
  3. 查詢調優
    1 、 禁 用wildcard;
    2 、 禁 用 批 量 terms( 成 百 上 千 的 場 景 );
    3、充分利用倒排索引機制,能 keyword 類型儘量 keyword;
    4、數據量大時候,可以先基於時間敲定索引再檢索;
    5、設置合理的路由機制。
  4. 其他調優
    部署調優,業務調優等。
    上面的提及一部分,面試者就基本對你之前的實踐或者運維經驗有所評估了。

2、elasticsearch 的倒排索引是什麼

面試官:想了解你對基礎概念的認知。解答:通俗解釋一下就可以。
傳統的我們的檢索是通過文章,逐個遍歷找到對應關鍵詞的位置。
而倒排索引,是通過分詞策略,形成了詞和文章的映射關係表,這種詞典+映射表即爲倒排索引。有了倒排索引,就能實現 o(1)時間複雜度的效率檢索文章了,極大的提高了檢索效率
在這裏插入圖片描述
學術的解答方式:
倒排索引,相反於一篇文章包含了哪些詞,它從詞出發,記載了這個詞在哪些文檔中出現過,由兩部分組成——詞典和倒排表。加分項:倒排索引的底層實現是基於:FST(Finite State Transducer)數據結構。
lucene 從 4+版本後開始大量使用的數據結構是 FST。FST 有兩個優點:

  1. 空間佔用小。通過對詞典中單詞前綴和後綴的重複利用,壓縮了存儲空間;
  2. 查詢速度快。O(len(str))的查詢時間複雜度。

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

面試官:想了解大數據量的運維能力。
解答:索引數據的規劃,應在前期做好規劃,正所謂“設計先行,編碼在後”,這樣纔能有效的避免突如其來的數據激增導致集羣處理能力不足引發的線上客戶檢索或者其他業務受到影響。
如何調優,正如問題 1 所說,這裏細化一下:

  1. 動態索引層面
    基於模板+時間+rollover api 滾動創建索引,舉例:設計階段定義:blog 索引的模板格式爲:blog_index_時間戳的形式,每天遞增數據。
    這樣做的好處:不至於數據量激增導致單個索引數據量非常大,接近於上線 2 的32 次冪-1,索引存儲達到了 TB+甚至更大。一旦單個索引很大,存儲等各種風險也隨之而來,所以要提前考慮+及早避免。
  2. 存儲層面
    冷熱數據分離存儲,熱數據(比如最近 3 天或者一週的數據),其餘爲冷數據。對於冷數據不會再寫入新數據,可以考慮定期 force_merge 加 shrink 壓縮操作,節省存儲空間和檢索效率。
  3. 部署層面
    一旦之前沒有規劃,這裏就屬於應急策略。結合 ES 自身的支持動態擴展的特點,動態新增機器的方式可以緩解集羣壓力,注意:如果之前主節點等規劃合理,不需要重啓集羣也能完成動態新增的。

4、elasticsearch 是如何實現 master 選舉的

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

  1. 只有候選主節點(master:true)的節點才能成爲主節點。
  2. 最小主節點數(min_master_nodes)的目的是防止腦裂。
    這個我看了各種網上分析的版本和源碼分析的書籍,雲裏霧裏。
    覈對了一下代碼,核心入口爲 findMaster,選擇主節點成功返回對應 Master,否則返回 null。選舉流程大致描述如下: 第一步:確認候選主節點數達標,elasticsearch.yml 設置的值
    discovery.zen.minimum_master_nodes;

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

  1. GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
  2. ip port heapPercent heapMax id name

5、詳細描述一下 Elasticsearch 索引文檔的過程

面試官:想了解 ES 的底層原理,不再只關注業務層面了。解答:
這裏的索引文檔應該理解爲文檔寫入 ES,創建索引的過程。
文檔寫入包含:單文檔寫入和批量 bulk 寫入,這裏只解釋一下:單文檔寫入流程。記住官方文檔中的這個圖。
在這裏插入圖片描述
第一步:客戶寫集羣某節點寫入數據,發送請求。(如果沒有指定路由/協調節點,請求的節點扮演路由節點的角色。)
第二步:節點 1 接受到請求後,使用文檔_id 來確定文檔屬於分片 0。請求會被轉到另外的節點,假定節點 3。因此分片 0 的主分片分配到節點 3 上。
第三步:節點 3 在主分片上執行寫操作,如果成功,則將請求並行轉發到節點 1和節點 2 的副本分片上,等待結果返回。所有的副本分片都報告成功,節點 3 將向協調節點(節點 1)報告成功,節點 1 向請求客戶端報告寫入成功。
如果面試官再問:第二步中的文檔獲取分片的過程?
回答:藉助路由算法獲取,路由算法就是根據路由和文檔 id 計算目標的分片 id 的過程。

1shard = hash(_routing) % (num_of_primary_shards)

6、詳細描述一下 Elasticsearch 搜索的過程?

面試官:想了解 ES 搜索的底層原理,不再只關注業務層面了。解答:
搜索拆解爲“query then fetch” 兩個階段。
query 階段的目的:定位到位置,但不取。步驟拆解如下:

  1. 假設一個索引數據有 5 主+1 副本 共 10 分片,一次請求會命中(主或者副本分片中)的一個。
  2. 每個分片在本地進行查詢,結果返回到本地有序的優先隊列中。
  3. 第 2步驟的結果發送到協調節點,協調節點產生一個全局的排序列表。fetch 階段的目的:取數據。路由節點獲取所有文檔,返回給客戶端。

7、Elasticsearch 在部署時,對 Linux 的設置有哪些優化方法

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

  1. 關閉緩存 swap;
  2. 堆內存設置爲:Min(節點內存/2, 32GB);
  3. 設置最大文件句柄數;
  4. 線程池+隊列大小根據業務需要做調整;
  5. 磁盤存儲 raid 方式——存儲有條件使用 RAID10,增加單節點性能以及避免單節點存儲故障。

8、lucence 內部結構是什麼?

面試官:想了解你的知識面的廣度和深度。解答:
在這裏插入圖片描述

9、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 功能*。

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

  1. 當集羣 master 候選數量不小於 3 個時,可以通過設置最少投票通過數量(discovery.zen.minimum_master_nodes)超過所有候選節點一半以上來解決腦裂問題;
  2. 當候選數量爲兩個時,只能修改爲唯一的一個 master 候選,其他作爲 data節點,避免腦裂問題

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

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

12、詳細描述一下 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)時
    在這裏插入圖片描述
    補充:關於 Lucene 的 Segement:
  5. Lucene 索引是由多個段組成,段本身是一個功能齊全的倒排索引。
  6. 段是不可變的,允許 Lucene 將新的文檔增量地添加到索引中,而不用從頭重建索引。
  7. 對於每一個搜索請求而言,索引中的所有段都會被搜索,並且每個段會消耗CPU 的時鐘周、文件句柄和內存。這意味着段的數量越多,搜索性能會越低。
  8. 爲了解決這個問題,Elasticsearch 會合並小段到一個較大的段,提交新的合併段到磁盤,並刪除那些舊的小段。

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

  1. 刪除和更新也都是寫操作,但是 Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動以展示其變更;
  2. 磁盤上的每個段都有一個相應的.del 文件。當刪除請求發送後,文檔並沒有真的被刪除,而是在.del 文件中被標記爲刪除。該文檔依然能匹配查詢,但是會在結果中被過濾掉。當段合併時,在.del 文件中被標記爲刪除的文檔將不會被寫入新段。
  3. 在新的文檔被創建時,Elasticsearch 會爲該文檔指定一個版本號,當執行更新時,舊版本的文檔在.del 文件中被標記爲刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,但是會在結果中被過濾掉。

14、詳細描述一下 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,這個評分更準確,但是性能會變差。

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

SEE:

  • Lucene 的索引文件格式(1)
  • Lucene 的索引文件格式(2)

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

  1. 64 GB 內存的機器是非常理想的, 但是 32 GB 和 16 GB 機器也是很常見的。少於 8 GB 會適得其反。
  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 默認被配置爲使用單播發現,以防止節點無意中加入集羣。只有在同一臺機器上運行的節點纔會自動組成集羣。最好使用單播代替組播。
  7. 不要隨意修改垃圾回收器(CMS)和各個線程池的大小。
  8. 把你的內存的(少於)一半給 Lucene(但不要超過 32 GB!),通過ES_HEAP_SIZE 環境變量設置。
  9. 內存交換到磁盤對服務器性能來說是致命的。如果內存交換到磁盤上,一個100 微秒的操作可能變成 10 毫秒。 再想想那麼多 10 微秒的操作時延累加起來。 不難看出
    swapping 對於性能是多麼可怕。
  10. Lucene 使用了大量的文件。同時,Elasticsearch 在節點和 HTTP 客戶端之間進行通信也使用了大量的套接字。 所有這一切都需要足夠的文件描述符。你應該增加你的文件描述符,設置一個很大的值,如 64,000。

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

  1. 使用批量請求並調整其大小:每次批量數據 5–15 MB 大是個不錯的起始點。
  2. 存儲:使用 SSD
  3. 段和合並:Elasticsearch 默認值是 20 MB/s,對機械磁盤應該是個不錯的設置。如果你用的是 SSD,可以考慮提高到 100–200 MB/s。如果你在做批量導入,完全不在意搜索,你可以徹底關掉合併限流。另外還可以增加 index.translog.flush_threshold_size 設置,從默認的 512 MB 到更大一些的值,比如 1 GB,這可以在一次清空觸發的時候在事務日誌裏積累出更大的段。
  4. 如果你的搜索結果不需要近實時的準確度,考慮把每個索引的index.refresh_interval 改到 30s。
  5. 如果你在做大批量導入,考慮通過設置 index.number_of_replicas: 0 關閉副本。

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

  1. SEE:https://elasticsearch.cn/article/32
  2. 倒排詞典的索引需要常駐內存,無法 GC,需要監控datanode上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 使用情況做持續的監控。

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

Elasticsearch 提供的首個近似聚合是 cardinality 度量。它提供一個字段的基數,即該字段的 distinct 或者 unique 值的數目。它是基於 HLL 算法的。HLL 會先對我們的輸入作哈希運算,然後根據哈希運算的結果中的 bits 做概率估算從而得到基數。其特點是:可配置的精度,用來控制內存的使用(更精確 = 更多內存);
小的數據集精度是非常高的;我們可以通過配置參數,來設置去重需要的固定內存使用量。無論數千還是數十億的唯一值,內存使用量只與你配置的精確度相關。

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

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

20、如何監控 Elasticsearch 集羣狀態?

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

21、介紹下你們電商搜索的整體技術架構

在這裏插入圖片描述

22、介紹一下你們的個性化搜索方案?

SEE 基於 word2vec 和 Elasticsearch 實現個性化搜索

23、是否瞭解字典樹?

常用字典數據結構如下所示
在這裏插入圖片描述
Trie 的核心思想是空間換時間,利用字符串的公共前綴來降低查詢時間的開銷以達到提高效率的目的。它有 3 個基本性質:

  1. 根節點不包含字符,除根節點外每一個節點都只包含一個字符。
  2. 從根節點到某一節點,路徑上經過的字符連接起來,爲該節點對應的字符串。
  3. 每個節點的所有子節點包含的字符都不相同。
    在這裏插入圖片描述
  4. 可以看到,trie 樹每一層的節點數是 26^i 級別的。所以爲了節省空間,我們還可以用動態鏈表,或者用數組來模擬動態。而空間的花費,不會超過單詞數×單詞長度。
  5. 實現:對每個結點開一個字母集大小的數組,每個結點掛一個鏈表,使用左兒子右兄弟表示法記錄這棵樹;
  6. 對於中文的字典樹,每個節點的子節點用一個哈希表存儲,這樣就不用浪費太大的空間,而且查詢速度上可以保留哈希的複雜度 O(1)

24、拼寫糾錯是如何實現的?

  1. 拼寫糾錯是基於編輯距離來實現;編輯距離是一種標準的方法,它用來表示經過插入、刪除和替換操作從一個字符串轉換到另外一個字符串的最小操作步數;
  2. 編輯距離的計算過程:比如要計算 batyu 和 beauty 的編輯距離,先創建一個7×8 的表(batyu 長度爲 5,coffee 長度爲 6,各加 2),接着,在如下位置填入黑色數字。其他格的計算過程是取以下三個值的最小值:
    如果最上方的字符等於最左方的字符,則爲左上方的數字。否則爲左上方的數字
    +1。(對於 3,3 來說爲 0)
    左方數字+1(對於 3,3 格來說爲 2) 上方數字+1(對於 3,3 格來說爲 2)
    最終取右下角的值即爲編輯距離的值 3。
    在這裏插入圖片描述
    對於拼寫糾錯,我們考慮構造一個度量空間(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) – 三角不等式
  3. 根據三角不等式,則滿足與 query 距離在 n 範圍內的另一個字符轉 B,其與 A的距離最大爲 d+n,最小爲 d-n。
  4. 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。
  5. 查詢相似詞如下:計算單詞與根節點的編輯距離 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 這個滿足條件的結果。
    在這裏插入圖片描述

擴展連接:加粗樣式更多請點擊這裏

博主公衆號程序員小羊 只發面試相關推文
在這裏插入圖片描述

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