分布式搜索引擎Elasticsearch的架構(gòu)分析

一、寫在前面

ES(Elasticsearch下文統(tǒng)一稱為ES)越來越多的企業(yè)在業(yè)務(wù)場(chǎng)景是使用ES存儲(chǔ)自己的非結(jié)構(gòu)化數(shù)據(jù),例如電商業(yè)務(wù)實(shí)現(xiàn)商品站內(nèi)搜索,數(shù)據(jù)指標(biāo)分析,日志分析等洪橘,ES作為傳統(tǒng)關(guān)系型數(shù)據(jù)庫的補(bǔ)充,提供了關(guān)系型數(shù)據(jù)庫不具備的一些能力棵帽。

ES最先進(jìn)入大眾視野的是其能夠?qū)崿F(xiàn)全文搜索的能力熄求,也是由于基于Lucene的實(shí)現(xiàn),內(nèi)部有一種倒排索引的數(shù)據(jù)結(jié)構(gòu)逗概。

本文作者將介紹ES的分布式架構(gòu)弟晚,以及ES的存儲(chǔ)索引機(jī)制,本文不會(huì)詳細(xì)介紹ES的API逾苫,會(huì)從整體架構(gòu)層面進(jìn)行分析卿城,后續(xù)作者會(huì)有其他文章對(duì)ES的使用進(jìn)行介紹。

二铅搓、什么是倒排索引

要講明白什么是倒排索引瑟押,首先我們先梳理下什么索引,比如一本書星掰,書的目錄頁多望,有章節(jié),章節(jié)名稱蹋偏,我們想看哪個(gè)章節(jié)便斥,我們通過目錄頁,查到對(duì)應(yīng)章節(jié)和頁碼威始,就能定位到具體的章節(jié)內(nèi)容,通過目錄頁的章節(jié)名稱查到章節(jié)的頁碼像街,進(jìn)而看到章節(jié)內(nèi)容黎棠,這個(gè)過程就是一個(gè)索引的過程晋渺,那么什么是倒排索引呢?

比如查詢《java編程思想》這本書的文章脓斩,翻開書本可以看到目錄頁木西,記錄這個(gè)章節(jié)名字和章節(jié)地址頁碼,通過查詢章節(jié)名字“繼承”可以定位到“繼承”這篇章節(jié)的具體地址随静,查看到文章的內(nèi)容八千,我們可以看到文章內(nèi)容中包含很多“對(duì)象”這個(gè)詞。

那么如果我們要在這本書中查詢所有包含有“對(duì)象”這個(gè)詞的文章燎猛,那該怎么辦呢恋捆?

按照現(xiàn)在的索引方式無疑大海撈針,假設(shè)我們有一個(gè)“對(duì)象”--→文章的映射關(guān)系重绷,不就可以了嗎沸停?類似這樣的反向建立映射關(guān)系的就叫倒排索引。

如圖1所示昭卓,將文章進(jìn)行分詞后得到關(guān)鍵詞愤钾,在根據(jù)關(guān)鍵詞建立倒排索引,關(guān)鍵詞構(gòu)建成一個(gè)詞典候醒,詞典中存放著一個(gè)個(gè)詞條(關(guān)鍵詞)能颁,每個(gè)關(guān)鍵詞都有一個(gè)列表與其對(duì)應(yīng),這個(gè)列表就是倒排表倒淫,存放的是章節(jié)文檔編號(hào)和詞頻等信息劲装,倒排列表中的每個(gè)元素就是一個(gè)倒排項(xiàng),最后可以看到昌简,整個(gè)倒排索引就像一本新華字典占业,所有單詞的倒排列表往往順序地存儲(chǔ)在磁盤的某個(gè)文件里,這個(gè)文件被稱之為倒排文件纯赎。

(圖1)

詞典和倒排文件是Lucene的兩種基本數(shù)據(jù)結(jié)構(gòu)谦疾,但是存儲(chǔ)方式不同,詞典在內(nèi)存中存儲(chǔ)犬金,倒排文件在磁盤上念恍。本文不會(huì)去介紹分詞,tf-idf晚顷,BM25峰伙,向量空間相似度等構(gòu)建倒排索引和查詢倒排索引所用到的技術(shù),讀者只需要對(duì)倒排索引有個(gè)基本的認(rèn)識(shí)即可该默。

三瞳氓、ES的集群架構(gòu)

1. ****集群節(jié)點(diǎn)

