作者 | 蔡柱梁
審校 | 重樓
目錄
精通ES,這一篇就夠了
目標(biāo)
前言
1 ES 的分布式設(shè)計(jì)
1.1 集群添加節(jié)點(diǎn)和移除節(jié)點(diǎn)
2 ES 的讀寫(xiě)
2.1 文檔
2.2 一個(gè)文檔寫(xiě)入到一個(gè)分片中
2.3 使文本可被搜索
2.3.1 動(dòng)態(tài)更新索引
2.3.2 準(zhǔn)實(shí)時(shí)搜索
2.3.3 持久化變更
2.3.4 段合并
2.4 取回文檔(讀文檔)
2.4.1 取回單個(gè)文檔
2.4.2 分布式查詢(xún)
2.4.3 深度分頁(yè)
3 管理和部署
3.1 如何合理設(shè)置分片數(shù)
3.2 擴(kuò)容
3.3 推遲分片分配
3.4 部署
3.4.1 上生產(chǎn)前應(yīng)該要注意的事項(xiàng)
3.4.2 滾動(dòng)重啟
3.4.3 備份集群
3.4.4 從快照恢復(fù)
4 總結(jié)
作者介紹
目標(biāo)
1.了解 ES 的分布式設(shè)計(jì)
2.了解 ES 的讀寫(xiě)
3.了解 ES 的管理和部署
前言
本文圖片大多來(lái)自官網(wǎng),其余為作者作圖。ES 的官網(wǎng)其實(shí)介紹的很詳細(xì),但是很少人將它整理出來(lái)。我這里整理了出來(lái),并加上了自己的看法,希望可以和大家一起深入學(xué)習(xí)ES。
參考文檔:??Elasticsearch 7.17??
1 ES 的分布式設(shè)計(jì)
ES 天生就是分布式的,并且在設(shè)計(jì)時(shí)屏蔽了分布式的復(fù)雜性,可以橫向擴(kuò)展至數(shù)百(甚至數(shù)千)的服務(wù)器節(jié)點(diǎn),同時(shí)可以處理PB級(jí)數(shù)據(jù)。
我們先來(lái)了解可以處理的一些事情:
- 分配文檔到不同的容器或分片中,文檔可以?xún)?chǔ)存在一個(gè)或多個(gè)節(jié)點(diǎn)中
- 按集群節(jié)點(diǎn)來(lái)均衡分配這些分片,從而對(duì)索引和搜索過(guò)程進(jìn)行負(fù)載均衡
- 復(fù)制每個(gè)分片以支持?jǐn)?shù)據(jù)冗余,從而防止硬件故障導(dǎo)致的數(shù)據(jù)丟失
- 將集群中任一節(jié)點(diǎn)的請(qǐng)求路由到存有相關(guān)數(shù)據(jù)的節(jié)點(diǎn)
- 集群擴(kuò)容時(shí)無(wú)縫整合新節(jié)點(diǎn),重新分配分片以便從離群節(jié)點(diǎn)恢復(fù)接下來(lái),我們來(lái)看下集群中一些重要的概念:
- 分片
分片是 ES 實(shí)際存儲(chǔ)數(shù)據(jù)的地方,我們都知道 ES 是使用 Java 語(yǔ)言實(shí)現(xiàn)的,而它的搜索的底層是基于 Lucene 實(shí)現(xiàn)的,而每一個(gè)分片就是一個(gè) Lucene 實(shí)例。在 Elasticsearch 6.x 以及之前的版本,每一個(gè)索引創(chuàng)建時(shí)默認(rèn)是 5 個(gè)分片的,在 Elasticsearc 7.0 開(kāi)始默認(rèn)是 1 個(gè)分片,即:
- 節(jié)點(diǎn)角色(這里列出一部分角色,更多請(qǐng)參考:??Elasticsearch-Node??)
– master
主節(jié)點(diǎn)是集群中的控制節(jié)點(diǎn),主要負(fù)責(zé)管理和維護(hù)集群的元數(shù)據(jù)(如索引、映射、分片分配等),并且負(fù)責(zé)選舉和維護(hù)集群中的主分片。每個(gè) ES 集群只有一個(gè) Master 節(jié)點(diǎn),但是如果 Master 節(jié)點(diǎn)宕機(jī),集群會(huì)通過(guò)選舉機(jī)制重新選舉一個(gè)新的 Master 節(jié)點(diǎn)。
– data
數(shù)據(jù)節(jié)點(diǎn)持有包含你所索引的文檔的分片。數(shù)據(jù)節(jié)點(diǎn)處理與數(shù)據(jù)有關(guān)的操作,如CRUD、搜索和聚合。這些操作是I/O、內(nèi)存和CPU密集型的。監(jiān)控這些資源是很重要的,如果它們過(guò)載了,可以增加更多的數(shù)據(jù)節(jié)點(diǎn)。擁有專(zhuān)用數(shù)據(jù)節(jié)點(diǎn)的主要好處是 master 和 data 角色分離。
– Coordinating node
協(xié)調(diào)節(jié)點(diǎn)是一種特殊的節(jié)點(diǎn)類(lèi)型,它主要負(fù)責(zé)協(xié)調(diào)集群中的各個(gè)節(jié)點(diǎn)之間的通信和任務(wù)分配,不參與數(shù)據(jù)的存儲(chǔ)和處理。需要注意的是,協(xié)調(diào)節(jié)點(diǎn)本身不存儲(chǔ)數(shù)據(jù),因此它們可以在任何節(jié)點(diǎn)上運(yùn)行(即任何節(jié)點(diǎn)都可以成為協(xié)調(diào)節(jié)點(diǎn)),并且可以隨時(shí)添加或刪除。通過(guò)將協(xié)調(diào)節(jié)點(diǎn)與數(shù)據(jù)節(jié)點(diǎn)分開(kāi),可以實(shí)現(xiàn)更好的性能和可伸縮性,同時(shí)保證集群的穩(wěn)定性和可靠性,但是不建議過(guò)多。因?yàn)? master 節(jié)點(diǎn)需要維護(hù)集群中的節(jié)點(diǎn),如果數(shù)量過(guò)多,會(huì)給 master 造成過(guò)多的負(fù)擔(dān),從而影響性能。具體作用如下:
1.路由請(qǐng)求
協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)處理集群中的路由請(qǐng)求,即將請(qǐng)求路由到正確的節(jié)點(diǎn)上進(jìn)行處理。例如,當(dāng)一個(gè)搜索請(qǐng)求被發(fā)送到集群時(shí),協(xié)調(diào)節(jié)點(diǎn)會(huì)確定哪些分片需要被搜索,并將請(qǐng)求路由到包含這些分片的節(jié)點(diǎn)上進(jìn)行處理。
2.分配任務(wù)
協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)分配各種任務(wù)到集群中的節(jié)點(diǎn)上進(jìn)行處理,例如分片的重新分配、節(jié)點(diǎn)的加入和移除等。
3.監(jiān)控集群
協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)監(jiān)控集群中各個(gè)節(jié)點(diǎn)的狀態(tài)和健康情況,并對(duì)集群中的故障進(jìn)行處理。例如,當(dāng)一個(gè)節(jié)點(diǎn)宕機(jī)時(shí),協(xié)調(diào)節(jié)點(diǎn)會(huì)負(fù)責(zé)將該節(jié)點(diǎn)上的分片重新分配到其他節(jié)點(diǎn)上。
- 管理索引和映射(這里和 master 不同,master 是維護(hù)元數(shù)據(jù),而這里管理的是行為)
協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)管理集群中的索引和映射,例如創(chuàng)建和刪除索引、修改映射等。
- Transport client(傳輸客戶(hù)端)
輕量級(jí)的傳輸客戶(hù)端可以將請(qǐng)求發(fā)送到遠(yuǎn)程集群。它本身不加入集群,但是它可以將請(qǐng)求轉(zhuǎn)發(fā)到集群中的一個(gè)節(jié)點(diǎn)上。
- Node client(節(jié)點(diǎn)客戶(hù)端)
節(jié)點(diǎn)客戶(hù)端作為一個(gè)非數(shù)據(jù)節(jié)點(diǎn)加入到本地集群中。換句話說(shuō),它本身不保存任何數(shù)據(jù),但是它知道數(shù)據(jù)在集群中的哪個(gè)節(jié)點(diǎn)中,并且可以把請(qǐng)求轉(zhuǎn)發(fā)到正確的節(jié)點(diǎn)。
1.1 集群添加節(jié)點(diǎn)和移除節(jié)點(diǎn)
當(dāng)配置了同樣的cluster.name: my-cluster的節(jié)點(diǎn)被發(fā)現(xiàn)后或者被移出集群,集群會(huì)對(duì)分片進(jìn)行再平衡。
1)假設(shè)當(dāng)前我集群中只有一個(gè)節(jié)點(diǎn),該節(jié)點(diǎn)只有一個(gè) index,設(shè)置了 3 個(gè)分片,具體如下:
這時(shí)副分片是沒(méi)有意義的,所以只有主分片,假設(shè)目前有三個(gè)分片,如下圖:

