來源:8rr.co/GsAajava
ES 寫入數據的工做原理是什麼啊?ES 查詢數據的工做原理是什麼啊?底層的 Lucene 介紹一下唄?倒排索引瞭解嗎?node
問這個,其實面試官就是要看看你瞭解不瞭解 es 的一些基本原理,由於用 es 無非就是寫入數據,搜索數據。你要是不明白你發起一個寫入和搜索請求的時候,es 在幹什麼,那你真的是......面試
對 es 基本就是個黑盒,你還能幹啥?你惟一能幹的就是用 es 的 api 讀寫數據了。要是出點什麼問題,你啥都不知道,那還能期望你什麼呢?算法
coordinating node
(協調節點)。coordinating node
對 document 進行路由,將請求轉發給對應的 node(有 primary shard)。primary shard
處理請求,而後將數據同步到 replica node
。coordinating node
若是發現 primary node
和全部 replica node
都搞定以後,就返回響應結果給客戶端。
es-writeapi
能夠經過 doc id
來查詢,會根據 doc id
進行 hash,判斷出來當時把 doc id
分配到了哪一個 shard 上面去,從那個 shard 去查詢。緩存
coordinate node
。coordinate node
對 doc id
進行哈希路由,將請求轉發到對應的 node,此時會使用 round-robin
隨機輪詢算法,在 primary shard
以及其全部 replica 中隨機選擇一個,讓讀請求負載均衡。coordinate node
。coordinate node
返回 document 給客戶端。es 最強大的是作全文檢索,就是好比你有三條數據:restful
java真好玩兒啊 java好難學啊 j2ee特別牛Copy to clipboardErrorCopied
你根據 java
關鍵詞來搜索,將包含 java
的 document
給搜索出來。es 就會給你返回:java真好玩兒啊,java好難學啊。數據結構
coordinate node
。primary shard
或 replica shard
,均可以。doc id
)返回給協調節點,由協調節點進行數據的合併、排序、分頁等操做,產出最終結果。doc id
去各個節點上拉取實際的 document
數據,最終返回給客戶端。寫請求是寫入 primary shard,而後同步給全部的 replica shard;讀請求能夠從 primary shard 或 replica shard 讀取,採用的是隨機輪詢算法。
es-write-detail負載均衡
先寫入內存 buffer,在 buffer 裏的時候數據是搜索不到的;同時將數據寫入 translog 日誌文件。性能
若是 buffer 快滿了,或者到必定時間,就會將內存 buffer 數據 refresh
到一個新的 segment file
中,可是此時數據不是直接進入 segment file
磁盤文件,而是先進入 os cache
。這個過程就是 refresh
。
每隔 1 秒鐘,es 將 buffer 中的數據寫入一個新的 segment file
,每秒鐘會產生一個新的磁盤文件 segment file
,這個 segment file
中就存儲最近 1 秒內 buffer 中寫入的數據。
可是若是 buffer 裏面此時沒有數據,那固然不會執行 refresh 操做,若是 buffer 裏面有數據,默認 1 秒鐘執行一次 refresh 操做,刷入一個新的 segment file 中。
操做系統裏面,磁盤文件其實都有一個東西,叫作 os cache
,即操做系統緩存,就是說數據寫入磁盤文件以前,會先進入 os cache
,先進入操做系統級別的一個內存緩存中去。只要 buffer
中的數據被 refresh 操做刷入 os cache
中,這個數據就能夠被搜索到了。
爲何叫 es 是準實時的?NRT
,全稱 near real-time
。默認是每隔 1 秒 refresh 一次的,因此 es 是準實時的,由於寫入的數據 1 秒以後才能被看到。能夠經過 es 的 restful api
或者 java api
,手動執行一次 refresh 操做,就是手動將 buffer 中的數據刷入 os cache
中,讓數據立馬就能夠被搜索到。只要數據被輸入 os cache
中,buffer 就會被清空了,由於不須要保留 buffer 了,數據在 translog 裏面已經持久化到磁盤去一份了。
重複上面的步驟,新的數據不斷進入 buffer 和 translog,不斷將 buffer
數據寫入一個又一個新的 segment file
中去,每次 refresh
完 buffer 清空,translog 保留。隨着這個過程推動,translog 會變得愈來愈大。當 translog 達到必定長度的時候,就會觸發 commit
操做。
commit 操做發生第一步,就是將 buffer 中現有數據 refresh
到 os cache
中去,清空 buffer。而後,將一個 commit point
寫入磁盤文件,裏面標識着這個 commit point
對應的全部 segment file
,同時強行將 os cache
中目前全部的數據都 fsync
到磁盤文件中去。最後清空 現有 translog 日誌文件,重啓一個 translog,此時 commit 操做完成。
這個 commit 操做叫作 flush
。默認 30 分鐘自動執行一次 flush
,但若是 translog 過大,也會觸發 flush
。flush 操做就對應着 commit 的全過程,咱們能夠經過 es api,手動執行 flush 操做,手動將 os cache 中的數據 fsync 強刷到磁盤上去。
translog 日誌文件的做用是什麼?你執行 commit 操做以前,數據要麼是停留在 buffer 中,要麼是停留在 os cache 中,不管是 buffer 仍是 os cache 都是內存,一旦這臺機器死了,內存中的數據就全丟了。因此須要將數據對應的操做寫入一個專門的日誌文件 translog
中,一旦此時機器宕機,再次重啓的時候,es 會自動讀取 translog 日誌文件中的數據,恢復到內存 buffer 和 os cache 中去。
translog 其實也是先寫入 os cache 的,默認每隔 5 秒刷一次到磁盤中去,因此默認狀況下,可能有 5 秒的數據會僅僅停留在 buffer 或者 translog 文件的 os cache 中,若是此時機器掛了,會丟失 5 秒鐘的數據。可是這樣性能比較好,最多丟 5 秒的數據。也能夠將 translog 設置成每次寫操做必須是直接 fsync
到磁盤,可是性能會差不少。
實際上你在這裏,若是面試官沒有問你 es 丟數據的問題,你能夠在這裏給面試官炫一把,你說,其實 es 第一是準實時的,數據寫入 1 秒後能夠搜索到;可能會丟失數據的。有 5 秒的數據,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盤上,此時若是宕機,會致使 5 秒的數據丟失。
總結一下,數據先寫入內存 buffer,而後每隔 1s,將數據 refresh 到 os cache,到了 os cache 數據就能被搜索到(因此咱們才說 es 從寫入到能被搜索到,中間有 1s 的延遲)。每隔 5s,將數據寫入 translog 文件(這樣若是機器宕機,內存數據全沒,最多會有 5s 的數據丟失),translog 大到必定程度,或者默認每隔 30mins,會觸發 commit 操做,將緩衝區的數據都 flush 到 segment file 磁盤文件中。
數據寫入 segment file 以後,同時就創建好了倒排索引。
若是是刪除操做,commit 的時候會生成一個 .del
文件,裏面將某個 doc 標識爲 deleted
狀態,那麼搜索的時候根據 .del
文件就知道這個 doc 是否被刪除了。
若是是更新操做,就是將原來的 doc 標識爲 deleted
狀態,而後新寫入一條數據。
buffer 每 refresh 一次,就會產生一個 segment file
,因此默認狀況下是 1 秒鐘一個 segment file
,這樣下來 segment file
會愈來愈多,此時會按期執行 merge。每次 merge 的時候,會將多個 segment file
合併成一個,同時這裏會將標識爲 deleted
的 doc 給物理刪除掉,而後將新的 segment file
寫入磁盤,這裏會寫一個 commit point
,標識全部新的 segment file
,而後打開 segment file
供搜索使用,同時刪除舊的 segment file
。
簡單來講,lucene 就是一個 jar 包,裏面包含了封裝好的各類創建倒排索引的算法代碼。咱們用 Java 開發的時候,引入 lucene jar,而後基於 lucene 的 api 去開發就能夠了。
經過 lucene,咱們能夠將已有的數據創建索引,lucene 會在本地磁盤上面,給咱們組織索引的數據結構。
在搜索引擎中,每一個文檔都有一個對應的文檔 ID,文檔內容被表示爲一系列關鍵詞的集合。例如,文檔 1 通過分詞,提取了 20 個關鍵詞,每一個關鍵詞都會記錄它在文檔中出現的次數和出現位置。
那麼,倒排索引就是關鍵詞到文檔 ID 的映射,每一個關鍵詞都對應着一系列的文件,這些文件中都出現了關鍵詞。
舉個栗子。
有如下文檔:
另外,實用的倒排索引還能夠記錄更多的信息,好比文檔頻率信息,表示在文檔集合中有多少個文檔包含某個單詞。
那麼,有了倒排索引,搜索引擎能夠很方便地響應用戶的查詢。好比用戶輸入查詢 Facebook
,搜索系統查找倒排索引,從中讀出包含這個單詞的文檔,這些文檔就是提供給用戶的搜索結果。
要注意倒排索引的兩個重要細節:
上面只是一個簡單的例子,並無嚴格按照字典順序升序排列。