談談ES讀寫數據那些事

前言

ES最強的的能力就是能做全文檢索,在互聯網平臺或者文檔檔案平臺隨處可見,那麼ES中數據如何實現讀寫操作的呢以及ES是如何檢索數據的呢,下面文章就揭曉下這些問題。

ES寫數據過程

  1. 客戶端選擇一個node發送請求,這個node就是協調節點(coordinate node);
  2. coordinate node 對document進行路由,將請求轉發對應的node(包含 primary shard)
  3. 實際的node上的primary shard處理請求,然後將數據同步到replica node
  4. coordinate node如果發現 primary node和所有replica node都搞定之後,就返回響應結果給客戶端;

上述可以理解爲協調節點對document進行路由轉發到其它節點包含主分片,然後主分片進行處理數據同步到副本,最後再由協調節點返回響應結果給客戶端。其過程即如下圖所示 es-1

ES讀數據過程

可以通過doc id來查詢,會根據doc id進行hash,判斷出來當時把doc id分配到哪個shard上面去,從哪個shard去查詢.

  1. 客戶端發送請求到任意一個node,成爲coordinate node;
  2. coordinate node 對doc id進行hash路由,將請求轉發到對應node,此時採用隨機輪詢算法,在primary shard以及所有replica shard中隨機選擇一個,讓讀請求負載均衡;
  3. 接收請求的node返回document給coordinate node;
  4. coordinate node 返回document給客戶端;

ES搜索數據過程

ES最強大的是做全文檢索

  1. 客戶端發送請求到一個coordinate node
  2. 協調節點將搜索請求轉發到所有的shard對應的primary shard或者replica shard,即可;
  3. query phase: 每個shard將自己的搜索結果(其實就是一些doc id)返回給協調節點,由協調節點進行數據的合併、排序、分頁等操作,產出最終結果;
  4. fetch phase:接着由協調節點根據doc id去各個節點上拉取實際的document數據,最終返回給客戶端;

說明:寫請求是寫入 主分片即primary shard,然後同步給所有的replica shard,讀請求可以從primary shard或者replica shard讀取,採用的隨機輪詢算法。

ES寫數據底層原理

ES寫數據過程分析

  1. 先寫入內存buffer,此時buffer中的數據是無法搜索的,同時將數據寫入translog日誌文件。

    如果buffer快滿時,或者到一定時間,此時會將內存buffer數據refresh到一個新文件segment file中但是此時數據不是直接進入segment file磁盤文件,而是先進入os cache 此過程就是refresh。

    默認每間隔1s鍾,es將buffer中數據寫入一個新的segment file,即每秒鐘會寫入一個新的segment file,此時segment file就存儲最近1s內buffer中寫入數據。

  2. 如果buffer中無數據,不會執行refresh操作,如果buffer裏面有數據,默認1秒鐘執行一次refresh操作,輸入一個新的segment file中。 操作系統裏面,磁盤文件其實都有一個東西,叫做os cache,即操作系統緩存,就是說數據寫入磁盤文件之前,會先進入os cache,先進入操作系統級別的一個內存緩存中去。只要buffer中的數據被refresh操作輸入os cache中,這個數據就可以被搜索到了。

  3. ES是準實時(NRT),全稱 near real-time.默認是每隔1秒refresh一次的,所以es是準實時的,因爲寫入的數據1s之後才能被看到。

    可以通過es的restful api或者 java api,手動執行一次 refresh操作,就是手動將buffer中的數據刷入os cache中,讓數據立馬就可以被搜索到。只要

    數據被輸入os cache中,buffer 就會被清空了,因爲不需要保留buffer了,數據在translog裏面已經持久化到磁盤去一份了。

  4. 重複上面的步驟,新的數據不斷進入buffer和translog,不斷將buffer數據寫入一個又一個新的segment file中去,每次refresh完buffer清空,translog保留。

    隨着這個過程的推進,translog會變得越來越大。當translog達到一定長度的時候,就會觸發commit操作。

  5. commit操作發生的第一步,就是將buffer中現有的數據refresh到os cache中去,清空buffer。然後將一個commit point寫入磁盤文件,裏面標識者這個commit

    point 對應的所有segment file,同時強行將os cache中目前所有的數據都fsync到磁盤文件中去。最後清空現有 translog日誌文件,重啓一個translog,此時commit操作完成。

  6. 這個commit操作叫做flush。默認30分鐘自動執行一次flush,但如translog 過大,也會觸發flush。flush操作就對應着commit的全過程,我們可以通過es api,手動執行flush操作,手動將os cache中數據fsync強刷到磁盤上去。

  7. 執行commit 操作之前,數據要麼是停留在buffer中,要麼是停留在os cache中,無論是buffer 還是os cache都是內存,一旦這臺機器死了,內存中的數據就全丟失。所以需要將數據對應的操作寫入一個專門的日誌文件translog中,一旦此時機器宕機了,再次重啓的時候,es會自動讀取translog日誌文件中的數據,恢復到內存buffer和os cache。

  8. translog其實也是先寫入os cache的,默認每隔5秒刷一次到磁盤中去,所以默認情況下,可能有5s的數據會僅僅停留在buffer或者translog文件的os cache中,如果此時機器掛了,會丟失5秒鐘的數據。但是這樣性能比較好,最多丟5秒的數據。也可以將translog設置成每次寫操作必須是直接fsync到磁盤,但是性能會差很多。

  9. es第一是準實時的,數據寫入1秒後就可以搜索到:可能會丟失數據的。有5秒的數據,停留在buffer、translog os cache 、segment file os cache中,而不在磁盤上,此時如果宕機,會導致5秒的數據丟失。