2)假如此時(shí),我添加了一個(gè)節(jié)點(diǎn),集群將會(huì)為這些主分片創(chuàng)建副本,并分開(kāi)存放(高可用,需要做到備份容災(zāi),主分片與自己的備份不應(yīng)該在同一節(jié)點(diǎn)),
假設(shè)只有一個(gè)副分片,如下圖:

3)我們搭建最小集群,節(jié)點(diǎn)個(gè)數(shù)應(yīng)該為 3 個(gè)(防止網(wǎng)絡(luò)分區(qū)問(wèn)題)。因此,再增加一個(gè)節(jié)點(diǎn),分片將發(fā)生再平衡

4)這時(shí) node 1 失聯(lián)了,重現(xiàn)選主 node 2 作為 master 節(jié)點(diǎn),分片也會(huì)發(fā)生再平衡

2 ES 的讀寫(xiě)
ES 的讀寫(xiě),其實(shí)就是創(chuàng)建文檔和讀取文檔的操作。因此,要了解這些操作,我們就要先了解文檔。
2.1 文檔
下面了解一些關(guān)于文檔的概念:
- 索引文檔
所謂的索引文檔就是指 通過(guò)使用 index API ,文檔可以被 索引 —— 存儲(chǔ)和使文檔可被搜索。使文檔可以被搜索,其實(shí)就是構(gòu)建倒排索引。
- 文檔ID
ES 的每一個(gè)文檔都有一個(gè) ID,這個(gè) ID 要么就是自己創(chuàng)建文檔時(shí)提供,要么讓 ES 自己生成,并且 index_name + id 可以確定唯一的文檔(如果是 ES8 之前,則是 index_name + type + id 確定唯一的文檔)。
- 版本號(hào)
在 ES 中每個(gè)文檔都有一個(gè)版本號(hào),每當(dāng)對(duì)文檔進(jìn)行修改時(shí)(包括刪除),版本號(hào)的值就會(huì)遞增,版本號(hào)用于處理并發(fā)沖突的場(chǎng)景。
上面提到了刪除文檔時(shí),版本號(hào)也會(huì)遞增,這是為什么呢?
因?yàn)樵?ES 中,文檔是不可變的,不能修改它們。因此,如果我們需要對(duì)一個(gè)文檔進(jìn)行修改時(shí),那只能 重建索引 或者 進(jìn)行替換。而刪除只是更新文檔的一種特殊情況而已。不管對(duì)文檔進(jìn)行修改還是刪除,版本號(hào)遞增后,我們只能讀取到最新的文檔。舊的文檔會(huì)被標(biāo)記為已刪除,但是不會(huì)被馬上物理刪除。
修改文檔的過(guò)程:
- 從舊文檔構(gòu)建
- 更改該
- 刪除舊文檔
- 索引一個(gè)新文檔
2.2 一個(gè)文檔寫(xiě)入到一個(gè)分片中
一個(gè)文檔寫(xiě)入到一個(gè)分片中,又可以稱(chēng)為路由一個(gè)文檔到一個(gè)分片。在說(shuō)路由之前,我們先梳理下節(jié)點(diǎn),分片,index,文檔之間的關(guān)系:
- index 是具有同一特征的文檔的集合
- 我們?cè)趧?chuàng)建 index 時(shí)需要指定分片數(shù)
- 一個(gè)分片就是一個(gè) Lucene 實(shí)例,而 Lucene 實(shí)例運(yùn)行在 ES 節(jié)點(diǎn)上,一個(gè)節(jié)點(diǎn)允許有多個(gè)分片
下圖表示一個(gè)擁有 3 個(gè)節(jié)點(diǎn)的小集群,一共有 2 個(gè) index,每個(gè) index 有 3 個(gè)分片(指的是有 3 個(gè)主分片,每個(gè)主分片有 1 個(gè)副本)。

假設(shè)有一個(gè)集群由三個(gè)節(jié)點(diǎn)組成。 它包含一個(gè)叫blogs的索引,有兩個(gè)主分片,每個(gè)主分片有兩個(gè)副本分片,具體如下(這是官網(wǎng)的例子):

假設(shè)現(xiàn)有要寫(xiě)入一個(gè)文檔到 blogs,那么這個(gè)過(guò)程是怎樣的呢?
首先要知道只有主分片具有處理寫(xiě)請(qǐng)求的能力,副本只提供讀的能力,然后才是路由一個(gè)文檔到一個(gè)主分片中存儲(chǔ)起來(lái)。
至于是怎么路由的,請(qǐng)看下面的路由公式:
shard = hash(routing) % number_of_primary_shards
- routing
routing 默認(rèn)是文檔 ID,也可以設(shè)置成一個(gè)自定義的值
- number_of_primary_shards
number_of_primary_shards 指的是主分片的數(shù)量
這也是為什么我們確定好 index 的分片數(shù)后不能修改的原因,如果我們需要擴(kuò)容,只能通過(guò)重建索引等手段來(lái)進(jìn)行水平擴(kuò)容了。
新建、索引(構(gòu)建倒排索引)和刪除 請(qǐng)求都是 寫(xiě) 操作, 必須在主分片上面完成之后才能被復(fù)制到相關(guān)的副本分片,如下圖所示:

