本套技術專欄是作者(秦凱新)平時工作的總結和昇華,並深度整理大量網上資源和專業書籍。通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:1120746959@qq.com,如有任何學術交流,可隨時聯絡。
1 ES 分散式架構設計
elasticsearch設計的理念就是分散式搜尋引擎,底層其實還是基於lucene的。
es中儲存資料的基本單位是索引,比如說你現在要在es中儲存一些訂單資料,你就應該在es中建立一個索引,order_idx,所有的訂單資料就都寫到這個索引裡面去,一個索引差不多就是相當於是mysql裡的一張表。
-> index(mysql裡的一張表)
-> type(一個index裡可以有多個type,每個type的欄位都是差不多的,但是有一些略微的差別。
比如在訂單index裡,建兩個type,一個是實物商品訂單type,一個是虛擬商品訂單type,
這兩個type大部分欄位是一樣的,少部分欄位是不一樣的)
-> mapping (mapping就是這個type的表結構定義)
-> document (一條document就代表了mysql中某個表裡的一行,每個document有多個field,每個field就代表了這個document中的一個欄位的值)
-> field(具體索引欄位)
複製程式碼
- 設計一個索引,這個索引可以拆分成多個shard,每個shard儲存部分資料。
- 每一個shard的資料實際是有多個備份,每個shard都有一個primaryshard,負責寫入資料,但是還有幾個replica shard。primary shard寫入資料之後,會將資料同步到其他幾個replica shard上去。
- es叢集多個節點,會自動選舉一個節點為master節點,這個master節點其實就是幹一些管理的工作的,比如維護索引後設資料拉,負責切換primary shard和replica shard身份等。
- 如果master節點當機了,那麼會重新選舉一個節點為master節點。
- 如果是非master節點當機了,那麼會由master節點讓那個當機節點上的primary shard的身份轉移到其他機器上的replica shard。
2 ES 寫資料過程深入剖析
2.1 ES 寫資料總體流程
- 客戶端選擇一個node傳送請求過去,這個node就是coordinating node(協調節點)
- coordinating node,對document進行路由,將請求轉發給對應的node(擁有primary shard 的節點)
- 擁有primary shard 的node處理寫入請求,然後將資料同步到replica node
- coordinating node,如果發現primary node和所有replica node都搞定之後,就返回響應結果給客戶端。
2.2 ES 寫資料核心原理剖析
-
步驟一(buffer緩衝和寫入translog日誌階段):ES 寫資料先寫入buffer,在buffer裡的時候資料是搜尋不到的,並同時將資料寫入translog日誌檔案。
-
步驟二(refresh刷寫os cache階段):當寫入資料buffer快滿了,或者到一定時間,就會將buffer資料refresh到一個新的segment file中,但是此時資料不是直接進入segment file的磁碟檔案的,而是先進入os cache的,這個過程就是refresh。segment file位於os cache中。
(1) 每隔1秒鐘,es將buffer中的資料寫入一個新的segment file, 每秒鐘會產生一個新的磁碟檔案,segment file,這個segment file 中就儲存最近1秒內buffer中寫入的資料。 (2) 如果buffer裡面此時沒有資料,那當然不會執行refresh操作,每秒建立換一個空的 segment file,如果buffer裡面有資料,預設1秒鐘執行一次refresh操作,刷入一個 新的segment file中 (3) 只要buffer中的資料被refresh操作,刷入os cache中,就代表這個資料就可以被搜尋到了 (4) 為什麼叫es是準實時的?NRT,near real-time,準實時。 預設是每隔1秒refresh一次的,所以es是準實時的,因為寫入的資料1秒之後才能被看到。 (5) 可以通過es的restful api或者java api, 手動執行一次refresh操作,就是手動將buffer中的資料刷入os cache中,讓資料立馬就可以被搜尋到。 複製程式碼
-
步驟三(清空buffer階段):只要資料被輸入os cache中,buffer就會被清空了,因為不需要保留buffer了,資料在translog裡面已經持久化到磁碟去一份了。
-
步驟四(commit階段flush操作):重複1~3步驟,新的資料不斷進入buffer和translog,不斷將buffer資料寫入一個又一個新的segment file中去,每次refresh完buffer清空,translog保留。隨著這個過程推進,translog會變得越來越大。當translog達到一定長度的時候,就會觸發commit操作。
(1)commit操作發生第一步,就是將buffer中現有資料refresh到os cache中去,清空buffer (2)將一個commit point寫入磁碟檔案,裡面標識著這個commit point對應的所有segment file (3)強行將os cache中目前所有的資料(所有的segment file檔案)都fsync到磁碟檔案中去。 (4)將現有的translog清空,然後再次重啟啟用一個translog,此時commit操作完成。 預設每隔30分鐘會自動執行一次commit,但是如果translog過大,也會觸發 commit。整個commit的過程,叫做flush操作。我們可以手動執行flush操作, 就是將所有os cache資料刷到磁碟檔案中去。 (5)es中的flush操作,就對應著commit的全過程。我們也可以通過es api, 手動執行flush操作,手動將os cache中的資料fsync強刷到磁碟上去, 記錄一個commit point,清空translog日誌檔案。 (6)translog其實也是先寫入os cache的,預設每隔5秒刷一次到磁碟中去,所以預設情況下, 可能有5秒的資料會僅僅停留在buffer或者translog檔案的 os cache中,如果此時機器掛了,會丟失5秒鐘的資料。但是這樣效能比較好,最多 丟5秒的資料。也可以將translog設定成每次寫操作必須是直接fsync到磁碟,但是效能會差很多。 (7) es是準實時的,資料寫入1秒後可以搜尋到;但是卻可能會丟失資料,因為 有5秒的資料停留在buffer、translog os cache、segment file os cache中, 有5秒的資料不在磁碟上,此時如果當機,會導致5秒的資料丟失。 (8) 如果你希望一定不能丟失資料的話,你可以設定個引數,官方文件,百度一下。 每次寫入一條資料,都是寫入buffer,同時寫入磁碟上的translog,但是 這會導致寫效能、寫入吞吐量會下降一個數量級。本來一秒鐘可以寫2000條, 現在你一秒鐘只能寫200條,都有可能。 複製程式碼
-
步驟五(刪除操作):commit的時候會生成一個.del檔案,裡面將某個doc標識為deleted狀態,那麼搜尋的時候根據.del檔案就知道這個doc被刪除了
-
步驟六(更新操作):就是將原來的doc標識為deleted狀態,然後新寫入一條資料
-
步驟七 (merge階段操作):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。
3 ES 讀資料過程深入剖析
- 步驟一:客戶端傳送請求到一個coordinate node(隨機選擇)
- 步驟二:協調節點將搜尋請求轉發到所有的shard對應的primary shard或replica shard(不同的副本都可以用來搜尋)。
- 步驟三:query階段,每個shard將自己的搜尋結果(其實就是一些doc id),返回給協調節點,由協調節點進行資料的合併、排序、分頁等操作,產出最終結果
- 步驟四:fetch階段,接著由協調節點,根據doc id去各個節點上拉取實際的document資料,最終返回給客戶端
4 總結
在此感謝石杉的講義,結合大資料在我們工業大資料平臺的實踐,總結成一篇實踐指南,方便以後查閱反思,後續我會根據本篇部落格進行程式碼技術實踐實現。
秦凱新 於鄭州 201903032152