一個(gè)ES集群可以有多個(gè)節(jié)點(diǎn)構(gòu)成,一個(gè)節(jié)點(diǎn)就是一個(gè)ES服務(wù)實(shí)例栓袖,通過配置集群名稱cluster.name加入集群匣摘。那么節(jié)點(diǎn)是如何通過配置相同的集群名稱加入集群的呢店诗?要搞明白這個(gè)問題,我們必須先搞清楚ES集群中節(jié)點(diǎn)的角色音榜。

ES中節(jié)點(diǎn)有角色的區(qū)分的庞瘸,通過配置文件conf/elasticsearch.yml中配置以下配置進(jìn)行角色的設(shè)定。

node.master: true/false
node.data: true/false

集群中單個(gè)節(jié)點(diǎn)既可以是候選主節(jié)點(diǎn)也可以是數(shù)據(jù)節(jié)點(diǎn)赠叼,通過上面的配置可以進(jìn)行兩兩組合形成四大分類:

(1)僅為候選主節(jié)點(diǎn)
(2)既是候選主節(jié)點(diǎn)也是數(shù)據(jù)節(jié)點(diǎn)
(3)僅為數(shù)據(jù)節(jié)點(diǎn)
(4)既不是候選主節(jié)點(diǎn)也不是數(shù)據(jù)節(jié)點(diǎn)

候選主節(jié)點(diǎn):只有是候選主節(jié)點(diǎn)才可以參與選舉投票,也只有候選主節(jié)點(diǎn)可以被選舉為主節(jié)點(diǎn)瞬场。

主節(jié)點(diǎn):負(fù)責(zé)索引的添加、刪除刃榨,跟蹤哪些節(jié)點(diǎn)是群集的一部分,對(duì)分片進(jìn)行分配苞轿、收集集群中各節(jié)點(diǎn)的狀態(tài)等,穩(wěn)定的主節(jié)點(diǎn)對(duì)集群的健康是非常重要契邀。

數(shù)據(jù)節(jié)點(diǎn):負(fù)責(zé)對(duì)數(shù)據(jù)的增坯门、刪古戴、改现恼、查述暂、聚合等操作建炫,數(shù)據(jù)的查詢和存儲(chǔ)都是由數(shù)據(jù)節(jié)點(diǎn)負(fù)責(zé)艺配,對(duì)機(jī)器的CPU,IO以及內(nèi)存的要求比較高,一般選擇高配置的機(jī)器作為數(shù)據(jù)節(jié)點(diǎn)砖织。

此外還有一種節(jié)點(diǎn)角色叫做協(xié)調(diào)節(jié)點(diǎn),其本身不是通過設(shè)置來分配的眶熬,用戶的請(qǐng)求可以隨機(jī)發(fā)往任何一個(gè)節(jié)點(diǎn)娜氏,并由該節(jié)點(diǎn)負(fù)責(zé)分發(fā)請(qǐng)求、收集結(jié)果等操作贸弥,而不需要主節(jié)點(diǎn)轉(zhuǎn)發(fā)抖棘。這種節(jié)點(diǎn)可稱之為協(xié)調(diào)節(jié)點(diǎn),集群中的任何節(jié)點(diǎn)都可以充當(dāng)協(xié)調(diào)節(jié)點(diǎn)的角色切省。每個(gè)節(jié)點(diǎn)之間都會(huì)保持聯(lián)系最岗。

(圖2)

2. 發(fā)現(xiàn)機(jī)制

前文說到通過設(shè)置一個(gè)集群名稱朝捆,節(jié)點(diǎn)就可以加入集群,那么ES是如何做到這一點(diǎn)的呢驯用?

這里就要講一講ES特殊的發(fā)現(xiàn)機(jī)制ZenDiscovery。

ZenDiscovery是ES的內(nèi)置發(fā)現(xiàn)機(jī)制薇正,提供單播和多播兩種發(fā)現(xiàn)方式雕沿,主要職責(zé)是集群中節(jié)點(diǎn)的發(fā)現(xiàn)以及選舉Master節(jié)點(diǎn)。

多播也叫組播猴仑,指一個(gè)節(jié)點(diǎn)可以向多臺(tái)機(jī)器發(fā)送請(qǐng)求审轮。生產(chǎn)環(huán)境中ES不建議使用這種方式,對(duì)于一個(gè)大規(guī)模的集群辽俗,組播會(huì)產(chǎn)生大量不必要的通信疾渣。