具體步驟如下:
- 客戶(hù)端向任意節(jié)點(diǎn)發(fā)出寫(xiě)請(qǐng)求(圖示例寫(xiě)著請(qǐng)求的是 node 1)
- node 1 通過(guò)路由算法確定文檔應(yīng)該分配到分片 P0 上,隨后將請(qǐng)求轉(zhuǎn)發(fā)到 node 3
- 主分片 P0 完成寫(xiě)請(qǐng)求后,轉(zhuǎn)發(fā)請(qǐng)求給 node 1 和 node 2,讓它們的副本分片 R0 完成數(shù)據(jù)同步
- 等到所有副本報(bào)告同步成功后,node 3 將向協(xié)調(diào)節(jié)點(diǎn)報(bào)告成功(這里的協(xié)調(diào)節(jié)點(diǎn)就是 node 1),協(xié)調(diào)節(jié)點(diǎn)向客戶(hù)端報(bào)告成功
2.3 使文本可被搜索?
上面說(shuō)了一個(gè)文檔寫(xiě)入的流程,但是文檔是一下就寫(xiě)到磁盤(pán)嗎?是一寫(xiě)入就立馬可以被搜索嗎?這些問(wèn)題會(huì)在這一節(jié)中給出答案。
我們知道最早開(kāi)始學(xué)全文搜索查詢(xún)到對(duì)應(yīng)的信息。ES 也是如此,那么如何實(shí)現(xiàn)全文搜索呢?前面也提到了 ES 采用的是倒排索引,我在《ES入門(mén)》有寫(xiě)倒排索引的原理,這里就不累述了。
當(dāng)討論倒排索引時(shí),我們會(huì)談到 文檔 標(biāo)引,因?yàn)闅v史原因,倒排索引被用來(lái)對(duì)整個(gè)非結(jié)構(gòu)化文本文檔進(jìn)行標(biāo)引。 ES 中的 文檔 是有字段和值的結(jié)構(gòu)化 JSON 文檔。事實(shí)上,在 JSON 文檔中, 每個(gè)被索引的字段都有自己的倒排索引。
早期的全文檢索會(huì)為整個(gè)文檔集合建立一個(gè)很大的倒排索引并將其寫(xiě)入到磁盤(pán)。一旦新的索引就緒,舊的就會(huì)被其替換,這樣最近的變化便可以被檢索到。倒排索引被寫(xiě)入磁盤(pán)后是不可改變的(我們稱(chēng)之為倒排索引具有不變性)。這個(gè)特性的好處有:
- 不需要鎖
不變性意味著不怕高并發(fā),所以不需要鎖。
- 極大提高了 ES 的性能
一旦索引被讀入內(nèi)核的文件系統(tǒng)緩存,便會(huì)一直在那。由于不變性,只要緩存還有足夠的空間,那么大部分請(qǐng)求會(huì)直接請(qǐng)求內(nèi)存。這就很大程度上提升了性能。
- 其他緩存(如 filter)在索引生命周期內(nèi)始終有效
因?yàn)閿?shù)據(jù)是不會(huì)變的(索引都沒(méi)變,數(shù)據(jù)當(dāng)然沒(méi)變)。
- 減少 I/O 和需要被緩存到內(nèi)存的索引的使用量
因?yàn)椴蛔冃?,所以可以在?duì)單個(gè)大的倒排索引寫(xiě)入時(shí)進(jìn)行數(shù)據(jù)壓縮。
當(dāng)然,有好處,就會(huì)有壞處:我要新增一個(gè)文檔,就需要重新構(gòu)建一個(gè)新的索引,因?yàn)榕f的索引是不可變的。這種設(shè)計(jì)會(huì)對(duì)索引包含的數(shù)據(jù)量和可被更新的頻率有極大的限制。
2.3.1 動(dòng)態(tài)更新索引
動(dòng)態(tài)更新索引指的是增量操作文檔后,會(huì)對(duì)索引進(jìn)行補(bǔ)充索引來(lái)反映新的修改。
上面說(shuō)了倒排索引的不變性的好處與壞處,那么如何在保留不變性的前提下實(shí)現(xiàn)倒排索引的更新呢?答案是:用更多的索引。
具體方法如下:
當(dāng)發(fā)生了一些操作導(dǎo)致需要更新倒排索引,ES 不會(huì)直接更新索引,而是通過(guò)增加新的補(bǔ)充索引來(lái)反映最新的修改(也就是所謂的用更多索引)。那么要查詢(xún)時(shí),關(guān)于這個(gè) index 的索引這么多,怎么用呢?也簡(jiǎn)單,就是按創(chuàng)建時(shí)間(升序)來(lái)遍歷這些索引查詢(xún)文檔,最后對(duì)查詢(xún)結(jié)果進(jìn)行合并。
ES 基于上面的理論,引入了 按段搜索的概念,每一個(gè)段都是一個(gè)倒排索引,但是索引在段的集合外,還有一個(gè)概念提交點(diǎn)。在提交點(diǎn)內(nèi)的段才是可見(jiàn)的,它包含的文檔才是可被搜索的。
到這里,很容易將文檔的集合——index(索引) 和 倒排索引(索引,分片中的段)搞混,也不知道它們與分片(Lucene 實(shí)例)是一個(gè)怎樣的關(guān)系。因此,這里有必要再梳理下它們的關(guān)系:一個(gè) index可以有多個(gè)分片,而一個(gè)分片中也可以有多個(gè)段用于搜索文檔。
下面用一個(gè)例子說(shuō)明動(dòng)態(tài)更新索引是如何在保留倒排索引的不變性的同時(shí)實(shí)現(xiàn)索引更新,從而讓新增的文檔可被搜索的:
1)假設(shè)現(xiàn)在有一個(gè) Lucene 索引當(dāng)前包含了一個(gè)提交點(diǎn)和三個(gè)段

2)現(xiàn)在我們新增了一個(gè)新的文檔。因?yàn)橹暗乃饕遣蛔兊?,所?ES 會(huì)進(jìn)行補(bǔ)充索引,具體如下:
2.1)新文檔被收集到內(nèi)存索引緩存

2.2)不時(shí)地提交緩存
完整的提交緩存流程如下:
- 在磁盤(pán)上寫(xiě)入一個(gè)追加的新段(也就是上面說(shuō)的補(bǔ)充索引)
- 在磁盤(pán)上寫(xiě)入一個(gè)新的提交點(diǎn),該提交點(diǎn)包含新的段
經(jīng)過(guò)上面兩步后得到下圖:

- 所有在文件系統(tǒng)緩存中等待的寫(xiě)入都刷新到磁盤(pán),以確保它們被寫(xiě)入物理文件(通過(guò) fsync 來(lái) flush,這樣在斷電的時(shí)候就不會(huì)丟失數(shù)據(jù))
2.3)新的段被開(kāi)啟,讓它包含的文檔可以被搜索
2.4)內(nèi)存緩存被清空,等待接收新的文檔

