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 存于內存中(堆外內存),有助于快速訪問。
更多 doc_values 的介紹與使用歡迎閱讀這篇文章:ElasticSearch搜索引擎:doc_values詳細介紹
5、text 和 keyword類型的區別:
兩個類型的區別主要是分詞:keyword 類型是不會分詞的,直接根據字符串內容建立倒排索引,所以keyword類型的字段只能通過精確值搜索到;Text 類型在存入 Elasticsearch 的時候,會先分詞,然后根據分詞后的內容建立倒排索引
6、query 和 filter 的區別?
(1)query:查詢操作不僅僅會進行查詢,還會計算分值,用于確定相關度;
(2)filter:查詢操作僅判斷是否滿足查詢條件,不會計算任何分值,也不會關心返回的排序問題,同時,filter 查詢的結果可以被緩存,提高性能。
二、ES的寫入流程:
1、ES寫數據的整體流程:
(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主分片寫數據的詳細流程:
(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。如果你在做批量導入,完全不在意搜索,你可以徹底關掉合并限流。
八、ES的深度分頁與滾動搜索scroll
(1)深度分頁:
深度分頁其實就是搜索的深淺度,比如第1頁,第2頁,第10頁,第20頁,是比較淺的;第10000頁,第20000頁就是很深了。搜索得太深,就會造成性能問題,會耗費內存和占用cpu。而且es為了性能,他不支持超過一萬條數據以上的分頁查詢。那么如何解決深度分頁帶來的問題,我們應該避免深度分頁操作(限制分頁頁數),比如最多只能提供100頁的展示,從第101頁開始就沒了,畢竟用戶也不會搜的那么深。
(2)滾動搜索:
一次性查詢1萬+數據,往往會造成性能影響,因為數據量太多了。這個時候可以使用滾動搜索,也就是 scroll。 滾動搜索可以先查詢出一些數據,然后再緊接著依次往下查詢。在第一次查詢的時候會有一個滾動id,相當于一個錨標記 ,隨后再次滾動搜索會需要上一次搜索滾動id,根據這個進行下一次的搜索請求。每次搜索都是基于一個歷史的數據快照,查詢數據的期間,如果有數據變更,那么和搜索是沒有關系的。
————————————————
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
原文鏈接:https://blog.csdn.net/a745233700/article/details/115585342

浙公網安備 33010602011771號