單播,當(dāng)一個(gè)節(jié)點(diǎn)加入一個(gè)現(xiàn)有集群榆苞,或者組建一個(gè)新的集群時(shí)稳衬,請(qǐng)求發(fā)送到一臺(tái)機(jī)器。當(dāng)一個(gè)節(jié)點(diǎn)聯(lián)系到單播列表中的成員時(shí)坐漏,它就會(huì)得到整個(gè)集群所有節(jié)點(diǎn)的狀態(tài)薄疚,然后它會(huì)聯(lián)系Master節(jié)點(diǎn),并加入集群赊琳。

只有在同一臺(tái)機(jī)器上運(yùn)行的節(jié)點(diǎn)才會(huì)自動(dòng)組成集群街夭。ES 默認(rèn)被配置為使用單播發(fā)現(xiàn),單播列表不需要包含集群中的所有節(jié)點(diǎn)躏筏,它只是需要足夠的節(jié)點(diǎn)板丽,當(dāng)一個(gè)新節(jié)點(diǎn)聯(lián)系上其中一個(gè)并且通信就可以了。如果你使用 Master 候選節(jié)點(diǎn)作為單播列表趁尼,你只要列出三個(gè)就可以了埃碱。

這個(gè)配置在 elasticsearch.yml 文件中:

discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]

集群信息收集階段采用了 Gossip 協(xié)議,上面配置的就相當(dāng)于一個(gè)seed nodes酥泞,Gossip協(xié)議這里就不多做贅述了砚殿。

ES官方建議unicast.hosts配置為所有的候選主節(jié)點(diǎn),ZenDiscovery 會(huì)每隔ping_interval(配置項(xiàng))ping一次芝囤,每次超時(shí)時(shí)間是discovery.zen.ping_timeout(配置項(xiàng))似炎,3次(ping_retries配置項(xiàng))ping失敗則認(rèn)為節(jié)點(diǎn)宕機(jī)辛萍,宕機(jī)的情況下會(huì)觸發(fā)failover,會(huì)進(jìn)行分片重分配羡藐、復(fù)制等操作贩毕。

如果宕機(jī)的節(jié)點(diǎn)不是Master,則Master會(huì)更新集群的元信息仆嗦,Master節(jié)點(diǎn)將最新的集群元信息發(fā)布出去辉阶,給其他節(jié)點(diǎn),其他節(jié)點(diǎn)回復(fù)Ack欧啤,Master節(jié)點(diǎn)收到discovery.zen.minimum_master_nodes的值-1個(gè) 候選主節(jié)點(diǎn)的回復(fù)睛藻,則發(fā)送Apply消息給其他節(jié)點(diǎn)启上,集群狀態(tài)更新完畢邢隧。如果宕機(jī)的節(jié)點(diǎn)是Master,則其他的候選主節(jié)點(diǎn)開始Master節(jié)點(diǎn)的選舉流程冈在。

2.1 選主

Master的選主過程中要確保只有一個(gè)master倒慧,ES通過一個(gè)參數(shù)quorum的代表多數(shù)派閾值,保證選舉出的master被至少quorum個(gè)的候選主節(jié)點(diǎn)認(rèn)可包券,以此來保證只有一個(gè)master纫谅。

選主的發(fā)起由候選主節(jié)點(diǎn)發(fā)起,當(dāng)前候選主節(jié)點(diǎn)發(fā)現(xiàn)自己不是master節(jié)點(diǎn)溅固,并且通過ping其他節(jié)點(diǎn)發(fā)現(xiàn)無法聯(lián)系到主節(jié)點(diǎn)付秕,并且包括自己在內(nèi)已經(jīng)有超過minimum_master_nodes個(gè)節(jié)點(diǎn)無法聯(lián)系到主節(jié)點(diǎn),那么這個(gè)時(shí)候則發(fā)起選主侍郭。

選主流程圖

(圖3)

選主的時(shí)候按照集群節(jié)點(diǎn)的參數(shù)<stateVersion, id> 排序询吴。stateVersion從大到小排序,以便選出集群元信息較新的節(jié)點(diǎn)作為Master亮元,id從小到大排序募书,避免在stateVersion相同時(shí)發(fā)生分票無法選出 Master蝴猪。

排序后第一個(gè)節(jié)點(diǎn)即為Master節(jié)點(diǎn)。當(dāng)一個(gè)候選主節(jié)點(diǎn)發(fā)起一次選舉時(shí),它會(huì)按照上述排序策略選出一個(gè)它認(rèn)為的Master涣脚。

2.2 腦裂