上面說(shuō)了新增文檔導(dǎo)致索引更新的情況,那么修改和刪除文檔呢?
因?yàn)槎问遣蛔兊?,所以文檔變更導(dǎo)致的索引變化是沒(méi)法在舊索引體現(xiàn)的。因此,每個(gè)提交點(diǎn)都會(huì)有一個(gè) .del 文件,這個(gè)文件記錄著這些過(guò)時(shí)的文檔。不管是修改還是刪除都會(huì)被標(biāo)記成刪除,但是沒(méi)有真的從磁盤(pán)上刪掉。當(dāng)我們遍歷段時(shí),這些文檔其實(shí)還是會(huì)被檢索出來(lái)的,只是 ES 做結(jié)果合并時(shí)會(huì)過(guò)濾這部分被標(biāo)記為刪除的文檔。
2.3.2 準(zhǔn)實(shí)時(shí)搜索
ES 從數(shù)據(jù)寫(xiě)入到可被搜索不是實(shí)時(shí)的,而是有一定時(shí)延的,所以無(wú)法接受這一點(diǎn)的場(chǎng)景可能就不適合使用 ES 了。
2.3.1 說(shuō)到了動(dòng)態(tài)更新索引 是如何在保留不變性的前提下更新索引,讓新的文檔可被搜索的,但是這方案中的提交階段需要 fsync 來(lái)確保段被物理性寫(xiě)入磁盤(pán)。如果每一次索引一個(gè)文檔都要執(zhí)行 fsync 的話,那么會(huì)對(duì)性能造成很大的影響。在 ES 和磁盤(pán)之間是文件系統(tǒng)緩存,為了提升性能, ES 做了一些列優(yōu)化使得 ES 可以近實(shí)時(shí)搜索。
下面用一個(gè)例子說(shuō)明 ES 的優(yōu)化(還是用 “有一個(gè) Lucene 索引當(dāng)前包含了一個(gè)提交點(diǎn)和三個(gè)段” 這個(gè)前提):
1)新文檔被寫(xiě)入了內(nèi)存索引緩存中,如下圖:

2)新文檔被寫(xiě)入一個(gè)新的段中,該段被寫(xiě)入了文件系統(tǒng)緩存(即只是寫(xiě)入磁盤(pán),但是沒(méi)有用 fsync 來(lái) flush)。Lucene 允許這個(gè)新段被寫(xiě)入和打開(kāi),使該段可以被搜索。

上面提到的 寫(xiě)入和打開(kāi)一個(gè)新段的過(guò)程 就是 refresh,ES 提供 refresh API,我們可以手動(dòng)觸發(fā),不手動(dòng)觸發(fā)的話,默認(rèn)是每個(gè)分片每秒自動(dòng)刷新一次。因此,我們說(shuō) ES 是準(zhǔn)實(shí)時(shí)搜索。將 “使新的段可以被搜索” 拆得更細(xì)一點(diǎn)的話,具體步驟如下:
- 新文檔被寫(xiě)入一個(gè)新的段中
- 該段被寫(xiě)入文件系統(tǒng)緩存并打開(kāi)(refresh)
- 同步數(shù)據(jù)到副本分片(如果有的話)
- 更新集群狀態(tài)(如果是集群的話)
master更新集群元數(shù)據(jù)
下面是對(duì)上面這些過(guò)程,幫助提升性能的一些思路:
- refresh 的時(shí)間
合理調(diào)整 refresh 頻率或者使用讀寫(xiě)性能更強(qiáng)大的 SSD 硬盤(pán)。
- 同步數(shù)據(jù)的時(shí)間
同步數(shù)據(jù)受網(wǎng)絡(luò),物理設(shè)備的狀態(tài),集群狀態(tài),副分片數(shù)量等因素影響,可以從這幾個(gè)角度考慮提升。
- master更新集群元數(shù)據(jù)的時(shí)間
這個(gè)受集群的大小和復(fù)雜程度影響,所以要合理搭建集群。
2.3.3 持久化變更
2.3.2說(shuō)到為了實(shí)現(xiàn)準(zhǔn)實(shí)時(shí)搜索完全拋棄了2.3.1也提到了動(dòng)態(tài)更新索引最近一次完整的提交會(huì)將段刷到磁盤(pán),但是這個(gè)提交點(diǎn)之后的操作呢?無(wú)法保證了,這樣就可能會(huì)出現(xiàn)數(shù)據(jù)丟失。
為了保證 ES 的可靠性,需要確保數(shù)據(jù)變化被持久化到磁盤(pán),為此 ES 增加了一個(gè) translog(事務(wù)日志,類(lèi)似 MySQL 的 redo 日志)。整個(gè)流程如下:
1)一個(gè)新文檔被索引之后,就會(huì)被添加到內(nèi)存緩沖區(qū),并且相應(yīng)的文檔操作被寫(xiě)入到 translog(順序IO)

2)refresh(分片每秒被 refresh 一次),具體操作如下:
- 內(nèi)存緩沖區(qū)中的文檔被寫(xiě)到一個(gè)新段中,且沒(méi)有進(jìn)行 fsync
- 新段被打開(kāi),使新段可以被搜索
打開(kāi)新段:
- 將新段加入到已有段的文件列表中,并且建立該段的倒排索引、文檔存儲(chǔ)和其他元數(shù)據(jù)
- 更新索引的內(nèi)存結(jié)構(gòu),包括倒排索引、字段信息、文檔數(shù)和大小等
- 內(nèi)存緩存區(qū)被清空

因?yàn)樗饕⑿聲?huì)觸發(fā) Lucene 的 SegmentReader 和 SegmentSearcher 的更新操作,使得新段可以被加入到搜索中,所以新段在刷新操作后可以被搜索。
3)這個(gè)進(jìn)程繼續(xù)工作,更多的文檔被添加到內(nèi)存緩沖區(qū)和追加到事務(wù)日志

4)不定時(shí)對(duì)索引 flush(分片每 30 分鐘被 flush一次或者 translog 過(guò)大的時(shí)候也會(huì)觸發(fā)),段被全量提交,并且事務(wù)日志被清空,具體操作如下:
- 內(nèi)存緩沖區(qū)中的所有文檔都被寫(xiě)入一個(gè)新段
- 緩沖區(qū)被清空
- 一個(gè)提交點(diǎn)被寫(xiě)入磁盤(pán)
- 文件系統(tǒng)緩存通過(guò) fsync 被 flush
- 老的 translog 被刪除