ES總體寫入數據分析

數據先寫入內存buffer,然後每隔1s,將數據refresh到 os cache,到了 os cache數據就能被搜索到(所以我們才說es從寫入到能被搜索到,中間有1s的延遲)。每隔5s,將數據寫入到translog文件(這樣如果機器宕機,內存數據全沒,最多會有5s的數據丟失),translog達到一定程度,或者默認每隔30min,會觸發commit操作,將緩衝區的數據都flush到segment file磁盤文件中。數據寫入 segment file之後,同時就建立好了倒排索引 。如下圖所示

es-2

ES寫入數據流程幾大特性

  1. 可靠性

    通過Replica和TransLog兩套機制保證數據的可靠性。

  2. 一致性

    Lucene中的Flush鎖只保證Update接口裏面Delete和Add中間不會Flush,但無法保證主分片與副本分片一致。因爲如果add之後立即flush,這個時候segment是主分片可見的,但副本分片要落後於主分片。不過最終都會一致。

  3. 原子性

    Add和Delete具有原子性。當部分更新時,使用Version和鎖保證更新是原子的

  4. 實時性

    Flush之後的segment對用戶可見,最快可配置100ms,可實現near-real-time。特定的查詢,直接查TransLog,可實現real-time。

  5. 隔離性

    採用Version和局部鎖來保證更新的是特定版本的數據;

  6. 高效性

    • 不需要所有Replica都返回後才能返回給用戶,只需要返回特定數目的就行;
    • 生成的Segment現在內存中提供服務,等一段時間後才刷新到磁盤,Segment在內存這段時間的可靠性由TransLog保證;
    • TransLog可以配置爲週期性的Flush,但這個會給可靠性帶來影響;
    • 每個線程持有一個Segment,多線程時相互不影響,相互獨立,性能更好;
    • 系統的寫入流程對版本依賴較重,讀取頻率較高,因此採用了versionMap,減少熱點數據的多次磁盤IO開銷;

ES 刪除、更新數據操作原理

如果是刪除操作,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。

底層lucence

簡單來說,lucence就是一個jar包,裏面包含了封裝好的各種建立倒排索引的算法代碼。我們用java 開發的時候,引入 lucene jar,然後基於lucene的api去開發就可以了。通過lucene,我們可以將已有的數據建立索引,lucene會在本地磁盤上面,給我們組織索引的數據結果。

倒排索引

在搜索引擎中,每個文檔都有一個對應的文檔ID,文檔內容被標識爲一系列關鍵詞的集合,例如文檔1經過分詞,提取到了20個關鍵詞,每個關鍵詞item都會記錄它在文檔中出現的次數和出現位置。那麼,倒排索引就是關鍵詞到文檔ID的映射,每個關鍵詞都對應着一系列的文件,這些文件中都出現了關鍵詞。另外,實用的倒排索引還可以記錄更多的信息,比如文檔頻率信息,表示在文檔集合中有多少個文檔包含某個詞。

  • 倒排索引中的所有詞項對應一個或多個文檔
  • 倒排索引中的詞項根據字典順序升序排列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章