提到分布式系統(tǒng)選主,不可避免的會(huì)提到腦裂這樣一個(gè)現(xiàn)象鬓照,什么是腦裂呢全跨?如果集群中選舉出多個(gè)Master節(jié)點(diǎn),使得數(shù)據(jù)更新時(shí)出現(xiàn)不一致成肘,這種現(xiàn)象稱之為腦裂卖局。

簡而言之集群中不同的節(jié)點(diǎn)對(duì)于 Master的選擇出現(xiàn)了分歧,出現(xiàn)了多個(gè)Master競(jìng)爭(zhēng)艇劫。

一般而言腦裂問題可能有以下幾個(gè)原因造成:

  • 網(wǎng)絡(luò)問題:集群間的網(wǎng)絡(luò)延遲導(dǎo)致一些節(jié)點(diǎn)訪問不到Master吼驶,認(rèn)為Master 掛掉了惩激,而master其實(shí)并沒有宕機(jī),而選舉出了新的Master蟹演,并對(duì)Master上的分片和副本標(biāo)紅风钻,分配新的主分片。

  • 節(jié)點(diǎn)負(fù)載:主節(jié)點(diǎn)的角色既為Master又為Data酒请,訪問量較大時(shí)可能會(huì)導(dǎo)致 ES 停止響應(yīng)(假死狀態(tài))造成大面積延遲骡技,此時(shí)其他節(jié)點(diǎn)得不到主節(jié)點(diǎn)的響應(yīng)認(rèn)為主節(jié)點(diǎn)掛掉了,會(huì)重新選取主節(jié)點(diǎn)羞反。

  • 內(nèi)存回收:主節(jié)點(diǎn)的角色既為Master又為Data布朦,當(dāng)Data節(jié)點(diǎn)上的ES進(jìn)程占用的內(nèi)存較大,引發(fā)JVM的大規(guī)模內(nèi)存回收昼窗,造成ES進(jìn)程失去響應(yīng)是趴。

如何避免腦裂:我們可以基于上述原因,做出優(yōu)化措施:

  • 適當(dāng)調(diào)大響應(yīng)超時(shí)時(shí)間澄惊,減少誤判唆途。通過參數(shù) discovery.zen.ping_timeout 設(shè)置節(jié)點(diǎn)ping超時(shí)時(shí)間,默認(rèn)為 3s掸驱,可以適當(dāng)調(diào)大肛搬。

  • 選舉觸發(fā),我們需要在候選節(jié)點(diǎn)的配置文件中設(shè)置參數(shù) discovery.zen.munimum_master_nodes 的值毕贼。這個(gè)參數(shù)表示在選舉主節(jié)點(diǎn)時(shí)需要參與選舉的候選主節(jié)點(diǎn)的節(jié)點(diǎn)數(shù)温赔,默認(rèn)值是 1,官方建議取值(master_eligibel_nodes/2)+1鬼癣,其中 master_eligibel_nodes 為候選主節(jié)點(diǎn)的個(gè)數(shù)陶贼。這樣做既能防止腦裂現(xiàn)象的發(fā)生,也能最大限度地提升集群的高可用性扣溺,因?yàn)橹灰簧儆?discovery.zen.munimum_master_nodes 個(gè)候選節(jié)點(diǎn)存活骇窍,選舉工作就能正常進(jìn)行。當(dāng)小于這個(gè)值的時(shí)候锥余,無法觸發(fā)選舉行為腹纳,集群無法使用,不會(huì)造成分片混亂的情況驱犹。

  • 角色分離嘲恍,即是上面我們提到的候選主節(jié)點(diǎn)和數(shù)據(jù)節(jié)點(diǎn)進(jìn)行角色分離,這樣可以減輕主節(jié)點(diǎn)的負(fù)擔(dān)雄驹,防止主節(jié)點(diǎn)的假死狀態(tài)發(fā)生佃牛,減少對(duì)主節(jié)點(diǎn)宕機(jī)的誤判。

四医舆、索引如何寫入的

1. 寫索引原理

1.1 分片

ES支持PB級(jí)全文搜索俘侠,通常我們數(shù)據(jù)量很大的時(shí)候象缀,查詢性能都會(huì)越來越慢,我們能想到的一個(gè)方式的將數(shù)據(jù)分散到不同的地方存儲(chǔ)爷速,ES也是如此央星,ES通過水平拆分的方式將一個(gè)索引上的數(shù)據(jù)拆分出來分配到不同的數(shù)據(jù)塊上,拆分出來的數(shù)據(jù)庫塊稱之為一個(gè)分片Shard惫东,很像MySQL的分庫分表莉给。