translog 提供所有還沒(méi)有被刷到磁盤(pán)的操作的一個(gè)持久化記錄。當(dāng) ES 啟動(dòng)的時(shí)候, 它會(huì)從磁盤(pán)中使用最后一個(gè)提交點(diǎn)去恢復(fù)已知的段,并且會(huì)重放 translog 中所有在最后一次提交后發(fā)生的變更操作。
這種執(zhí)行一個(gè)提交并且截?cái)?translog 的行為在 ES 中被稱(chēng)為一次 flush。分片每 30 分鐘被自動(dòng) flush 一次或者 translog 太大的時(shí)候也會(huì)觸發(fā)。具體可看 Translog。我們也能手動(dòng)觸發(fā) flush,具體請(qǐng)看 Flush API。
2.3.4 段合并
段合并的時(shí)候會(huì)將那些舊的已刪除文檔從文件系統(tǒng)中清除,被刪除的文檔(或被更新文檔的舊版本)不會(huì)被拷貝到新的大段中。
默認(rèn)每秒一次刷新,會(huì)導(dǎo)致段的數(shù)量在短時(shí)間能激增,但是如果降低 refresh 的頻率,對(duì)于一些實(shí)時(shí)性要求較高的場(chǎng)景又不能滿足。而且,段數(shù)量過(guò)多也會(huì)造成各種各樣的問(wèn)題:每一個(gè)段都會(huì)消耗文件句柄、內(nèi)存和CPU運(yùn)行周期;更重要的是,每個(gè)搜索請(qǐng)求都必須輪流檢查每個(gè)段;所以段越多,搜索也就越慢。ES 通過(guò)在后臺(tái)進(jìn)行 段合并 來(lái)解決這個(gè)問(wèn)題。啟動(dòng) 段合并 不需要我們做任何事,ES 進(jìn)行索引和搜索時(shí)會(huì)自動(dòng)進(jìn)行。
假設(shè)現(xiàn)在要進(jìn)行段合并了:
1)合并進(jìn)程選擇大小相似的小段并且將他們合并到更大的段中(這樣就不會(huì)中斷索引和搜索)。如下圖所示:

2)一旦合并結(jié)束,老的段被刪除

合并大的段需要消耗大量的 I/O 和 CPU 資源,如果任其發(fā)展會(huì)影響搜索性能。ES 在默認(rèn)情況下會(huì)對(duì)合并流程進(jìn)行資源限制,所以搜索仍然有足夠的資源很好地執(zhí)行。
?2.3.4.1 段合并建議
2.3.4 末尾說(shuō)到了 “合并大的段需要消耗大量的 I/O 和 CPU 資源”,但是合并是在后臺(tái)定期操作的。因?yàn)檫@些操作可能要很長(zhǎng)時(shí)間才能完成,尤其是比較大的段。這個(gè)通常來(lái)說(shuō)都沒(méi)問(wèn)題,因?yàn)榇笠?guī)模段合并的概率是很小的。不過(guò)有時(shí)候合并會(huì)拖累寫(xiě)入速率,如果這個(gè)真的發(fā)生了,ES 會(huì)自動(dòng)限制索引請(qǐng)求到單個(gè)線程里。這樣可以防止出現(xiàn) 段爆炸 問(wèn)題(即數(shù)以百計(jì)的段在被合并之前就生成出來(lái))。
ES 默認(rèn)設(shè)置在這塊比較保守:不希望搜索性能被后臺(tái)合并影響。不過(guò)有時(shí)候(尤其是 SSD,或者日志場(chǎng)景)限流閾值太低了。默認(rèn)值是 20 MB/s,對(duì)機(jī)械磁盤(pán)應(yīng)該是個(gè)不錯(cuò)的設(shè)置。
- 如果服務(wù)器用的是 SSD,可以考慮提高到 100–200 MB/s。測(cè)試驗(yàn)證對(duì)系統(tǒng)哪個(gè)值比較合適:
- 如果在做批量導(dǎo)入,完全不在意搜索,那么可以徹底關(guān)掉合并限流。這樣讓索引速度跑到你磁盤(pán)允許的極限:
最后,可以增加 index.translog.flush_threshold_size 設(shè)置,從默認(rèn)的 512 MB 到更大一些的值,比如 1 GB。這可以在一次清空觸發(fā)的時(shí)候,在事務(wù)日志里積累出更大的段。而通過(guò)構(gòu)建更大的段,清空的頻率變低,大段合并的頻率也變低。這一切合起來(lái)導(dǎo)致更少的磁盤(pán) I/O 開(kāi)銷(xiāo)和更好的索引速率。當(dāng)然,這會(huì)需要對(duì)應(yīng)量級(jí)的 heap 內(nèi)存用以積累更大的緩沖空間,調(diào)整這個(gè)設(shè)置的時(shí)候請(qǐng)記住這點(diǎn)。
不過(guò)一般對(duì)于中小公司的業(yè)務(wù)或者試探性的業(yè)務(wù)建議用默認(rèn)設(shè)置就好了,否則自己不是特別熟悉 ES 的情況下,容易讓 ES 性能下降又找不出原因。
2.3.4.2 科學(xué)的測(cè)試性能
2.3.4.1 有些設(shè)置給出的值是經(jīng)驗(yàn)值,但不適用所有公司。因此,真的要改默認(rèn)設(shè)置的話,性能測(cè)試很重要。下面給出一些方法論,如下:
- 在單個(gè)節(jié)點(diǎn)上,對(duì)單個(gè)分片,無(wú)副本的場(chǎng)景測(cè)試性能。
- 在 100% 默認(rèn)配置的情況下記錄性能結(jié)果,這樣就有了一個(gè)對(duì)比基線。
- 確保性能測(cè)試運(yùn)行足夠長(zhǎng)的時(shí)間(30 分鐘以上),這樣可以評(píng)估長(zhǎng)期性能,而不是短期的峰值或延遲。
一些事件(比如段合并,GC)不會(huì)立刻發(fā)生,所以性能概況會(huì)隨著時(shí)間繼續(xù)而改變的。
- 開(kāi)始在基線上逐一修改默認(rèn)值。
嚴(yán)格測(cè)試需要修改的配置,如果性能提升可以接受,保留這個(gè)配置項(xiàng),開(kāi)始下一項(xiàng)。
2.4 取回文檔(讀文檔)
關(guān)于讀請(qǐng)求需要知道:
- 在處理讀取請(qǐng)求時(shí),協(xié)調(diào)結(jié)點(diǎn)在每次請(qǐng)求的時(shí)候都會(huì)通過(guò)輪詢(xún)所有的副本分片來(lái)達(dá)到負(fù)載均衡。
- 在文檔被檢索時(shí),已經(jīng)被索引的文檔可能已經(jīng)存在于主分片上但是還沒(méi)有復(fù)制到副本分片。在這種情況下,副本分片可能會(huì)報(bào)告文檔不存在,但是主分片可能成功返回文檔。一旦索引請(qǐng)求成功返回給用戶(hù),文檔在主分片和副本分片都是可用的。
2.4.1 取回單個(gè)文檔
通過(guò)文檔 ID 查詢(xún)文檔。
以下是從主分片或者副本分片檢索文檔的步驟順序(官網(wǎng)例子):
- 客戶(hù)端向某個(gè)節(jié)點(diǎn)(假設(shè)現(xiàn)在是 Node 1) 發(fā)送獲取請(qǐng)求。
- 節(jié)點(diǎn)使用文檔的 _id 來(lái)確定文檔屬于哪個(gè)分片。
假設(shè)是屬于分片0,并應(yīng)該請(qǐng)求 Node 2 的 R0,這時(shí)會(huì)將請(qǐng)求轉(zhuǎn)發(fā)到 Node 2。
- Node 2 將文檔返回給 Node 1,然后將文檔返回給客戶(hù)端。
下面是上面步驟的流程圖:

