2021-Java后端工程師面試指南-(Elasticsearch)

前言

文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger
種一棵樹最好的時間是十年前,其次是現在

Tips

面試指南系列,很多情況下不會去深挖細節,是小六六以被面試者的角色去回顧知識的一種方式,所以我默認大部分的東西,作為面試官的你,肯定是懂的。

https://www.processon.com/view/link/600ed9e9637689349038b0e4

上面的是腦圖地址

叨絮

今天來看看Elasticsearch
然后下面是前面的文章匯總

Es其實用的很多,而且如果體量大點的話,基本上都需要使用到它,所以掌握它還是很有必要的,那么我們來一起看看吧

說說什么是Elasticsearch

  • Elasticsearch,基于lucene.分布式的Restful實時搜索和分析引擎(實時)
  • 分布式的實時文件存儲,每個字段都被索引并可被搜索
  • 高擴展性,可擴展至上百臺服務器,處理PB級結構化或非結構化數據
  • Elasticsearch用于全文檢索,結構化搜索,分析/合并使用

聊聊Elasticsearch的特性:

  • Elasticsearch沒有典型意義的事務(無事務性)
  • Elasticsearch是一種面向文檔的數據庫
  • Elasticsearch沒有提供授權和認證特性

什么是全文檢索和Lucene?

全文檢索,倒排索引

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

lucene
lucene,就是一個jar包,里面包含了封裝好的各種建立倒排索引,以及進行搜索的代碼,包括各種算法。我們就用java開發的時候,引入lucene jar,然后基于lucene的api進行去進行開發就可以了。

那你聊聊Elasticsearch的核心概念,就是我們經常用的那些。

近實時
近實時,兩個意思,從寫入數據到數據可以被搜索到有一個小延遲(大概1秒);基于es執行搜索和分析可以達到秒級。

Cluster(集群)
集群包含多個節點,每個節點屬于哪個集群是通過一個配置(集群名稱,默認是elasticsearch)來決定的,對于中小型應用來說,剛開始一個集群就一個節點很正常

Node(節點)

集群中的一個節點,節點也有一個名稱(默認是隨機分配的),節點名稱很重要(在執行運維管理操作的時候),默認節點會去加入一個名稱為“elasticsearch”的集群,如果直接啟動一堆節點,那么它們會自動組成一個elasticsearch集群,當然一個節點也可以組成一個elasticsearch集群。

Index(索引-數據庫)
索引包含一堆有相似結構的文檔數據,比如可以有一個客戶索引,商品分類索引,訂單索引,索引有一個名稱。一個index包含很多document,一個index就代表了一類類似的或者相同的document。比如說建立一個product index,商品索引,里面可能就存放了所有的商品數據,所有的商品document。

Type(類型-表)
每個索引里都可以有一個或多個type,type是index中的一個邏輯數據分類,一個type下的document,都有相同的field,比如博客系統,有一個索引,可以定義用戶數據type,博客數據type,評論數據type。

Document(文檔-行)
文檔是es中的最小數據單元,一個document可以是一條客戶數據,一條商品分類數據,一條訂單數據,通常用JSON數據結構表示,每個index下的type中,都可以去存儲多個document。

Field(字段-列)
Field是Elasticsearch的最小單位。一個document里面有多個field,每個field就是一個數據字段。

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

replica
任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,因此可以為每個shard創建多個replica副本。replica可以在shard故障時提供備用服務,保證數據不丟失,多個replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時一次設置,不能修改,默認5個),replica shard(隨時修改數量,默認1個),默認每個索引10個shard,5個primary shard,5個replica shard,最小的高可用配置,是2臺服務器。

說說Elasticsearch樂觀并發控制

Elasticsearch是分布式的。當文檔被創建、更新或刪除,文檔的新版本會被復制到集群的其它節點。Elasticsearch即是同步的又是異步的,意思是這些復制請求都是平行發送的,并無序(out of sequence)的到達目的地。這就需要一種方法確保老版本的文檔永遠不會覆蓋新的版本。
上文我們提到index、get、delete請求時,我們指出每個文檔都有一個_version號碼,這個號碼在文檔被改變時加一。Elasticsearch使用這個_version保證所有修改都被正確排序。當一個舊版本出現在新版本之后,它會被簡單的忽略。
我們利用_version的這一優點確保數據不會因為修改沖突而丟失。我們可以指定文檔的version來做想要的更改。如果那個版本號不是現在的,我們的請求就失敗了。
用version 來保證并發的順序一致性