不同的主分片分布在不同的節(jié)點(diǎn)上,那么在多分片的索引中數(shù)據(jù)應(yīng)該被寫入哪里廉沮?肯定不能隨機(jī)寫颓遏,否則查詢的時(shí)候就無法快速檢索到對(duì)應(yīng)的數(shù)據(jù)了,這需要有一個(gè)路由策略來確定具體寫入哪一個(gè)分片中滞时,怎么路由我們下文會(huì)介紹叁幢。在創(chuàng)建索引的時(shí)候需要指定分片的數(shù)量,并且分片的數(shù)量一旦確定就不能修改漂洋。

1.2 副本

副本就是對(duì)分片的復(fù)制遥皂,每個(gè)主分片都有一個(gè)或多個(gè)副本分片,當(dāng)主分片異常時(shí)刽漂,副本可以提供數(shù)據(jù)的查詢等操作。主分片和對(duì)應(yīng)的副本分片是不會(huì)在同一個(gè)節(jié)點(diǎn)上的弟孟,避免數(shù)據(jù)的丟失贝咙,當(dāng)一個(gè)節(jié)點(diǎn)宕機(jī)的時(shí)候,還可以通過副本查詢到數(shù)據(jù)拂募,副本分片數(shù)的最大值是 N-1(其中 N 為節(jié)點(diǎn)數(shù))庭猩。

對(duì)doc的新建、索引和刪除請(qǐng)求都是寫操作陈症,這些寫操作是必須在主分片上完成蔼水,然后才能被復(fù)制到對(duì)應(yīng)的副本上。ES為了提高寫入的能力這個(gè)過程是并發(fā)寫的录肯,同時(shí)為了解決并發(fā)寫的過程中數(shù)據(jù)沖突的問題趴腋,ES通過樂觀鎖的方式控制,每個(gè)文檔都有一個(gè) _version號(hào)论咏,當(dāng)文檔被修改時(shí)版本號(hào)遞增优炬。

一旦所有的副本分片都報(bào)告寫成功才會(huì)向協(xié)調(diào)節(jié)點(diǎn)報(bào)告成功,協(xié)調(diào)節(jié)點(diǎn)向客戶端報(bào)告成功厅贪。

(圖4)

1.3 Elasticsearch 的寫索引流程

上面提到了寫索引是只能寫在主分片上蠢护,然后同步到副本分片,那么如圖4所示养涮,這里有四個(gè)主分片分別是S0葵硕、S1眉抬、S2、S3懈凹,一條數(shù)據(jù)是根據(jù)什么策略寫到指定的分片上呢吐辙?這條索引數(shù)據(jù)為什么被寫到S0上而不寫到 S1 或 S2 上?這個(gè)過程是根據(jù)下面這個(gè)公式?jīng)Q定的蘸劈。

shard = hash(routing) % number_of_primary_shards

以上公式的值是在0到number_of_primary_shards-1之間的余數(shù)昏苏,也就是數(shù)據(jù)檔所在分片的位置。routing通過Hash函數(shù)生成一個(gè)數(shù)字威沫,然后這個(gè)數(shù)字再除以number_of_primary_shards(主分片的數(shù)量)后得到余數(shù)贤惯。routing是一個(gè)可變值,默認(rèn)是文檔的_id 棒掠,也可以設(shè)置成一個(gè)自定義的值孵构。

在一個(gè)寫請(qǐng)求被發(fā)送到某個(gè)節(jié)點(diǎn)后,該節(jié)點(diǎn)按照前文所述烟很,會(huì)充當(dāng)協(xié)調(diào)節(jié)點(diǎn)颈墅,會(huì)根據(jù)路由公式計(jì)算出寫哪個(gè)分片,當(dāng)前節(jié)點(diǎn)有所有其他節(jié)點(diǎn)的分片信息雾袱,如果發(fā)現(xiàn)對(duì)應(yīng)的分片是在其他節(jié)點(diǎn)上恤筛,再將請(qǐng)求轉(zhuǎn)發(fā)到該分片的主分片節(jié)點(diǎn)上。

在ES集群中每個(gè)節(jié)點(diǎn)都通過上面的公式知道數(shù)據(jù)的在集群中的存放位置芹橡,所以每個(gè)節(jié)點(diǎn)都有接收讀寫請(qǐng)求的能力毒坛。

那么為什么在創(chuàng)建索引的時(shí)候就確定好主分片的數(shù)量,并且不可修改林说?因?yàn)槿绻麛?shù)量變化了煎殷,那么所有之前路由計(jì)算的值都會(huì)無效,數(shù)據(jù)也就再也找不到了腿箩。

