Elasticsearch由淺入深(十一)內核原理


倒排索引組成結構以及索引不可變原因

對於倒排索引是非常適合用來進行搜索的
它的結構:
(1)包含這個關鍵詞的document list
(2)包含這個關鍵詞的所有document的數量:IDF(inverse document frequency)
(3)這個關鍵詞在每個document中出現的次數:TF(term frequency)
(4)這個關鍵詞在這個document中的次序
(5)每個document的長度:length norm
(6)包含這個關鍵詞的所有document的平均長度
其實本質上主要是為了計算相關度分數

_score = boost * idf * tf 
此時boost = 2.2, idf = 0.18232156, tf = 0.5116279

idf = log(1 + (N - n + 0.5) / (n + 0.5))
此時n = 2 (n, number of documents containing term), 
N = 2(N, total number of documents with field)

tf = freq / (freq + k1 * (1 - b + b * dl / avgdl))
此時freq = 1(freq, occurrences of term within document), 
k1 = 1.2(k1, term saturation parameter), 
b = 0.75(b, length normalization parameter), 
d1 = 4 (dl, length of field), 
avgdl = 5.5(avgdl, average length of field)

倒排索引的不可變好處

(1)不需要鎖,提升了並發能力,避免鎖的問題
(2)數據不變,一直保存在OS cache中,只要cache內存足夠
(3)filter cache一直駐留在內存
(4)可以壓縮,節省cpu和io開銷
這個對應的就是primary shard的數量不變,不能修改field的屬性(將date改成text)

倒排索引不可變的壞處

(1)每次都需要重新構建整個索引

 

document寫入原理

(1)數據寫入buffer
(2)commit point
(3)buffer中的數據寫入新的index segment
(4)等待在OS cache中的index segment被fsync強制刷到磁盤上
(5)新的index segment被打開,供search使用
(6)buffer被清空

下面做幾點說明:

1、在Elasticsearch中,底層用的是lucene,lucene底層的index是分為多個segment的,每個segment都會存放部分數據。
2、如果是刪除操作,每次commit的時候,就會生成一個.del文件,標明哪個index segment的哪個document被刪除了。
3、如果是更新操作,實際上是將的doc標記為deleted,然后將新的document寫入新的index segment中。下次search過來的時候,也許會匹配到一個document的多個版本,但是之前的版本已經被標記為deleted了,所以只會返回最新版本的doc
4、如果搜索請求過來,在index segment中,匹配到了id=1的doc,此時會發現在.del文件中已經被標識為deleted了,這種數據就會被過濾掉,不會作為搜索結果返回。
圖示如下:

寫入流程近實時NRT(filesystem cache,refresh)

現有的流程的問題,每次都必須等待fsync將segment刷入磁盤,才能將segment打開供search使用,這樣的話,從一個document寫入,到它可以被搜索,可能會超過1分鍾,這也就不是近實時的搜索了。主要的瓶頸在於fsync從磁盤IO寫數據進磁盤是很耗時的。
ES寫入流程的改進:
(1)數據寫入buffer
(2)每個一定時間,buffer中的數據被寫入segment文件,但是先寫入OS cache
(3)只要segment寫入OS cache,那就直接打開供search使用,不立即執行commit
數據寫入OS cache,並被打開供搜索的過程,叫做refresh,默認是每隔一秒refresh一次,也就是說,每隔一秒就會將buffer中的數據寫入OS cache中,寫入一個新的index segment file。所以ES是近實時的,數據寫入到可以被搜索,默認是1秒。
一般不用修改,讓ES自己搞定就好了,要修改的話,通過refresh_interval參數即可
格式:

寫入流程的實現 durability可靠存儲(translog,flush)

最終流程:

1)數據寫入buffer緩存和translog日志文件
(2)每隔一秒,buffer中的數據被寫入新的segment file,並進入os cache,此時segment被打開並供search使用
(3)buffer被清空
(4)重復1~3,新的segment不斷添加,buffer不斷被清空,而translog中的數據不斷累加
(5)當translog長度達到一定程度的時候,commit操作發生
    (5.1)buffer中的所有數據,寫入一個新的segment,並寫入os cache,打開供使用
    (5.2)buffer被清空
    (5.3)一個commit point被寫入磁盤,標明了所有的index segment
    (5.4)filesystem cache中的所有index segment file緩存數據,被fsync強制刷到磁盤上
    (5.5)現有的translog被清空,創建一個新的translog

