引言
很多認爲Elasticsearch(以下簡稱ES),同一個分片的主分片和副本分片文檔數量肯定是樣的,數據大小也是一樣的。
這個其實值說對了一半,文檔數量是一樣的沒錯,但是數據大小不一定一樣。
產生這種現象的原因在於,主分片和副本分片的segment
數量可能不一樣。
正文
我們來看個示例。
以下的示例測試環境是ES 7.1.0版本
先插入4個文檔,
PUT my_blog/_doc/1
{
"title" : "blog1",
"content" : "this is blog1"
}
PUT my_blog/_doc/2
{
"title" : "blog2",
"content" : "this is blog2"
}
PUT my_blog/_doc/3
{
"title" : "blog3",
"content" : "this is blog3"
}
PUT my_blog/_doc/4
{
"title" : "blog4",
"content" : "this is blog4"
}
然後使用cat/shards
命令看下索引的分片信息,
GET _cat/shards/my_blog?v
結果如下圖
可以很清楚的看到,主分片和副本分片雖然文檔數量都是4,但是大小一個是15.7KB,一個是11.9KB。前面說了原因,是因爲主副分片中的segment數量不一樣導致的。我們來證實下。
使用cat/segment
命令來查看分片的segment信息,
GET _cat/segments/my_blog?v
結果如下圖
從結果中可以很明顯看出副本分片上的segment數量比主分片少了一個。這就是造成數據大小不一樣的“真兇”。
通常情況下,這種不一致並沒有什麼影響。ES會幫我們自動處理好分片上segment的數量。當然我們也可以通過ES的force merge
命令,強制把分片上的segment合併成指定的數量。
POST my_blog/_forcemerge?max_num_segments=1
max_num_segments
參數用來指定最終要合到的segment數量。
通過上面這個命令,我們強制索引合併segment到一個。然後再次用cat/segment
看下分片信息,
這樣我們的主副分片都只有一個segment了。大小自然是一樣的。
知識延伸
ES在寫入(index)數據的時候,是先寫入到緩存中。這時候數據還不能被搜索到。默認情況下ES每隔1秒會執行refresh
操作,從內存buffer中將數據寫入os cache(操作系統的內存),產生一個segment file文件。同時建立倒排索引,這個時候文檔是可以被搜索到的。
每次refresh都會生成一個新的segment,那麼segment的數量很快就會爆炸。另外就是每次搜索請求都必須訪問segment,理論上segment越多,搜索請求就會變的越慢。
ES有一個後臺進程專門負責segment的合併,它會把小segments合併成更大的segments。這個merge
操作大部分時候我們並不需要關心,ES自動處理什麼時候merge。只要不影響查詢性能,我們也不需要關係分片上有多少個segment。
不過對於一些業務場景,索引是按照天,周,或者月建立的,如果一些老的索引已經停止寫入或者更新,我們可以通過執行一次force merge
來強制該索引合併到一個大的segment
上,提高搜索的效率。