( 圖5)

如上圖5所示豪直,當(dāng)前一個(gè)數(shù)據(jù)通過路由計(jì)算公式得到的值是 shard=hash(routing)%4=0,則具體流程如下:

(1)數(shù)據(jù)寫請(qǐng)求發(fā)送到 node1 節(jié)點(diǎn)珠移,通過路由計(jì)算得到值為1弓乙,那么對(duì)應(yīng)的數(shù)據(jù)會(huì)應(yīng)該在主分片S1上。
(2)node1節(jié)點(diǎn)將請(qǐng)求轉(zhuǎn)發(fā)到 S1 主分片所在的節(jié)點(diǎn)node2剑梳,node2 接受請(qǐng)求并寫入到磁盤唆貌。
(3)并發(fā)將數(shù)據(jù)復(fù)制到三個(gè)副本分片R1上,其中通過樂觀并發(fā)控制數(shù)據(jù)的沖突垢乙。一旦所有的副本分片都報(bào)告成功锨咙,則節(jié)點(diǎn) node2將向node1節(jié)點(diǎn)報(bào)告成功,然后node1節(jié)點(diǎn)向客戶端報(bào)告成功追逮。

這種模式下酪刀,只要有副本在粹舵,寫入延時(shí)最小也是兩次單分片的寫入耗時(shí)總和,效率會(huì)較低骂倘,但是這樣的好處也很明顯眼滤,避免寫入后單個(gè)機(jī)器硬件故障導(dǎo)致數(shù)據(jù)丟失,在數(shù)據(jù)完整性和性能方面历涝,一般都是優(yōu)先選擇數(shù)據(jù)诅需,除非一些允許丟數(shù)據(jù)的特殊場(chǎng)景。

在ES里為了減少磁盤IO保證讀寫性能荧库,一般是每隔一段時(shí)間(比如30分鐘)才會(huì)把數(shù)據(jù)寫入磁盤持久化堰塌,對(duì)于寫入內(nèi)存,但還未flush到磁盤的數(shù)據(jù)分衫,如果發(fā)生機(jī)器宕機(jī)或者掉電场刑,那么內(nèi)存中的數(shù)據(jù)也會(huì)丟失,這時(shí)候如何保證蚪战?

對(duì)于這種問題牵现,ES借鑒數(shù)據(jù)庫中的處理方式,增加CommitLog模塊邀桑,在ES中叫transLog瞎疼,在下面的ES存儲(chǔ)原理中會(huì)介紹。

2. 存儲(chǔ)原理

上面介紹了在ES內(nèi)部的寫索引處理流程概漱,數(shù)據(jù)在寫入到分片和副本上后丑慎,目前數(shù)據(jù)在內(nèi)存中,要確保數(shù)據(jù)在斷電后不丟失瓤摧,還需要持久化到磁盤上。

我們知道ES是基于Lucene實(shí)現(xiàn)的玉吁,內(nèi)部是通過Lucene完成的索引的創(chuàng)建寫入和搜索查詢照弥,Lucene 工作原理如下圖所示,當(dāng)新添加一片文檔時(shí)进副,Lucene進(jìn)行分詞等預(yù)處理这揣,然后將文檔索引寫入內(nèi)存中,并將本次操作寫入事務(wù)日志(transLog)影斑,transLog類似于mysql的binlog给赞,用于宕機(jī)后內(nèi)存數(shù)據(jù)的恢復(fù),保存未持久化數(shù)據(jù)的操作日志矫户。

默認(rèn)情況下片迅,Lucene每隔1s(refresh_interval配置項(xiàng))將內(nèi)存中的數(shù)據(jù)刷新到文件系統(tǒng)緩存中,稱為一個(gè)segment(段)皆辽。一旦刷入文件系統(tǒng)緩存柑蛇,segment才可以被用于檢索芥挣,在這之前是無法被檢索的。

因此refresh_interval決定了ES數(shù)據(jù)的實(shí)時(shí)性耻台,因此說ES是一個(gè)準(zhǔn)實(shí)時(shí)的系統(tǒng)空免。segment 在磁盤中是不可修改的,因此避免了磁盤的隨機(jī)寫盆耽,所有的隨機(jī)寫都在內(nèi)存中進(jìn)行蹋砚。隨著時(shí)間的推移,segment越來越多摄杂,默認(rèn)情況下坝咐,Lucene每隔30min或segment 空間大于512M,將緩存中的segment持久化落盤匙姜,稱為一個(gè)commit point畅厢,此時(shí)刪掉對(duì)應(yīng)的transLog。