translog

對Lucene的更改僅在Lucene提交期間持久保存到磁盤,這是一項相對昂貴的操作,因此無法在每次索引或刪除操作后執行。如果進程退出或硬件發生故障,Lucene將在一次提交之后和另一次提交之前發生的更改將從索引中刪除。

因為Lucene提交對於每個單獨的更改都執行起來太昂貴,所以每個分片副本還有一個事務日志,稱為與之關聯的translog。所有索引和刪除操作在由內部Lucene索引處理之后但在確認之前寫入translog。在發生崩潰的情況下,最新的已確認但尚未包含在上一個Lucene提交中的事務可以在分片恢復時從translog中恢復。

Elasticsearch flush是執行Lucene提交並啟動新的translog的過程。在后台自動執行刷新以確保translog不會變得太大,這將使得在恢復期間重放其操作需要相當長的時間。手動執行刷新的能力也通過API公開,盡管很少需要。

translog設置

translog中的數據僅在fsync編輯和提交translog時持久保存到磁盤 。如果發生硬件故障,自上次translog提交以來寫入的任何數據都將丟失。

默認情況下,fsync如果index.translog.durability設置為async或request 在每個索引,刪除, 更新或 批量請求結束時設置為(默認),則Elasticsearch會每隔5秒提交一次translog 。更確切地說,如果設置為request,則fsync在主數據庫和每個已分配的副本服務器上成功編輯和提交translog之后,Elasticsearch將僅向客戶端報告索引,刪除,更新或批量請求的成功 。

以下可動態更新的每索引設置控制translog的行為:

index.translog.sync_interval
    fsync無論寫入操作 如何,translog都經常被寫入磁盤並提交。默認為5s。小於的值100ms是不允許的。
index.translog.durability
    是否fsync在每個索引,刪除,更新或批量請求之后提交translog。此設置接受以下參數:
        request
        (默認)fsync並在每個請求后提交。如果發生硬件故障,所有已確認的寫入都已提交到磁盤。
        async
        fsync並在每個背景中提交sync_interval。如果發生硬件故障,將丟棄自上次自動提交以來的所有已確認寫入。
index.translog.flush_threshold_size
    translog存儲尚未安全保存在Lucene中的所有操作(即,不是Lucene提交點的一部分)。盡管這些操作可用於
    讀取,但如果要關閉並且必須恢復,則需要重新編制索引。此設置控制這些操作的最大總大小,以防止恢復時間
    過長。達到最大大小后,將發生刷新,生成新的Lucene提交點。默認為512mb。
index.translog.retention.size
    要保留的translog文件的總大小。保留更多的translog文件會增加在恢復副本時執行基於同步操作的機會。如
    果translog文件不足,副本恢復將回退到基於文件的同步。默認為512mb
index.translog.retention.age
    保留translog文件的最長持續時間。默認為12h。
PUT /my_index/_settings
{
    "index.translog.durability": "async",
    "index.translog.sync_interval": "5s"
}

圖示如下:

數據恢復

假設os cache中囤積了一些數據,但是此時不巧,宕機了,os cache中的數據全部丟失,那么我們怎么進行數據恢復呢?
我們知道寫doc的時候也會寫入translog,那么translog就存儲了上一次flush直到現在最近的數據變更記錄。機器被重啟之后,disk上的數據並沒有丟失,此時就會將translog文件中的變更記錄進行回收,重新執行之前的各種操作,在buffer中執行,在重新刷一個一個的segment到os cache中,等待下一次commit發生即可。

海量磁盤文件的合並(segment merge,optimize)

每秒一個segment file,會導致文件過多,而且每次search都要搜索所有的segment,很耗時。所以在Elasticsearch內部會默認在后台執行segment merge操作(forcemerge),在merge的時候,被標記為deleted的document也會被徹底物理刪除掉。
每次merge的操作流程:
(1)選擇一些有相似大小的segment,merge成一個大的segment
(2)將新的segment flush到磁盤上去
(3)寫一個新的commit point,包括了新的segment,並且排除舊的那些segment
(4)將新的segment打開供搜索
(5)將舊的segment刪除 

POST /my_index/_optimize?max_num_segments=1盡量不要手動執行,讓它自動默認執行就可以了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM