es寫入數據的工作原理是什么啊?es查詢數據的工作原理是什么?底層的lucence介紹一下唄?倒排索引了解嗎?
一、es寫數據過程
1、客戶端選擇一個node發送請求過去,這個node就是coordinating node(協調節點)
2、coordinating node 對document進行路由,將請求轉發給對應的node(有primary shard)
3、實際的node上的primary shard 處理請求,然后將數據同步到replica node。
4、coordinating node如果發現 primary node和所有replica node都搞定之后,就返回響應結果給客戶端。
二、es讀數據過程
可以通過doc id 來查詢,會根據doc id進行hash,判斷出來當時把doc id分配到了哪個shard上面去,從那個shard去查詢。
1、客戶端發送請求到任意一個node,成為coordinate node
2、coordinate node 對doc id進行哈希路由,將請求轉發到對應node,此時會使用round-robin隨機輪詢算法,在primary shard 以及其所有replica中隨機選擇一個,讓讀請求負載均衡。
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 讀取,采用的是隨機輪詢算法。
四、寫數據底層原理
1、先寫入內存buffer,在buffer里的時候數據是搜索不到的;同時將數據寫入translog日志文件。
如果buffer快滿了,或者到一定時間,就會將內存buffer數據refresh 到一個新的segment file中,但是此時數據不是直接進入segment file磁盤文件,而是先進入
os cache。這個過程就是 refresh。
每隔1秒鍾,es將buffer中的數據寫入一個新的segment file,每秒鍾會寫入一個新的segment file,這個segment file中就存儲最近1秒內 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、translog日志文件的作用是什么?
執行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秒的數據丟失。
10、總結::數據先寫入內存buffer,然后每隔1s,將數據refresh到 os cache,到了 os cache數據就能被搜索到(所以我們才說es從寫入到能被搜索到,中間有1s的延遲)。
每隔5s,將數據寫入到translog文件(這樣如果機器宕機,內存數據全沒,最多會有5s的數據丟失),translog達到一定程度,或者默認每隔30min,會觸發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。
六、底層lucence
簡單來說,lucence就是一個jar包,里面包含了封裝好的各種建立倒排索引的算法代碼。我們用java 開發的時候,引入 lucene jar,然后基於lucene的api去開發
就可以了。
通過lucene,我們可以將已有的數據建立索引,lucene會在本地磁盤上面,給我們組織索引的數據結果。