聊聊text,keyword類型的區別

  • text:當一個字段是要被全文搜索的,比如Email內容、產品描述,應該使用text類型。設置text類型以后,字段內容會被分析,在生成倒排索引以前,字符串會被分析器分成一個一個詞項。text類型的字段不用于排序,很少用于聚合。
  • keyword:keyword類型適用于索引結構化的字段,比如email地址、主機名、狀態碼和標簽。如果字段需要進行過濾(比如查找已發布博客中status屬性為published的文章)、排序、聚合。keyword類型的字段只能通過精確值搜索到。

那你說說查詢api返回的主要包含什么東西

hits
響應中最重要的部分是hits,它包含了total字段來表示匹配到的文檔總數,hits數組還包含了匹配到的前10條數據。
hits數組中的每個結果都包含_index、_type和文檔的_id字段,被加入到_source字段中這意味著在搜索結果中我們將可以直接使用全部文檔。這不像其他搜索引擎只返回文檔ID,需要你單獨去獲取文檔。
每個節點都有一個_score字段,這是相關性得分(relevance score),它衡量了文檔與查詢的匹配程度。默認的,返回的結果中關聯性最大的文檔排在首位;這意味著,它是按照_score降序排列的。這種情況下,我們沒有指定任何查詢,所以所有文檔的相關性是一樣的,因此所有結果的_score都是取得一個中間值1
max_score指的是所有文檔匹配查詢中_score的最大值。

took
took告訴我們整個搜索請求花費的毫秒數。

shards
_shards節點告訴我們參與查詢的分片數(total字段),有多少是成功的(successful字段),有多少的是失敗的(failed字段)。通常我們不希望分片失敗,不過這個有可能發生。如果我們遭受一些重大的故障導致主分片和復制分片都故障,那這個分片的數據將無法響應給搜索請求。這種情況下,Elasticsearch將報告分片failed,但仍將繼續返回剩余分片上的結果。

timeout

time_out值告訴我們查詢超時與否。一般的,搜索請求不會超時。如果響應速度比完整的結果更重要,你可以定義timeout參數為10或者10ms(10毫秒),或者1s(1秒)