2.4.2 分布式查詢(xún)
我們大多數(shù)時(shí)候都不是根據(jù)文檔 ID 查詢(xún)文檔,而是根據(jù)某些條件篩選做聚合查詢(xún)。這時(shí),我們就需要了解下分布式查詢(xún)是怎樣處理請(qǐng)求的了。整體上分為兩個(gè)階段:查詢(xún)階段 和 取回階段。
2.4.2.1 查詢(xún)階段
協(xié)調(diào)節(jié)點(diǎn)向各個(gè)分片發(fā)出查詢(xún)請(qǐng)求,每個(gè)分片(可能是主分片,也可能是副分片,但是不會(huì)重復(fù)分片)查詢(xún)出自己的結(jié)果并返回給協(xié)調(diào)節(jié)點(diǎn),協(xié)調(diào)節(jié)點(diǎn)合并所有結(jié)果并得到最終查詢(xún)結(jié)果。
下圖是客戶(hù)端的一次分布式查詢(xún)請(qǐng)求圖(以下圖為例子說(shuō)明查詢(xún)階段需要做的事情)

查詢(xún)階段包含以下三個(gè)步驟:
- 客戶(hù)端發(fā)送一個(gè) search 請(qǐng)求到 Node 3 (協(xié)調(diào)節(jié)點(diǎn)可以是任意節(jié)點(diǎn),這時(shí) Node 3 成為了協(xié)調(diào)節(jié)點(diǎn)), Node 3 會(huì)創(chuàng)建一個(gè)大小為 from + size 的空優(yōu)先隊(duì)列。
協(xié)調(diào)節(jié)點(diǎn)將在之后的請(qǐng)求中輪詢(xún)所有的分片來(lái)分?jǐn)傌?fù)載。
- Node 3 將查詢(xún)請(qǐng)求轉(zhuǎn)發(fā)到索引的每個(gè) 主分片/副分片 中。每個(gè)分片在本地執(zhí)行查詢(xún)并添加結(jié)果到大小為 from + size 的本地有序優(yōu)先隊(duì)列中。
- 每個(gè)分片返回各自?xún)?yōu)先隊(duì)列中所有文檔的 ID 和 排序值 給協(xié)調(diào)節(jié)點(diǎn),也就是 Node 3,它合并這些值到自己的優(yōu)先隊(duì)列中來(lái)產(chǎn)生一個(gè)全局排序后的結(jié)果列表。
2.4.2.2 取回階段
查詢(xún)階段得到的結(jié)果只是最終結(jié)果的文檔 ID,但是要返回給客戶(hù)端的需要是文檔,所以需要取回文檔這么一個(gè)動(dòng)作。
2.4.2.1 的例子的分布式搜索的取回階段的流程,大概如下圖:

下面是步驟解釋?zhuān)?/p>
- 協(xié)調(diào)節(jié)點(diǎn)辨別出哪些文檔需要被取回并向相關(guān)的分片提交多個(gè)
- 每個(gè)分片加載對(duì)應(yīng)文檔返回給協(xié)調(diào)節(jié)點(diǎn)
- 全部文檔取回之后,協(xié)調(diào)節(jié)點(diǎn)返回結(jié)果給客戶(hù)端
2.4.3 深度分頁(yè)
了解了分布式查詢(xún)后,相信大家都會(huì)有一個(gè)問(wèn)題:
分片要返回給協(xié)調(diào)節(jié)點(diǎn)from + size個(gè)結(jié)果,那么協(xié)調(diào)節(jié)點(diǎn)將會(huì)收到number_of_shards * (from + size)個(gè)結(jié)果,然后再排序。如果我要查第如果數(shù)據(jù)量更大,那么會(huì)占用多少
因此,我們要避免深度分頁(yè),如果真的無(wú)法避免,那么請(qǐng)使用??scroll??(Elasticsearch 7.x 開(kāi)始不再推薦使用 scroll)或者 search after。
3 管理和部署
3.1 如何合理設(shè)置分片數(shù)
我們知道每個(gè)原因??僧?dāng)公司大到一定規(guī)模或者老板覺(jué)得自己發(fā)展很好要求我們要預(yù)設(shè)一段時(shí)間內(nèi)可以承受的訪問(wèn)量時(shí),就不可能用默認(rèn)的分片數(shù)或者隨便設(shè)置了。
要注意的點(diǎn)如下:
- 硬件
索引的分片數(shù)量應(yīng)該與集群的可用硬件資源相匹配,特別是磁盤(pán)和內(nèi)存資源。如果分片數(shù)量太大,可能會(huì)導(dǎo)致磁盤(pán)空間不足或內(nèi)存不足,影響搜索性能。如果分片數(shù)量太少,可能會(huì)導(dǎo)致硬件資源的浪費(fèi)。
- 數(shù)據(jù)量
索引的分片數(shù)量應(yīng)該與數(shù)據(jù)量相匹配,特別是對(duì)于大型數(shù)據(jù)集。通常,建議每個(gè)分片至少包含幾十 GB 的數(shù)據(jù)。如果分片數(shù)量太多,可能會(huì)導(dǎo)致管理和查詢(xún)索引變得困難,如果分片數(shù)量太少,可能會(huì)導(dǎo)致搜索性能下降。
- 并發(fā)查詢(xún)
索引的分片數(shù)量應(yīng)該與集群中同時(shí)進(jìn)行的查詢(xún)數(shù)量相匹配。每個(gè)分片都需要處理查詢(xún)請(qǐng)求,并返回結(jié)果;如果分片數(shù)量太少,可能會(huì)導(dǎo)致查詢(xún)請(qǐng)求在隊(duì)列中排隊(duì)等待,影響查詢(xún)性能。
- 索引更新頻率
索引的分片數(shù)量應(yīng)該考慮索引的更新頻率,如果索引更新頻率很高,可能會(huì)導(dǎo)致更新操作在集群中的競(jìng)爭(zhēng),影響寫(xiě)入性能。
分片數(shù)建議不要超過(guò)節(jié)點(diǎn)數(shù),當(dāng)我們計(jì)算出分片數(shù)大于節(jié)點(diǎn)數(shù)時(shí),我們應(yīng)該增加節(jié)點(diǎn)。
因?yàn)榉制瑪?shù)超過(guò)了節(jié)點(diǎn)數(shù),同一個(gè)文檔的主分片有多個(gè)在同一節(jié)點(diǎn)會(huì)讓該節(jié)點(diǎn)負(fù)載過(guò)重,而且一旦該節(jié)點(diǎn)掛掉,會(huì)影響到多個(gè)分片的可用性。當(dāng)然,資金短缺的情況就沒(méi)辦法了,那這時(shí)建議每個(gè)節(jié)點(diǎn)分配到的分片數(shù)盡量一致。
具體數(shù)值應(yīng)該怎么定呢?
- 要盡量和生產(chǎn)中要使用的硬件資源,網(wǎng)絡(luò)資源保持一致,然后單節(jié)點(diǎn)單分片,然后進(jìn)行壓測(cè),逐漸增大數(shù)據(jù)量,看我們能接受的平均響應(yīng)值對(duì)應(yīng)的數(shù)據(jù)量是多少,假設(shè) 50 G。
- 再去看看我們實(shí)際業(yè)務(wù)場(chǎng)景預(yù)計(jì)需要支撐的數(shù)據(jù)量是多少(包括預(yù)留未來(lái) 3 年的預(yù)估值,如果業(yè)務(wù)給不出,就按照今年的值的 3 倍),然后除以 50,就是我們一個(gè)理論值的分片數(shù)了。
- 但是要考慮到 索引更新頻率 問(wèn)題,如果是文檔里面某個(gè)字段高頻更新導(dǎo)致的,考慮是否可以拆出來(lái);如果不行,那就得對(duì)這個(gè)理論值進(jìn)行實(shí)際壓測(cè),看看是否要減少分片數(shù)了。
3.2 擴(kuò)容
大多數(shù)的擴(kuò)容問(wèn)題可以通過(guò)添加節(jié)點(diǎn)來(lái)解決。但有一種資源是有限制的,因此值得我們認(rèn)真對(duì)待:集群狀態(tài)。
集群狀態(tài)是一種數(shù)據(jù)結(jié)構(gòu),貯存下列集群級(jí)別的信息:
- 集群級(jí)別的設(shè)置
- 集群中的節(jié)點(diǎn)
- 索引以及它們的設(shè)置、映射、分析器、預(yù)熱器(Warmers)和別名
- 與每個(gè)索引關(guān)聯(lián)的分片以及它們分配到的節(jié)點(diǎn)
集群狀態(tài)存在于集群中的每個(gè)節(jié)點(diǎn),包括客戶(hù)端節(jié)點(diǎn)。這就是為什么任何一個(gè)節(jié)點(diǎn)都可以將請(qǐng)求直接轉(zhuǎn)發(fā)至被請(qǐng)求數(shù)據(jù)的節(jié)點(diǎn)——每個(gè)節(jié)點(diǎn)都知道每個(gè)文檔應(yīng)該在哪里。
一旦某個(gè)索引要增加一個(gè)字段(數(shù)據(jù)結(jié)構(gòu)需要變化的情況),那么接收到這個(gè)請(qǐng)求的主分片所在的節(jié)點(diǎn)必須向 master 匯報(bào)(因?yàn)橹挥?master 可以修改集群狀態(tài))。然后,master 要將更改合并到集群狀態(tài)中,并向集群中所有節(jié)點(diǎn)發(fā)布一個(gè)新版本。請(qǐng)注意:集群狀態(tài)包括了映射!因此,我們字段越多,集群狀態(tài)也會(huì)越大,網(wǎng)絡(luò)開(kāi)銷(xiāo)也會(huì)越大,所以最好想辦法拆一些字段出來(lái)(垂直拆分)。而拆字段出來(lái)導(dǎo)致文檔更多了也沒(méi)關(guān)系,ES 本來(lái)就是為了解決大數(shù)據(jù)的,保持集群狀態(tài)小而敏捷更重要。
3.3 推遲分片分配
我們都知道 ES 將自動(dòng)在可用節(jié)點(diǎn)間進(jìn)行分片均衡,包括新節(jié)點(diǎn)的加入和現(xiàn)有節(jié)點(diǎn)的離線。理論上來(lái)說(shuō),這個(gè)是理想的行為,我們想要提拔副本分片來(lái)盡快恢復(fù)丟失的主分片。我們同時(shí)也希望保證資源在整個(gè)集群的均衡,用以避免熱點(diǎn)。
然而,在實(shí)踐中,立即的再均衡所造成的問(wèn)題會(huì)比其解決的更多。舉例來(lái)說(shuō),考慮到以下情形:
- 集群中的某個(gè)節(jié)點(diǎn)突然失聯(lián)了(只是短暫的失聯(lián))。
- master 立即發(fā)現(xiàn)了有節(jié)點(diǎn)離線了,然后在集群內(nèi)提拔了擁有該節(jié)點(diǎn)主分片副本的副分片為主分片。
- 在副本被提拔為主分片以后,master 節(jié)點(diǎn)開(kāi)始執(zhí)行恢復(fù)操作來(lái)重建缺失的副本。集群中的節(jié)點(diǎn)之間互相拷貝分片數(shù)據(jù),網(wǎng)卡壓力劇增,集群狀態(tài)嘗試變綠。
- 由于目前集群處于非平衡狀態(tài),這個(gè)過(guò)程還有可能會(huì)觸發(fā)小規(guī)模的分片移動(dòng)。其他不相關(guān)的分片將在節(jié)點(diǎn)間遷移來(lái)達(dá)到一個(gè)最佳的平衡狀態(tài)。
與此同時(shí),失聯(lián)的節(jié)點(diǎn)又回歸集群了。不幸的是,這個(gè)節(jié)點(diǎn)被告知當(dāng)前的數(shù)據(jù)已經(jīng)沒(méi)有用了,數(shù)據(jù)已經(jīng)在其他節(jié)點(diǎn)上重新分配了。因此,它只能刪除本地?cái)?shù)據(jù),然后重新開(kāi)始恢復(fù)集群的其他分片(然后這又導(dǎo)致了一個(gè)新的再平衡)。這種開(kāi)銷(xiāo)無(wú)疑是極大而且是沒(méi)有必要的。為了避免這種情況,ES 可以推遲分片的分配。這可以讓集群在重新分配之前有時(shí)間去檢測(cè)這個(gè)節(jié)點(diǎn)是否會(huì)再次重新加入。
下面將延時(shí)修改成 5 分鐘:
3.4 部署
經(jīng)過(guò) 1 和 2 章節(jié),相信大家對(duì) ES 的核心原理已經(jīng)比較清楚了,但是我們更多是作為使用者,所以如何正確部署、管理和使用其實(shí)更為重要。
3.4.1 上生產(chǎn)前應(yīng)該要注意的事項(xiàng)
? 硬件
– 內(nèi)存
如果有一種資源是最先被耗盡的,它很可能是內(nèi)存。排序和聚合都很耗內(nèi)存,所以有足夠的堆空間來(lái)應(yīng)付它們是很重要的。即使堆空間比較小的時(shí)候, 也能為操作系統(tǒng)文件緩存提供額外的內(nèi)存。因?yàn)?/p>
內(nèi)存一般選 8 ~ 64 GB,64 GB 內(nèi)存的機(jī)器是非常理想的。少于8 GB 會(huì)適得其反(你最終需要很多很多的小機(jī)器),大于64 GB 的機(jī)器也會(huì)有問(wèn)題。
– CPU
大多數(shù)他資源,具體配置多少個(gè)(CPU)不是那么關(guān)鍵。常見(jiàn)的集群使用兩到八個(gè)核的機(jī)器。
– 硬盤(pán)
硬盤(pán)對(duì)所有的集群都很重要,對(duì)大量寫(xiě)入的集群更是加倍重要(例如那些存儲(chǔ)日志數(shù)據(jù)的)。硬盤(pán)是服務(wù)器上最慢的子系統(tǒng),這意味著那些寫(xiě)入量很大的集群很容易讓硬盤(pán)飽和,使得它成為集群的瓶頸。純看速度的話,推薦
– 網(wǎng)絡(luò)
快速可靠的網(wǎng)絡(luò)顯然對(duì)分布式系統(tǒng)的性能是很重要的。低延時(shí)能幫助確保節(jié)點(diǎn)間能順暢通訊,大帶寬能幫助分片移動(dòng)和恢復(fù)。現(xiàn)代數(shù)據(jù)中心網(wǎng)絡(luò)(1 GbE, 10 GbE)對(duì)絕大多數(shù)集群都是足夠的。
- JVM
每個(gè) ES 版本都會(huì)有和它相匹配的推薦的 JDK 版本,自己注意就好了。這里說(shuō)下關(guān)于堆的設(shè)置。首先 xms 和 xmx 應(yīng)該設(shè)置成一樣的。其次,堆占用的內(nèi)存不應(yīng)該超過(guò)服務(wù)器內(nèi)存的一半。更詳細(xì)請(qǐng)看:set-jvm-heap-size 。
- 文件描述符和 MMap
Lucene 使用了大量的文件。同時(shí), ES 在節(jié)點(diǎn)和 HTTP 客戶(hù)端之間進(jìn)行通信也使用了大量的套接字。這一切都需要足夠的文件描述符。因此,安裝好 ES 后,要請(qǐng)求 GET /_nodes/process 確認(rèn)下 max_file_descriptors 是否足夠大(比如 64000)。另外,ES 對(duì)各種文件混合使用了 NioFs(非阻塞文件系統(tǒng))和 MMapFs (內(nèi)存映射文件系統(tǒng))。請(qǐng)確認(rèn)系統(tǒng)配置的最大映射數(shù)量,以便有足夠的虛擬內(nèi)存可用于 mmapped 文件??梢栽?/etc/sysctl.conf 通過(guò)修改 vm.max_map_count 永久設(shè)置它。
3.4.2 滾動(dòng)重啟
我們平常給應(yīng)用上線,是一個(gè)個(gè)節(jié)點(diǎn)部署,做的好一點(diǎn)的公司甚至是逐漸放量到新節(jié)點(diǎn),穩(wěn)定后再上另一個(gè)節(jié)點(diǎn)的。ES 如果要重啟,也應(yīng)該是如此。操作流程如下:
- 可能的話,停止索引新的數(shù)據(jù)。雖然不是每次都能真的做到,但是這一步可以幫助提高恢復(fù)速度。
- 禁止分片分配。這一步阻止 ES 再平衡缺失的分片,直到我們處理好。禁止分配如下:
- 關(guān)閉單個(gè)節(jié)點(diǎn)
- 執(zhí)行維護(hù)/升級(jí)
- 重啟節(jié)點(diǎn),然后確認(rèn)它加入到集群了
- 用如下命令重啟分片分配:
分片再平衡會(huì)花一些時(shí)間。一直等到集群變成綠色狀態(tài)后再繼續(xù)
- 重重復(fù)第 2 到 6 步操作剩余節(jié)點(diǎn)
- 到這步可以安全的恢復(fù)索引了(如果之前停止了的話),不過(guò)等待集群完全均衡后再恢復(fù)索引,也會(huì)有助于提高處理速度。
3.4.3 備份集群
不管是備份容災(zāi),還是遷移集群,都是需要備份的。
要備份集群,可以使用??snapshot API??。這個(gè)會(huì)拿到集群里當(dāng)前的狀態(tài)和數(shù)據(jù),然后保存到一個(gè)共享倉(cāng)庫(kù)里。這個(gè)備份過(guò)程是"智能"的。第一個(gè)快照會(huì)是一個(gè)數(shù)據(jù)的完整拷貝,但是所有后續(xù)的快照會(huì)保留的是已存快照和新數(shù)據(jù)之間的差異。隨著不時(shí)的對(duì)數(shù)據(jù)進(jìn)行快照,備份也在增量的添加和刪除。這意味著后續(xù)備份會(huì)相當(dāng)快速,因?yàn)樗鼈冎粋鬏敽苄〉臄?shù)據(jù)量。
1.要使用這個(gè)功能,必須首先創(chuàng)建一個(gè)保存數(shù)據(jù)的倉(cāng)庫(kù)。有多個(gè)倉(cāng)庫(kù)類(lèi)型可以選擇:
– 共享文件系統(tǒng),比如 NAS
– Amazon S3
– HDFS (Hadoop 分布式文件系統(tǒng))
– Azure Cloud
2.選好倉(cāng)庫(kù)后,就要部署一個(gè)共享文件系統(tǒng)倉(cāng)庫(kù),如下:
注意:共享文件系統(tǒng)路徑必須確保集群所有節(jié)點(diǎn)都可以訪問(wèn)到。
3.快照所有打開(kāi)的索引 PUT _snapshot/my_backup/snapshot_1
這個(gè)調(diào)用會(huì)立刻返回,然后快照會(huì)在后臺(tái)運(yùn)行。
– 如果希望等待快照完成才有返回:PUT _snapshot/my_backup/snapshot_1?wait_for_completion=true
– 快照指定索引,如下:
– 刪除快照:DELETE _snapshot/my_backup/snapshot_2這個(gè)要慎用。
– 監(jiān)控快照進(jìn)度:GET _snapshot/my_backup/snapshot_2/_status
– 取消一個(gè)快照,用于刪除一個(gè)進(jìn)行中的快照:DELETE _snapshot/my_backup/snapshot_2
這個(gè)會(huì)中斷快照進(jìn)程,然后刪除倉(cāng)庫(kù)里進(jìn)行到一半的快照。
3.4.4 從快照恢復(fù)
官網(wǎng)介紹:restore snapshot api
備份好數(shù)據(jù)后,就可以通過(guò)備份的快照快速恢復(fù)數(shù)據(jù)了。如下:
4 總結(jié)
紙上得來(lái)終覺(jué)淺,絕知此事要躬行。希望你能在工作中,根據(jù)公司實(shí)際情況按照學(xué)到的案例實(shí)際應(yīng)用就最好了。
作者介紹
蔡柱梁,51CTO社區(qū)編輯,從事Java后端開(kāi)發(fā)8年,做過(guò)傳統(tǒng)項(xiàng)目廣電BOSS系統(tǒng),后投身互聯(lián)網(wǎng)電商,負(fù)責(zé)過(guò)訂單,TMS,中間件等。






