當(dāng)我們?cè)谶M(jìn)行寫操作的測(cè)試的時(shí)候氮昧,可以通過手動(dòng)刷新來保障數(shù)據(jù)能夠被及時(shí)檢索到框杜,但是不要在生產(chǎn)環(huán)境下每次索引一個(gè)文檔都去手動(dòng)刷新,刷新操作會(huì)有一定的性能開銷袖肥。一般業(yè)務(wù)場(chǎng)景中并不都需要每秒刷新咪辱。

可以通過在 Settings 中調(diào)大 refresh_interval = "30s" 的值,來降低每個(gè)索引的刷新頻率椎组,設(shè)值時(shí)需要注意后面帶上時(shí)間單位油狂,否則默認(rèn)是毫秒。當(dāng) refresh_interval=-1 時(shí)表示關(guān)閉索引的自動(dòng)刷新寸癌。

(圖6)

索引文件分段存儲(chǔ)并且不可修改专筷,那么新增、更新和刪除如何處理呢蒸苇?

  • 新增磷蛹,新增很好處理,由于數(shù)據(jù)是新的溪烤,所以只需要對(duì)當(dāng)前文檔新增一個(gè)段就可以了味咳。

  • 刪除,由于不可修改檬嘀,所以對(duì)于刪除操作槽驶,不會(huì)把文檔從舊的段中移除而是通過新增一個(gè) .del 文件,文件中會(huì)列出這些被刪除文檔的段信息鸳兽,這個(gè)被標(biāo)記刪除的文檔仍然可以被查詢匹配到掂铐, 但它會(huì)在最終結(jié)果被返回前從結(jié)果集中移除。

  • 更新,不能修改舊的段來進(jìn)行文檔的更新堡纬,其實(shí)更新相當(dāng)于是刪除和新增這兩個(gè)動(dòng)作組成聂受。會(huì)將舊的文檔在 .del 文件中標(biāo)記刪除,然后文檔的新版本中被索引到一個(gè)新的段烤镐〉凹茫可能兩個(gè)版本的文檔都會(huì)被一個(gè)查詢匹配到,但被刪除的那個(gè)舊版本文檔在結(jié)果集返回前就會(huì)被移除炮叶。

segment被設(shè)定為不可修改具有一定的優(yōu)勢(shì)也有一定的缺點(diǎn)碗旅。

優(yōu)點(diǎn):

  • 不需要鎖。如果你從來不更新索引镜悉,你就不需要擔(dān)心多進(jìn)程同時(shí)修改數(shù)據(jù)的問題祟辟。

  • 一旦索引被讀入內(nèi)核的文件系統(tǒng)緩存,便會(huì)留在哪里侣肄,由于其不變性旧困。只要文件系統(tǒng)緩存中還有足夠的空間,那么大部分讀請(qǐng)求會(huì)直接請(qǐng)求內(nèi)存稼锅,而不會(huì)命中磁盤吼具。這提供了很大的性能提升.

  • 其它緩存(像 Filter 緩存),在索引的生命周期內(nèi)始終有效矩距。它們不需要在每次數(shù)據(jù)改變時(shí)被重建拗盒,因?yàn)閿?shù)據(jù)不會(huì)變化。

  • 寫入單個(gè)大的倒排索引允許數(shù)據(jù)被壓縮锥债,減少磁盤 I/O 和需要被緩存到內(nèi)存的索引的使用量陡蝇。

缺點(diǎn):

  • 當(dāng)對(duì)舊數(shù)據(jù)進(jìn)行刪除時(shí),舊數(shù)據(jù)不會(huì)馬上被刪除哮肚,而是在 .del 文件中被標(biāo)記為刪除登夫。而舊數(shù)據(jù)只能等到段更新時(shí)才能被移除,這樣會(huì)造成大量的空間浪費(fèi)允趟。

  • 若有一條數(shù)據(jù)頻繁的更新悼嫉,每次更新都是新增新的,標(biāo)記舊的拼窥,則會(huì)有大量的空間浪費(fèi)。

  • 每次新增數(shù)據(jù)時(shí)都需要新增一個(gè)段來存儲(chǔ)數(shù)據(jù)蹋凝。當(dāng)段的數(shù)量太多時(shí)鲁纠,對(duì)服務(wù)器的資源例如文件句柄的消耗會(huì)非常大。

  • 在查詢的結(jié)果中包含所有的結(jié)果集鳍寂,需要排除被標(biāo)記刪除的舊數(shù)據(jù)改含,這增加了查詢的負(fù)擔(dān)。