聊聊shard&replica機制

  • index包含多個shard
  • 每個shard都是一個最小工作單元,承載部分數據,lucene實例,完整的建立索引和處理請求的能力
  • 增減節點時,shard會自動在nodes中負載均衡
  • primary shard和replica shard,每個document肯定只存在于某一個primary shard以及其對應的replica shard中,不可能存在于多個primary shard
  • replica shard是primary shard的副本,負責容錯,以及承擔讀請求負載
  • primary shard的數量在創建索引的時候就固定了,replica shard的數量可以隨時修改
  • primary shard的默認數量是5,replica默認是1,默認有10個shard,5個primary shard,5個replica shard
  • primary shard不能和自己的replica shard放在同一個節點上(否則節點宕機,primary shard和副本都丟失,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節點上

ES是如何實現master選舉的?

前置條件:

  • 只有是候選主節點(master:true)的節點才能成為主節點。
  • 最小主節點數(min_master_nodes)的目的是防止腦裂。

Elasticsearch 的選主是 ZenDiscovery 模塊負責的,主要包含 Ping(節點之間通過這個RPC來發現彼此)和 Unicast(單播模塊包含一個主機列表以控制哪些節點需要 ping 通)這兩部分;
獲取主節點的核心入口為 findMaster,選擇主節點成功返回對應 Master,否則返回 null。

選舉流程大致描述如下:

  • 第一步:確認候選主節點數達標,elasticsearch.yml 設置的值 discovery.zen.minimum_master_nodes;
  • 第二步:對所有候選主節點根據nodeId字典排序,每次選舉每個節點都把自己所知道節點排一次序,然后選出第一個(第0位)節點,暫且認為它是master節點。
  • 第三步:如果對某個節點的投票數達到一定的值(候選主節點數n/2+1)并且該節點自己也選舉自己,那這個節點就是master。否則重新選舉一直到滿足上述條件。

如何解決ES集群的腦裂問題

所謂集群腦裂,是指 Elasticsearch 集群中的節點(比如共 20 個),其中的 10 個選了一個 master,另外 10 個選了另一個 master 的情況。

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

聊聊es的寫入流程

Elasticsearch采用多Shard方式,通過配置routing規則將數據分成多個數據子集,每個數據子集提供獨立的索引和搜索功能。當寫入文檔的時候,根據routing規則,將文檔發送給特定Shard中建立索引。這樣就能實現分布式了。

每個Index由多個Shard組成(默認是5個),每個Shard有一個主節點和多個副本節點,副本個數可配。但每次寫入的時候,寫入請求會先根據_routing規則選擇發給哪個Shard,Index Request中可以設置使用哪個Filed的值作為路由參數,如果沒有設置,則使用Mapping中的配置,如果mapping中也沒有配置,則使用_id作為路由參數,然后通過_routing的Hash值選擇出Shard(在OperationRouting類中),最后從集群的Meta中找出出該Shard的Primary節點。

請求接著會發送給Primary Shard,在Primary Shard上執行成功后,再從Primary Shard上將請求同時發送給多個Replica Shard,請求在多個Replica Shard上執行成功并返回給Primary Shard后,寫入請求執行成功,返回結果給客戶端。

那你說說具體在 shard上的寫入流程唄

在每一個Shard中,寫入流程分為兩部分,先寫入Lucene,再寫入TransLog。

寫入請求到達Shard后,先寫Lucene文件,創建好索引,此時索引還在內存里面,接著去寫TransLog,寫完TransLog后,刷新TransLog數據到磁盤上,寫磁盤成功后,請求返回給用戶。這里有幾個關鍵點:

和數據庫不同,數據庫是先寫CommitLog,然后再寫內存,而Elasticsearch是先寫內存,最后才寫TransLog,一種可能的原因是Lucene的內存寫入會有很復雜的邏輯,很容易失敗,比如分詞,字段長度超過限制等,比較重,為了避免TransLog中有大量無效記錄,減少recover的復雜度和提高速度,所以就把寫Lucene放在了最前面。

寫Lucene內存后,并不是可被搜索的,需要通過Refresh把內存的對象轉成完整的Segment后,然后再次reopen后才能被搜索,一般這個時間設置為1秒鐘,導致寫入Elasticsearch的文檔,最快要1秒鐘才可被從搜索到,所以Elasticsearch在搜索方面是NRT(Near Real Time)近實時的系統。

每隔一段比較長的時間,比如30分鐘后,Lucene會把內存中生成的新Segment刷新到磁盤上,刷新后索引文件已經持久化了,歷史的TransLog就沒用了,會清空掉舊的TransLog。

Lucene緩存中的數據默認1秒之后才生成segment文件,即使是生成了segment文件,這個segment是寫到頁面緩存中的,并不是實時的寫到磁盤,只有達到一定時間或者達到一定的量才會強制flush磁盤。如果這期間機器宕掉,內存中的數據就丟了。如果發生這種情況,內存中的數據是可以從TransLog中進行恢復的,TransLog默認是每5秒都會刷新一次磁盤。但這依然不能保證數據安全,因為仍然有可能最多丟失TransLog中5秒的數據。這里可以通過配置增加TransLog刷磁盤的頻率來增加數據可靠性,最小可配置100ms,但不建議這么做,因為這會對性能有非常大的影響。一般情況下,Elasticsearch是通過副本機制來解決這一問題的。即使主分片所在節點宕機,丟失了5秒數據,依然是可以通過副本來進行恢復的。

總結一下,數據先寫入內存 buffer,然后每隔 1s,將數據 refresh 到 os cache,到了 os cache 數據就能被搜索到(所以我們才說 es 從寫入到能被搜索到,中間有 1s 的延遲)。每隔 5s,將數據寫入 translog 文件(這樣如果機器宕機,內存數據全沒,最多會有 5s 的數據丟失),translog 大到一定程度,或者默認每隔 30mins,會觸發 commit 操作,將緩沖區的數據都 flush 到 segment file 磁盤文件中。

說說es的更新流程吧

Lucene中不支持部分字段的Update,所以需要在Elasticsearch中實現該功能,具體流程如下:

  • 到Update請求后,從Segment或者TransLog中讀取同id的完整Doc,記錄版本號為V1。
  • 將版本V1的全量Doc和請求中的部分字段Doc合并為一個完整的Doc,同時更新內存中的VersionMap。獲取到完整Doc后,Update請求就變成了Index請求。
  • 加鎖。
  • 再次從versionMap中讀取該id的最大版本號V2,如果versionMap中沒有,則從Segment或者TransLog中讀取,這里基本都會從versionMap中獲取到。
  • 檢查版本是否沖突(V1==V2),如果沖突,則回退到開始的“Update doc”階段,重新執行。如果不沖突,則執行最新的Add請求。
  • 在Index Doc階段,首先將Version + 1得到V3,再將Doc加入到Lucene中去,Lucene中會先刪同id下的已存在doc id,然后再增加新Doc。寫入Lucene成功后,將當前V3更新到versionMap中。
  • 釋放鎖,部分更新的流程就結束了

詳細描述一下ES搜索的過程?

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

Query階段:
查詢會廣播到索引中每一個分片拷貝(主分片或者副本分片)。每個分片在本地執行搜索并構建一個匹配文檔的大小為 from + size 的優先隊列。PS:在搜索的時候是會查詢Filesystem Cache的,但是有部分數據還在Memory Buffer,所以搜索是近實時的。
每個分片返回各自優先隊列中 所有文檔的 ID 和排序值 給協調節點,它合并這些值到自己的優先隊列中來產生一個全局排序后的結果列表。
Fetch階段:
協調節點辨別出哪些文檔需要被取回并向相關的分片提交多個 GET 請求。每個分片加載并 豐富 文檔,如果有需要的話,接著返回文檔給協調節點。一旦所有的文檔都被取回了,協調節點返回結果給客戶端。

說說es的寫一致性

我們在發送任何一個增刪改操作的時候,比如說put /index/type/id,都可以帶上一個consistency參數,指明我們想要的寫一致性是什么?
put /index/type/id?consistency=quorum

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

聊聊 elasticsearch 深度分頁以及scroll 滾動搜索

深度分頁
深度分頁其實就是搜索的深淺度,比如第1頁,第2頁,第10頁,第20頁,是比較淺的;第10000頁,第20000頁就是很深了。
搜索得太深,就會造成性能問題,會耗費內存和占用cpu。而且es為了性能,他不支持超過一萬條數據以上的分頁查詢。那么如何解決深度分頁帶來的問題,我們應該避免深度分頁操作(限制分頁頁數),比如最多只能提供100頁的展示,從第101頁開始就沒了,畢竟用戶也不會搜的那么深,我們平時搜索淘寶或者京東也就看個10來頁就頂多了。

滾動搜索
一次性查詢1萬+數據,往往會造成性能影響,因為數據量太多了。這個時候可以使用滾動搜索,也就是 scroll 。
滾動搜索可以先查詢出一些數據,然后再緊接著依次往下查詢。在第一次查詢的時候會有一個滾動id,相當于一個錨標記 ,隨后再次滾動搜索會需要上一次搜索滾動id,根據這個進行下一次的搜索請求。每次搜索都是基于一個歷史的數據快照,查詢數據的期間,如果有數據變更,那么和搜索是沒有關系的。

es在數據量很大的情況下如何提高性能

filesystem

es每次走fileSystem cache查詢速度是最快的
所以將每個查詢的數據50% 容量
= fileSystem cache 容量。

數據預熱
數據預熱是指,每隔一段時間,將熱數據
手動在后臺查詢一遍,將熱數據刷新到fileSystem cache上

冷熱分離
類似于MySQL的分表分庫
將熱數據單獨建立一個索引 分配3臺機器只保持熱機器的索引
另外的機器保持冷數據的索引,但有一個問題,就是事先必須知道哪些是熱數據 哪些是冷數據

不可以深度分頁

跟產品經理說,你系統不允許翻那么深的頁,默認翻的越深,性能就越差。

類似于 app 里的推薦商品不斷下拉出來一頁一頁的
類似于微博中,下拉刷微博,刷出來一頁一頁的,你可以用 scroll api

結束

es可能我自己用的也比較少,就用來做一些搜索,沒有用來做bi,所以呢?也不是那么深入吧,希望對大家有幫助,接下來復習下隊列

日常求贊

好了各位,以上就是這篇文章的全部內容了,能看到這里的人呀,都是真粉

創作不易,各位的支持和認可,就是我創作的最大動力,我們下篇文章見

微信 搜 "六脈神劍的程序人生" 回復888 有我找的許多的資料送給大家

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容