2.1 段合并

由于每當(dāng)刷新一次就會(huì)新建一個(gè)segment(段)迄汛,這樣會(huì)導(dǎo)致短時(shí)間內(nèi)的段數(shù)量暴增捍壤,而segment數(shù)目太多會(huì)帶來較大的麻煩骤视。大量的segment會(huì)影響數(shù)據(jù)的讀性能。每一個(gè)segment都會(huì)消耗文件句柄鹃觉、內(nèi)存和CPU 運(yùn)行周期专酗。

更重要的是,每個(gè)搜索請(qǐng)求都必須輪流檢查每個(gè)segment然后合并查詢結(jié)果盗扇,所以segment越多祷肯,搜索也就越慢。

因此Lucene會(huì)按照一定的策略將segment合并疗隶,合并的時(shí)候會(huì)將那些舊的已刪除文檔從文件系統(tǒng)中清除佑笋。被刪除的文檔不會(huì)被拷貝到新的大segment中。

合并的過程中不會(huì)中斷索引和搜索斑鼻,倒排索引的數(shù)據(jù)結(jié)構(gòu)使得文件的合并是比較容易的蒋纬。

段合并在進(jìn)行索引和搜索時(shí)會(huì)自動(dòng)進(jìn)行,合并進(jìn)程選擇一小部分大小相似的段坚弱,并且在后臺(tái)將它們合并到更大的段中蜀备,這些段既可以是未提交的也可以是已提交的。

合并結(jié)束后老的段會(huì)被刪除史汗,新的段被刷新到磁盤琼掠,同時(shí)寫入一個(gè)包含新段且排除舊的和較小的段的新提交點(diǎn),新的段被打開停撞,可以用來搜索瓷蛙。段合并的計(jì)算量龐大,而且還要吃掉大量磁盤 I/O戈毒,并且段合并會(huì)拖累寫入速率艰猬,如果任其發(fā)展會(huì)影響搜索性能。

ES在默認(rèn)情況下會(huì)對(duì)合并流程進(jìn)行資源限制埋市,所以搜索性能可以得到保證冠桃。

(圖7)

五、寫在最后

作者對(duì)ES的架構(gòu)原理和索引存儲(chǔ)和寫機(jī)制進(jìn)行介紹道宅,ES的整體架構(gòu)體系相對(duì)比較巧妙食听,我們?cè)谶M(jìn)行系統(tǒng)設(shè)計(jì)的時(shí)候可以借鑒其設(shè)計(jì)思路,本文只介紹ES整體架構(gòu)部分污茵,更多的內(nèi)容樱报,后續(xù)作者會(huì)在其他文章中繼續(xù)分享。

作者:vivo官網(wǎng)商城開發(fā)團(tuán)隊(duì)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泞当,一起剝皮案震驚了整個(gè)濱河市迹蛤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖盗飒,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嚷量,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡逆趣,警方通過查閱死者的電腦和手機(jī)蝶溶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汗贫,“玉大人身坐,你說我怎么就攤上這事÷浒” “怎么了部蛇?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長咐蝇。 經(jīng)常有香客問我涯鲁,道長,這世上最難降的妖魔是什么有序? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任抹腿,我火速辦了婚禮,結(jié)果婚禮上旭寿,老公的妹妹穿的比我還像新娘警绩。我一直安慰自己,他們只是感情好盅称,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布肩祥。 她就那樣靜靜地躺著,像睡著了一般缩膝。 火紅的嫁衣襯著肌膚如雪混狠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天疾层,我揣著相機(jī)與錄音将饺,去河邊找鬼。 笑死痛黎,一個(gè)胖子當(dāng)著我的面吹牛予弧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播湖饱,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼桌肴,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了琉历?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旗笔,沒想到半個(gè)月后彪置,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝇恶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年拳魁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撮弧。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡潘懊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贿衍,到底是詐尸還是另有隱情授舟,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布贸辈,位于F島的核電站释树,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏擎淤。R本人自食惡果不足惜奢啥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘴拢。 院中可真熱鬧桩盲,春花似錦、人聲如沸席吴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抢腐。三九已至姑曙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迈倍,已是汗流浹背伤靠。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啼染,地道東北人宴合。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像迹鹅,于是被迫代替她去往敵國和親卦洽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斜棚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容