一造壮、Elasticsearch是什么?
Elasticsearch(簡(jiǎn)稱ES)是一個(gè)分布式骂束、可擴(kuò)展耳璧、實(shí)時(shí)的搜索與數(shù)據(jù)分析引擎。ES不僅僅只是全文搜索展箱,還支持結(jié)構(gòu)化搜索旨枯、數(shù)據(jù)分析、復(fù)雜的語(yǔ)言處理混驰、地理位置和對(duì)象間關(guān)聯(lián)關(guān)系等攀隔。
ES的底層依賴Lucene,Lucene可以說(shuō)是當(dāng)下最先進(jìn)栖榨、高性能昆汹、全功能的搜索引擎庫(kù)。但是Lucene僅僅只是一個(gè)庫(kù)婴栽。為了充分發(fā)揮其功能满粗,你需要使用Java并將Lucene直接集成到應(yīng)用程序中。更糟糕的是愚争,您可能需要獲得信息檢索學(xué)位才能了解其工作原理映皆,因?yàn)長(zhǎng)ucene非常復(fù)雜。
鑒于Lucene如此強(qiáng)大卻難以上手的特點(diǎn)轰枝,誕生了ES捅彻。ES也是使用Java編寫的,它的內(nèi)部使用Lucene做索引與搜索鞍陨,它的目的是隱藏Lucene的復(fù)雜性步淹,取而代之的提供一套簡(jiǎn)單一致的RESTful API。
ES具有如下特點(diǎn):
一個(gè)分布式的實(shí)時(shí)文檔存儲(chǔ)引擎,每個(gè)字段都可以被索引與搜索
一個(gè)分布式實(shí)時(shí)分析搜索引擎贤旷,支持各種查詢和聚合操作
能勝任上百個(gè)服務(wù)節(jié)點(diǎn)的擴(kuò)展广料,并可以支持PB級(jí)別的結(jié)構(gòu)化或者非結(jié)構(gòu)化數(shù)據(jù)
二、為什么要使用ElasticSearch
2.1 關(guān)系型數(shù)據(jù)庫(kù)有什么問(wèn)題幼驶?
傳統(tǒng)的關(guān)系數(shù)據(jù)庫(kù)提供事務(wù)保證艾杏,具有不錯(cuò)的性能,高可靠性盅藻,久經(jīng)歷史考驗(yàn)购桑,而且使用簡(jiǎn)單,功能強(qiáng)大氏淑,同時(shí)也積累了大量的成功案例勃蜘。
后來(lái),隨著訪問(wèn)量的上升假残,幾乎大部分使用 MySQL 架構(gòu)的網(wǎng)站在數(shù)據(jù)庫(kù)上都開(kāi)始出現(xiàn)了性能問(wèn)題缭贡,web 程序不再僅僅專注在功能上,同時(shí)也在追求性能辉懒。
讀寫分離
由于數(shù)據(jù)庫(kù)的寫入壓力增加阳惹,讀寫集中在一個(gè)數(shù)據(jù)庫(kù)上讓數(shù)據(jù)庫(kù)不堪重負(fù),大部分網(wǎng)站開(kāi)始使用主從復(fù)制技術(shù)來(lái)達(dá)到讀寫分離眶俩,以提高讀寫性能和讀庫(kù)的可擴(kuò)展性莹汤。Mysql 的 master-slave 模式成為這個(gè)時(shí)候的網(wǎng)站標(biāo)配了。
分表分庫(kù)
開(kāi)始流行使用分表分庫(kù)來(lái)緩解寫壓力和數(shù)據(jù)增長(zhǎng)的擴(kuò)展問(wèn)題颠印。這個(gè)時(shí)候纲岭,分表分庫(kù)成了一個(gè)熱門技術(shù),也是業(yè)界討論的熱門技術(shù)問(wèn)題线罕。
MySQL 的擴(kuò)展性瓶頸
大數(shù)據(jù)量高并發(fā)環(huán)境下的 MySQL 應(yīng)用開(kāi)發(fā)越來(lái)越復(fù)雜止潮,也越來(lái)越具有技術(shù)挑戰(zhàn)性。分表分庫(kù)的規(guī)則把握都是需要經(jīng)驗(yàn)的闻坚。雖然有像淘寶這樣技術(shù)實(shí)力強(qiáng)大的公司開(kāi)發(fā)了透明的中間件層來(lái)屏蔽開(kāi)發(fā)者的復(fù)雜性沽翔,但是避免不了整個(gè)架構(gòu)的復(fù)雜性兢孝。分庫(kù)分表的子庫(kù)到一定階段又面臨擴(kuò)展問(wèn)題窿凤。還有就是需求的變更,可能又需要一種新的分庫(kù)方式跨蟹。
關(guān)系數(shù)據(jù)庫(kù)很強(qiáng)大雳殊,但是它并不能很好的應(yīng)付所有的應(yīng)用場(chǎng)景。MySQL 的擴(kuò)展性差(需要復(fù)雜的技術(shù)來(lái)實(shí)現(xiàn))窗轩,大數(shù)據(jù)下 IO 壓力大夯秃,表結(jié)構(gòu)更改困難,正是當(dāng)前使用 MySQL 的開(kāi)發(fā)人員面臨的問(wèn)題。
2.2 ElasticSearch有什么優(yōu)勢(shì)仓洼?
非關(guān)系型介陶、搜索引擎、近實(shí)時(shí)搜索與分析色建、高可用哺呜、天然分布式、橫向可擴(kuò)展
2.3 ES使用場(chǎng)景
- 搜索引擎
電商網(wǎng)站的商品搜索箕戳、站內(nèi)搜索某残、模糊查詢、全文檢索服務(wù) - 非關(guān)系型數(shù)據(jù)庫(kù)
業(yè)務(wù)寬表(數(shù)據(jù)庫(kù)字段太多陵吸,查詢太慢玻墅,索引沒(méi)有辦法再做優(yōu)化)
數(shù)據(jù)庫(kù)做統(tǒng)計(jì)查詢 - 大數(shù)據(jù)近實(shí)時(shí)分析引擎
- 日志分析
三、ElasticSearch概念壮虫、原理與實(shí)現(xiàn)
3.1 搜索引擎原理
一次完整的搜索從用戶輸入要查詢的關(guān)鍵詞開(kāi)始澳厢,比如想查找 Lucene 的相關(guān)學(xué)習(xí)資料,我們都會(huì)在 Google 或百度等搜索引擎中輸入關(guān)鍵詞囚似,比如輸入“Lucene 赏酥,全文檢索框架”,之后系統(tǒng)根據(jù)用戶輸入的關(guān)鍵詞返回相關(guān)信息谆构。一次檢索大致可分為四步:
第一步:查詢分析
正常情況下用戶輸入正確的查詢裸扶,比如搜索“里約奧運(yùn)會(huì)”這個(gè)關(guān)鍵詞,用戶輸入正確完成一次搜索搬素,但是搜索通常都是全開(kāi)放的呵晨,任何的用戶輸入都是有可能的,很大一部分還是非嘲境撸口語(yǔ)化和個(gè)性化的摸屠,有時(shí)候還會(huì)存在拼寫錯(cuò)誤,用戶不小心把“淘寶”打成“濤寶”粱哼,這時(shí)候需要用自然語(yǔ)言處理技術(shù)來(lái)做拼寫糾錯(cuò)等處理季二,以正確理解用戶需求。
第二步:分詞技術(shù)
這一步利用自然語(yǔ)言處理技術(shù)將用戶輸入的查詢語(yǔ)句進(jìn)行分詞揭措,如標(biāo)準(zhǔn)分詞會(huì)把“l(fā)ucene全文檢索框架”分成 lucene | 全 | 文|檢|索|框|架|胯舷, IK分詞會(huì)分成: lucene|全文|檢索|框架|,還有簡(jiǎn)單分詞等多種分詞方法。
第三步:關(guān)鍵詞檢索
提交關(guān)鍵詞后在倒排索引庫(kù)中進(jìn)行匹配绊含,倒排索引就是關(guān)鍵詞和文檔之間的對(duì)應(yīng)關(guān)系桑嘶,就像給文檔貼上標(biāo)簽。比如在文檔集中含有 "lucene" 關(guān)鍵詞的有文檔1 躬充、文檔 6逃顶、文檔9讨便,含有 "全文檢索" 關(guān)鍵詞的有文檔1 、文檔6 那么做與運(yùn)算以政,同時(shí)含有 "lucene" 和 "全文檢索" 的文檔就是文檔1和文檔6霸褒,在實(shí)際的搜索中會(huì)有更復(fù)雜的文檔匹配模型。
第四步:搜索排序
對(duì)多個(gè)相關(guān)文檔進(jìn)行相關(guān)度計(jì)算盈蛮、排序傲霸,返回給用戶檢索結(jié)果。
3.2 倒排索引
索引是構(gòu)成搜索引擎的核心技術(shù)之一眉反,索引在日常生活中其實(shí)也是非常常見(jiàn)的昙啄,比如當(dāng)我們看一本書的時(shí)候,我們首先會(huì)看書的目錄寸五,通過(guò)目錄可以快速定位到某一章節(jié)的頁(yè)碼梳凛,加快對(duì)內(nèi)容的查詢速度。
倒排索引梳杏,也常被稱為反向索引韧拒,是一種索引方法,被用來(lái)存儲(chǔ)在全文搜索下某個(gè)單詞在一個(gè)文檔或者一組文檔中的存儲(chǔ)位置的映射十性,它是文檔檢索系統(tǒng)中最常用的數(shù)據(jù)結(jié)構(gòu)叛溢。
下面我們通過(guò)具體實(shí)例深入理解倒排索引,通過(guò)簡(jiǎn)單文檔以小見(jiàn)大劲适,體驗(yàn)倒排索引的建過(guò)程楷掉。
文檔ID | 文檔內(nèi)容 |
---|---|
1 | 人工智能成為互聯(lián)網(wǎng)大會(huì)焦點(diǎn) |
2 | 谷歌推出開(kāi)源人工智能系統(tǒng)工具 |
3 | 互聯(lián)網(wǎng)的未來(lái)在人工智能 |
4 | 谷歌開(kāi)源機(jī)器學(xué)習(xí)工具 |
對(duì)于文檔內(nèi)容,先要經(jīng)過(guò)詞條化處理霞势。與英文不同的是烹植,英文通過(guò)空格分隔單詞,中文的詞與詞之間沒(méi)有明確的分隔符號(hào)愕贡,經(jīng)過(guò)分詞系統(tǒng)進(jìn)行中文分詞以后把矩陣切分成一個(gè)個(gè)的詞條草雕。
詞項(xiàng) | 文檔頻率 | 倒排記錄表 |
---|---|---|
人工 | 3 | 1,2,3 |
智能 | 3 | 1,2,3 |
成為 | 1 | 1 |
互聯(lián)網(wǎng) | 2 | 1,3 |
大會(huì) | 1 | 1 |
焦點(diǎn) | 1 | 1 |
谷歌 | 2 | 2,4 |
推出 | 1 | 2 |
開(kāi)源 | 2 | 2,4 |
系統(tǒng) | 1 | 2 |
工具 | 2 | 2,4 |
的 | 1 | 3 |
未來(lái) | 1 | 3 |
在 | 1 | 3 |
機(jī)器 | 1 | 4 |
學(xué)習(xí) | 1 | 4 |
然而這套索引的實(shí)現(xiàn),要上生產(chǎn)環(huán)境固以,那還遠(yuǎn)著墩虹。這個(gè)世界上那么多單詞,中文憨琳、英文诫钓、日文、韓文 … 每次搜索一個(gè)單詞栽渴,都要全局遍歷一遍尖坤,很明顯不行。
于是有了排序闲擦,我們需要對(duì)單詞進(jìn)行排序慢味,像 B+ 樹(shù)一樣,可以在頁(yè)里實(shí)現(xiàn)二分查找墅冷。
Lucene 的倒排索引纯路,增加了最左邊的一層「字典樹(shù)」term index,它不存儲(chǔ)所有的單詞寞忿,只存儲(chǔ)單詞前綴驰唬,通過(guò)字典樹(shù)找到單詞所在的塊,也就是單詞的大概位置腔彰,再在塊里二分查找叫编,找到對(duì)應(yīng)的單詞,再找到單詞對(duì)應(yīng)的文檔列表霹抛。
Lucene 的實(shí)現(xiàn)會(huì)要更加復(fù)雜搓逾,針對(duì)不同的數(shù)據(jù)結(jié)構(gòu)采用不同的字典索引,使用了FST模型杯拐、BKDTree等結(jié)構(gòu)霞篡。
真實(shí)的倒排記錄也并非一個(gè)鏈表,而是采用了SkipList端逼、BitSet等結(jié)構(gòu)朗兵。
3.3 ElasticSearch如何建立索引
索引的不變性
由于倒排索引的結(jié)構(gòu)特性,在索引建立完成后對(duì)其進(jìn)行修改將會(huì)非常復(fù)雜顶滩。再加上幾層索引嵌套余掖,更讓索引的更新變成了幾乎不可能的動(dòng)作。
所以索性設(shè)計(jì)成不可改變的:倒排索引被寫入磁盤后是不可改變的礁鲁,它永遠(yuǎn)不會(huì)修改浊吏。不變性有重要的價(jià)值:
1.不需要鎖。如果你從來(lái)不更新索引救氯,你就不需要擔(dān)心多進(jìn)程同時(shí)修改數(shù)據(jù)的問(wèn)題找田。
2.一旦索引被讀入內(nèi)核的文件系統(tǒng)緩存,便會(huì)留在哪里着憨,由于其不變性墩衙。只要文件系統(tǒng)緩存中還有足夠的空間,那么大部分讀請(qǐng)求會(huì)直接請(qǐng)求內(nèi)存甲抖,而不會(huì)命中磁盤漆改。這提供了很大的性能提升。
3.其它緩存(像filter緩存)准谚,在索引的生命周期內(nèi)始終有效挫剑。它們不需要在每次數(shù)據(jù)改變時(shí)被重建,因?yàn)閿?shù)據(jù)不會(huì)變化柱衔。
4.寫入單個(gè)大的倒排索引允許數(shù)據(jù)壓縮樊破,減少磁盤 I/O 和 需要被緩存到內(nèi)存的索引的使用量愉棱。
當(dāng)然,一個(gè)不變的索引也有不好的地方哲戚。主要事實(shí)是它是不可變的奔滑,你不能修改它。如果你需要讓一個(gè)新的文檔 可被搜索顺少,你需要重建整個(gè)索引朋其。這要么對(duì)一個(gè)索引所能包含的數(shù)據(jù)量造成了很大的限制,要么對(duì)索引可被更新的頻率造成了很大的限制脆炎。
3.3.1 動(dòng)態(tài)更新索引
怎樣在保留不變性的前提下實(shí)現(xiàn)倒排索引的更新梅猿?答案是: 用更多的索引。
通過(guò)增加新的補(bǔ)充索引來(lái)反映新近的修改秒裕,而不是直接重寫整個(gè)倒排索引袱蚓。每一個(gè)倒排索引都會(huì)被輪流查詢到—?從最早的開(kāi)始—?查詢完后再對(duì)結(jié)果進(jìn)行合并。
Elasticsearch 基于 Lucene, 引入了 按段搜索 的概念簇爆。 每一 段 本身都是一個(gè)倒排索引癞松, 但 索引 在 Lucene 中除表示所有 段 的集合外, 還增加了 提交點(diǎn) 的概念 — 一個(gè)列出了所有已知段的文件入蛆,新的文檔首先被添加到內(nèi)存索引緩存中响蓉,然后寫入到一個(gè)基于磁盤的段。
在 lucene 中查詢是基于 segment哨毁。每個(gè) segment 可以看做是一個(gè)獨(dú)立的 subindex枫甲,在建立索引的過(guò)程中,lucene 會(huì)不斷的 flush 內(nèi)存中的數(shù)據(jù)持久化形成新的 segment扼褪。多個(gè) segment 也會(huì)不斷的被 merge 成一個(gè)大的 segment想幻,在老的 segment 還有查詢?cè)谧x取的時(shí)候,不會(huì)被刪除话浇,沒(méi)有被讀取且被 merge 的 segement 會(huì)被刪除脏毯。
1)數(shù)據(jù)先寫入內(nèi)存buffer,在寫入buffer的同時(shí)將數(shù)據(jù)寫入translog日志文件幔崖,注意:此時(shí)數(shù)據(jù)還沒(méi)有被成功es索引記錄食店,因此無(wú)法搜索到對(duì)應(yīng)數(shù)據(jù);
2)如果buffer快滿了或者到一定時(shí)間赏寇,es就會(huì)將buffer數(shù)據(jù)refresh到一個(gè)新的segment file中吉嫩,但是此時(shí)數(shù)據(jù)不是直接進(jìn)入segment file的磁盤文件,而是先進(jìn)入os cache的嗅定。這個(gè)過(guò)程就是refresh自娩。
每隔1秒鐘,es將buffer中的數(shù)據(jù)寫入一個(gè)新的segment file渠退,因此每秒鐘會(huì)產(chǎn)生一個(gè)新的磁盤文件segment file忙迁,這個(gè)segment file中就存儲(chǔ)最近1秒內(nèi)buffer中寫入的數(shù)據(jù)脐彩。
操作系統(tǒng)中,磁盤文件其實(shí)都有一個(gè)操作系統(tǒng)緩存os cache动漾,因此數(shù)據(jù)寫入磁盤文件之前丁屎,會(huì)先進(jìn)入操作系統(tǒng)級(jí)別的內(nèi)存緩存os cache中荠锭。
一旦buffer中的數(shù)據(jù)被refresh操作旱眯,刷入os cache中,就代表這個(gè)數(shù)據(jù)就可以被搜索到了证九。
這就是為什么es被稱為準(zhǔn)實(shí)時(shí)(NRT删豺,near real-time):因?yàn)閷懭氲臄?shù)據(jù)默認(rèn)每隔1秒refresh一次,也就是數(shù)據(jù)每隔一秒才能被 es 搜索到愧怜,之后才能被看到呀页,所以稱為準(zhǔn)實(shí)時(shí)。
只要數(shù)據(jù)被輸入os cache中拥坛,buffer就會(huì)被清空蓬蝶,并且數(shù)據(jù)在translog日志文件里面持久化到磁盤了一份,此時(shí)就可以讓這個(gè)segment file的數(shù)據(jù)對(duì)外提供搜索了猜惋。
3)重復(fù)1~2步驟丸氛,新的數(shù)據(jù)不斷進(jìn)入buffer和translog,不斷將buffer數(shù)據(jù)寫入一個(gè)又一個(gè)新的segment file中去著摔,每次refresh完缓窜,buffer就會(huì)被清空,同時(shí)translog保留一份日志數(shù)據(jù)谍咆。隨著這個(gè)過(guò)程推進(jìn)禾锤,translog文件會(huì)不斷變大。當(dāng)translog文件達(dá)到一定程度時(shí)摹察,就會(huì)執(zhí)行commit操作恩掷。
4)commit操作發(fā)生第一步,就是將buffer中現(xiàn)有數(shù)據(jù)refresh到os cache中去供嚎,清空buffer黄娘。
5)將一個(gè) commit point 寫入磁盤文件,里面標(biāo)識(shí)著這個(gè) commit point 對(duì)應(yīng)的所有 segment file查坪,同時(shí)強(qiáng)行將 os cache 中目前所有的數(shù)據(jù)都 fsync 到磁盤文件中去寸宏。
6)將現(xiàn)有的translog清空,然后再次重啟啟用一個(gè)translog偿曙,此時(shí)commit操作完成氮凝。
translog日志文件的作用是什么?
在你執(zhí)行commit操作之前望忆,數(shù)據(jù)要么是停留在buffer中罩阵,要么是停留在os cache中竿秆,無(wú)論是buffer還是os cache都是內(nèi)存,一旦這臺(tái)機(jī)器死了稿壁,內(nèi)存中的數(shù)據(jù)就全丟了幽钢。
因此需要將數(shù)據(jù)對(duì)應(yīng)的操作寫入一個(gè)專門的日志文件,也就是translog日志文件傅是,一旦此時(shí)機(jī)器宕機(jī)匪燕,再次重啟的時(shí)候,es會(huì)自動(dòng)讀取translog日志文件中的數(shù)據(jù)喧笔,恢復(fù)到內(nèi)存buffer和os cache中去帽驯。
綜上可以看出:
es是準(zhǔn)實(shí)時(shí)的,因此數(shù)據(jù)寫入1秒后才可以搜索到书闸。
如果translog是異步寫入的話尼变,es可能會(huì)丟失數(shù)據(jù):有n秒的數(shù)據(jù)停留在buffer、translog的os cache浆劲、segment file的os cache中嫌术,也就是這n秒的數(shù)據(jù)不在磁盤上,此時(shí)如果宕機(jī)牌借,會(huì)導(dǎo)致n秒的數(shù)據(jù)丟失廊移。
translog
寫入ES的數(shù)據(jù)首先會(huì)被寫入translog文件醒颖,該文件持久化到磁盤鲤桥,保證服務(wù)器宕機(jī)的時(shí)候數(shù)據(jù)不會(huì)丟失卑吭,由于順序?qū)懘疟P,速度也會(huì)很快丙躏。
同步寫入:每次寫入請(qǐng)求執(zhí)行的時(shí)候择示,translog在fsync到磁盤之后,才會(huì)給客戶端返回成功
異步寫入:寫入請(qǐng)求緩存在內(nèi)存中晒旅,每經(jīng)過(guò)固定時(shí)間之后才會(huì)fsync到磁盤栅盲,寫入量很大,對(duì)于數(shù)據(jù)的完整性要求又不是非常嚴(yán)格的情況下废恋,可以開(kāi)啟異步寫入
refresh
經(jīng)過(guò)固定的時(shí)間谈秫,或者手動(dòng)觸發(fā)之后,將內(nèi)存中的數(shù)據(jù)構(gòu)建索引生成segment鱼鼓,寫入文件系統(tǒng)緩沖區(qū)
commit/flush
超過(guò)固定的時(shí)間拟烫,或者translog文件過(guò)大之后,觸發(fā)flush操作:
- 內(nèi)存的buffer被清空迄本,相當(dāng)于進(jìn)行一次refresh
- 文件系統(tǒng)緩沖區(qū)中所有segment刷寫到磁盤
- 將一個(gè)包含所有段列表的新的提交點(diǎn)寫入磁盤
- 啟動(dòng)或重新打開(kāi)一個(gè)索引的過(guò)程中使用這個(gè)提交點(diǎn)來(lái)判斷哪些segment隸屬于當(dāng)前分片
- 刪除舊的translog硕淑,開(kāi)啟新的translog
merge
上面提到,每次refresh的時(shí)候,都會(huì)在文件系統(tǒng)緩沖區(qū)中生成一個(gè)segment置媳,后續(xù)flush觸發(fā)的時(shí)候持久化到磁盤于樟。所以,隨著數(shù)據(jù)的寫入拇囊,尤其是refresh的時(shí)間設(shè)置的很短的時(shí)候迂曲,磁盤中會(huì)生成越來(lái)越多的segment:
segment數(shù)目太多會(huì)帶來(lái)較大的麻煩。 每一個(gè)segment都會(huì)消耗文件句柄寥袭、內(nèi)存和cpu運(yùn)行周期路捧。
更重要的是,每個(gè)搜索請(qǐng)求都必須輪流檢查每個(gè)segment纠永,所以segment越多鬓长,搜索也就越慢谒拴。
merge的過(guò)程大致描述如下:
- 磁盤上兩個(gè)小segment:A和B尝江,內(nèi)存中又生成了一個(gè)小segment:C
- A,B被讀取到內(nèi)存中,與內(nèi)存中的C進(jìn)行merge英上,生成了新的更大的segment:D
- 觸發(fā)commit操作炭序,D被fsync到磁盤
- 創(chuàng)建新的提交點(diǎn),刪除A和B苍日,新增D
- 刪除磁盤中的A和B
3.3.2 文檔的更新與刪除
刪除
段是不可改變的惭聂,所以既不能從把文檔從舊的段中移除,也不能修改舊的段來(lái)進(jìn)行反映文檔的更新相恃。
磁盤上的每個(gè)segment都有一個(gè).del文件與它相關(guān)聯(lián)辜纲。當(dāng)發(fā)送刪除請(qǐng)求時(shí),該文檔未被真正刪除拦耐,而是在.del文件中標(biāo)記為已刪除耕腾。此文檔可能仍然能被搜索到,但會(huì)從結(jié)果中過(guò)濾掉杀糯。當(dāng)segment合并時(shí)扫俺,在.del文件中標(biāo)記為已刪除的文檔不會(huì)被包括在新的segment中,也就是說(shuō)merge的時(shí)候會(huì)真正刪除被刪除的文檔固翰。
更新
創(chuàng)建新文檔時(shí)狼纬,Elasticsearch將為該文檔分配一個(gè)版本號(hào)。對(duì)文檔的每次更改都會(huì)產(chǎn)生一個(gè)新的版本號(hào)骂际。當(dāng)執(zhí)行更新時(shí)疗琉,舊版本在.del文件中被標(biāo)記為已刪除,并且新版本在新的segment中寫入索引歉铝。舊版本可能仍然與搜索查詢匹配盈简,但是從結(jié)果中將其過(guò)濾掉。
3.4 并發(fā)控制
在數(shù)據(jù)庫(kù)領(lǐng)域中,有兩種方法通常被用來(lái)確保并發(fā)更新時(shí)變更不會(huì)丟失:
悲觀并發(fā)控制
這種方法被關(guān)系型數(shù)據(jù)庫(kù)廣泛使用送火,它假定有變更沖突可能發(fā)生拳话,因此阻塞訪問(wèn)資源以防止沖突。一個(gè)典型的例子是讀取一行數(shù)據(jù)之前先將其鎖住种吸,確保只有放置鎖的線程能夠?qū)@行數(shù)據(jù)進(jìn)行修改弃衍。
樂(lè)觀并發(fā)控制
Elasticsearch 中使用的這種方法假定沖突是不可能發(fā)生的,并且不會(huì)阻塞正在嘗試的操作坚俗。然而镜盯,如果源數(shù)據(jù)在讀寫當(dāng)中被修改,更新將會(huì)失敗猖败。應(yīng)用程序接下來(lái)將決定該如何解決沖突速缆。例如,可以重試更新恩闻、使用新的數(shù)據(jù)艺糜、或者將相關(guān)情況報(bào)告給用戶。
Elasticsearch 是分布式的幢尚。當(dāng)文檔創(chuàng)建破停、更新或刪除時(shí), 新版本的文檔必須復(fù)制到集群中的其他節(jié)點(diǎn)尉剩。Elasticsearch 也是異步和并發(fā)的真慢,這意味著這些復(fù)制請(qǐng)求被并行發(fā)送,并且到達(dá)目的地時(shí)也許 順序是亂的理茎。Elasticsearch 需要一種方法確保文檔的舊版本不會(huì)覆蓋新的版本黑界。
每個(gè)文檔都有一個(gè) _version (版本)號(hào),當(dāng)文檔被修改時(shí)版本號(hào)遞增皂林。 Elasticsearch 使用這個(gè) _version 號(hào)來(lái)確保變更以正確順序得到執(zhí)行朗鸠。如果舊版本的文檔在新版本之后到達(dá),它可以被簡(jiǎn)單的忽略式撼。
使用內(nèi)部版本號(hào):刪除或者更新數(shù)據(jù)的時(shí)候童社,攜帶_version參數(shù),如果文檔的最新版本不是這個(gè)版本號(hào)著隆,那么操作會(huì)失敗扰楼,這個(gè)版本號(hào)是ES內(nèi)部自動(dòng)生成的,每次操作之后都會(huì)遞增一美浦。
PUT /website/blog/1?version=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
使用外部版本號(hào):ES默認(rèn)采用遞增的整數(shù)作為版本號(hào)弦赖,也可以通過(guò)外部自定義整數(shù)(long類型)作為版本號(hào),例如時(shí)間戳浦辨。通過(guò)添加參數(shù)version_type=external蹬竖,可以使用自定義版本號(hào)。內(nèi)部版本號(hào)使用的時(shí)候,更新或者刪除操作需要攜帶ES索引當(dāng)前最新的版本號(hào)币厕,匹配上了才能成功操作列另。外部版本號(hào)的處理方式和我們之前討論的內(nèi)部版本號(hào)的處理方式有些不同, Elasticsearch 不是檢查當(dāng)前 _version 和請(qǐng)求中指定的版本號(hào)是否相同旦装, 而是檢查當(dāng)前 _version 是否 小于 指定的版本號(hào)页衙。 如果請(qǐng)求成功,外部的版本號(hào)作為文檔的新 _version 進(jìn)行存儲(chǔ)阴绢。
PUT /website/blog/2?version=5&version_type=external
{
"title": "My first external blog entry",
"text": "Starting to get the hang of this..."
}
3.5 批量操作
bulk API 允許在單個(gè)步驟中進(jìn)行多次 create 店乐、 index 、 update 或 delete 請(qǐng)求呻袭。如果你需要索引一個(gè)數(shù)據(jù)流比如日志事件眨八,它可以排隊(duì)和索引數(shù)百或數(shù)千批次。
bulk 請(qǐng)求不是原子的: 不能用它來(lái)實(shí)現(xiàn)事務(wù)控制左电。每個(gè)請(qǐng)求是單獨(dú)處理的廉侧,因此一個(gè)請(qǐng)求的成功或失敗不會(huì)影響其他的請(qǐng)求。
整個(gè)批量請(qǐng)求都需要由接收到請(qǐng)求的節(jié)點(diǎn)加載到內(nèi)存中券腔,因此該請(qǐng)求越大伏穆,其他請(qǐng)求所能獲得的內(nèi)存就越少。 批量請(qǐng)求的大小有一個(gè)最佳值纷纫,大于這個(gè)值,性能將不再提升陪腌,甚至?xí)陆怠?但是最佳值不是一個(gè)固定的值辱魁。它完全取決于硬件、文檔的大小和復(fù)雜度诗鸭、索引和搜索的負(fù)載的整體情況染簇。
3.6 ElasticSearch數(shù)據(jù)類型
Elasticsearch 支持如下簡(jiǎn)單域類型:
- 字符串:
string
- 整數(shù) :
byte
,short
,integer
,long
- 浮點(diǎn)數(shù):
float
,double
- 布爾型:
boolean
- 日期:
date
映射
為了能夠?qū)r(shí)間域視為時(shí)間,數(shù)字域視為數(shù)字强岸,字符串域視為全文或精確值字符串锻弓, Elasticsearch 需要知道每個(gè)域中數(shù)據(jù)的類型。這個(gè)信息包含在映射中蝌箍。
索引中每個(gè)文檔都有 類型 青灼。每種類型都有它自己的 映射 ,或者 模式定義 妓盲。映射定義了類型中的域杂拨,每個(gè)域的數(shù)據(jù)類型,以及Elasticsearch如何處理這些域悯衬。映射也用于配置與類型有關(guān)的元數(shù)據(jù)弹沽。
當(dāng)你索引一個(gè)包含新域的文檔(?之前未曾出現(xiàn)),Elasticsearch 會(huì)使用 動(dòng)態(tài)映射,通過(guò)JSON中基本數(shù)據(jù)類型策橘,嘗試猜測(cè)域類型炸渡,使用如下規(guī)則:
3.7 ElasticSearch集群原理
Document:文檔,指一行數(shù)據(jù)丽已;
Index:索引偶摔,是多個(gè)document的集合(和sql數(shù)據(jù)庫(kù)的表對(duì)應(yīng));
Shard:分片促脉,當(dāng)有大量的文檔時(shí)辰斋,由于內(nèi)存的限制、磁盤處理能力不足瘸味、無(wú)法足夠快的響應(yīng)客戶端的請(qǐng)求等宫仗,一個(gè)節(jié)點(diǎn)可能不夠。這種情況下旁仿,數(shù)據(jù)可以分為較小的分片藕夫。每個(gè)分片放到不同的服務(wù)器上。
當(dāng)你查詢的索引分布在多個(gè)分片上時(shí)枯冈,ES會(huì)把查詢發(fā)送給每個(gè)相關(guān)的分片毅贮,并將結(jié)果組合在一起,而應(yīng)用程序并不知道分片的存在尘奏。即:這個(gè)過(guò)程對(duì)用戶來(lái)說(shuō)是透明的
Replia:副本滩褥,為提高查詢吞吐量或?qū)崿F(xiàn)高可用性,可以使用分片副本炫加。
副本是一個(gè)分片的精確復(fù)制瑰煎,每個(gè)分片可以有零個(gè)或多個(gè)副本。ES中可以有許多相同的分片俗孝,其中之一被選擇更改索引操作酒甸,這種特殊的分片稱為主分片。
當(dāng)主分片丟失時(shí)赋铝,如:該分片所在的數(shù)據(jù)不可用時(shí)插勤,集群將副本提升為新的主分片。
Node:節(jié)點(diǎn)革骨,形成集群的每個(gè)服務(wù)器稱為節(jié)點(diǎn)农尖,一個(gè)節(jié)點(diǎn)可以包含多個(gè)shard
Cluster:集群,ES可以作為一個(gè)獨(dú)立的單個(gè)搜索服務(wù)器苛蒲。不過(guò)卤橄,為了處理大型數(shù)據(jù)集,實(shí)現(xiàn)容錯(cuò)和高可用性臂外,ES可以運(yùn)行在許多互相合作的服務(wù)器上窟扑。這些服務(wù)器的集合稱為集群喇颁。
我們往 Elasticsearch 添加數(shù)據(jù)時(shí)需要用到 索引 —— 保存相關(guān)數(shù)據(jù)的地方。 索引實(shí)際上是指向一個(gè)或者多個(gè)物理 分片 的 邏輯命名空間 嚎货。
一個(gè) 分片 是一個(gè)底層的 工作單元 橘霎,它僅保存了全部數(shù)據(jù)中的一部分。 一個(gè)分片是一個(gè) Lucene 的實(shí)例殖属,以及它本身就是一個(gè)完整的搜索引擎姐叁。 我們的文檔被存儲(chǔ)和索引到分片內(nèi),但是應(yīng)用程序是直接與索引而不是與分片進(jìn)行交互洗显。
Elasticsearch 是利用分片將數(shù)據(jù)分發(fā)到集群內(nèi)各處的外潜。分片是數(shù)據(jù)的容器,文檔保存在分片內(nèi)挠唆,分片又被分配到集群內(nèi)的各個(gè)節(jié)點(diǎn)里处窥。 當(dāng)你的集群規(guī)模擴(kuò)大或者縮小時(shí), Elasticsearch 會(huì)自動(dòng)的在各節(jié)點(diǎn)中遷移分片玄组,使得數(shù)據(jù)仍然均勻分布在集群里滔驾。
一個(gè)分片可以是 主分片或者 副本分片。索引內(nèi)任意一個(gè)文檔都?xì)w屬于一個(gè)主分片俄讹,所以主分片的數(shù)目決定著索引能夠保存的最大數(shù)據(jù)量哆致。
一個(gè)副本分片只是一個(gè)主分片的拷貝。副本分片作為硬件故障時(shí)保護(hù)數(shù)據(jù)不丟失的冗余備份患膛,并為搜索和返回文檔等讀操作提供服務(wù)摊阀。
在索引建立的時(shí)候就已經(jīng)確定了主分片數(shù),但是副本分片數(shù)可以隨時(shí)修改剩瓶。
3.7.1 集群節(jié)點(diǎn)角色
ES集群的服務(wù)器主要分為以下三種角色:
1)master節(jié)點(diǎn):負(fù)責(zé)保存和更新集群的一些元數(shù)據(jù)信息驹溃,之后同步到所有節(jié)點(diǎn),所以每個(gè)節(jié)點(diǎn)都需要保存全量的元數(shù)據(jù)信息:
- 集群的配置信息
- 集群的節(jié)點(diǎn)信息
- 模板template設(shè)置
- 索引以及對(duì)應(yīng)的設(shè)置延曙、mapping、分詞器和別名
- 索引關(guān)聯(lián)到的分片以及分配到的節(jié)點(diǎn)
2)data節(jié)點(diǎn):負(fù)責(zé)數(shù)據(jù)存儲(chǔ)和查詢
3)coordinator節(jié)點(diǎn):
路由索引請(qǐng)求
聚合搜索結(jié)果集
分發(fā)批量索引請(qǐng)求
master選舉
選舉策略
如果集群中存在master亡哄,認(rèn)可該master枝缔,加入集群
如果集群中不存在master,從具有master資格的節(jié)點(diǎn)中選id最小的節(jié)點(diǎn)作為master選舉時(shí)機(jī)
集群?jiǎn)?dòng):后臺(tái)啟動(dòng)線程去ping集群中的節(jié)點(diǎn)蚊惯,按照上述策略從具有master資格的節(jié)點(diǎn)中選舉出master
現(xiàn)有的master離開(kāi)集群:后臺(tái)一直有一個(gè)線程定時(shí)ping master節(jié)點(diǎn)愿卸,超過(guò)一定次數(shù)沒(méi)有ping成功之后,重新進(jìn)行master的選舉避免腦裂
腦裂問(wèn)題是采用master-slave模式的分布式集群普遍需要關(guān)注的問(wèn)題截型,腦裂一旦出現(xiàn)趴荸,會(huì)導(dǎo)致集群的狀態(tài)出現(xiàn)不一致,導(dǎo)致數(shù)據(jù)錯(cuò)誤甚至丟失宦焦。
ES避免腦裂的策略:過(guò)半原則发钝,可以在ES的集群配置中添加一下配置顿涣,避免腦裂的發(fā)生
3.7.2 數(shù)據(jù)副本
ES通過(guò)副本分片的方式,保證集群數(shù)據(jù)的高可用酝豪,同時(shí)增加集群并發(fā)處理查詢請(qǐng)求的能力涛碑,相應(yīng)的,在數(shù)據(jù)寫入階段會(huì)增大集群的寫入壓力孵淘。
數(shù)據(jù)寫入的過(guò)程中蒲障,首先被路由到主分片,寫入成功之后瘫证,將數(shù)據(jù)發(fā)送到副本分片揉阎,為了保證數(shù)據(jù)不丟失,最好保證至少一個(gè)副本分片寫入成功以后才返回客戶端成功背捌。
3.7.3 水平擴(kuò)容
Node 1 和 Node 2 上各有一個(gè)分片被遷移到了新的 Node 3 節(jié)點(diǎn)毙籽,現(xiàn)在每個(gè)節(jié)點(diǎn)上都擁有2個(gè)分片,而不是之前的3個(gè)载萌。 這表示每個(gè)節(jié)點(diǎn)的硬件資源(CPU, RAM, I/O)將被更少的分片所共享惧财,每個(gè)分片的性能將會(huì)得到提升。
分片是一個(gè)功能完整的搜索引擎扭仁,它擁有使用一個(gè)節(jié)點(diǎn)上的所有資源的能力垮衷。 我們這個(gè)擁有6個(gè)分片(3個(gè)主分片和3個(gè)副本分片)的索引可以最大擴(kuò)容到6個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)上存在一個(gè)分片乖坠,并且每個(gè)分片擁有所在節(jié)點(diǎn)的全部資源搀突。
但是如果我們想要擴(kuò)容超過(guò)6個(gè)節(jié)點(diǎn)怎么辦呢?
主分片的數(shù)目在索引創(chuàng)建時(shí)就已經(jīng)確定了下來(lái)熊泵。實(shí)際上仰迁,這個(gè)數(shù)目定義了這個(gè)索引能夠 存儲(chǔ) 的最大數(shù)據(jù)量。(實(shí)際大小取決于你的數(shù)據(jù)顽分、硬件和使用場(chǎng)景徐许。) 但是,讀操作——搜索和返回?cái)?shù)據(jù)——可以同時(shí)被主分片 或 副本分片所處理卒蘸,所以當(dāng)你擁有越多的副本分片時(shí)雌隅,也將擁有越高的吞吐量。
在運(yùn)行中的集群上是可以動(dòng)態(tài)調(diào)整副本分片數(shù)目的缸沃,我們可以按需伸縮集群恰起。讓我們把副本數(shù)從默認(rèn)的 1 增加到 2 :
3.7.4 故障轉(zhuǎn)移
如果我們關(guān)閉第一個(gè)節(jié)點(diǎn),這時(shí)集群的狀態(tài)為:
我們關(guān)閉的節(jié)點(diǎn)是一個(gè)主節(jié)點(diǎn)趾牧。而集群必須擁有一個(gè)主節(jié)點(diǎn)來(lái)保證正常工作检盼,所以發(fā)生的第一件事情就是選舉一個(gè)新的主節(jié)點(diǎn): Node 2 。
在我們關(guān)閉 Node 1 的同時(shí)也失去了主分片 1 和 2 翘单,并且在缺失主分片的時(shí)候索引也不能正常工作吨枉。 如果此時(shí)來(lái)檢查集群的狀況蹦渣,我們看到的狀態(tài)將會(huì)為 red :不是所有主分片都在正常工作。
幸運(yùn)的是东羹,在其它節(jié)點(diǎn)上存在著這兩個(gè)主分片的完整副本剂桥, 所以新的主節(jié)點(diǎn)立即將這些分片在 Node 2 和 Node 3 上對(duì)應(yīng)的副本分片提升為主分片。
3.7.5 路由機(jī)制
當(dāng)索引一個(gè)文檔的時(shí)候属提,文檔會(huì)被存儲(chǔ)到一個(gè)主分片中权逗。 Elasticsearch 如何知道一個(gè)文檔應(yīng)該存放到哪個(gè)分片中呢?當(dāng)我們創(chuàng)建文檔時(shí)冤议,它如何決定這個(gè)文檔應(yīng)當(dāng)被存儲(chǔ)在分片 1 還是分片 2 中呢斟薇?
首先這肯定不會(huì)是隨機(jī)的,否則將來(lái)要獲取文檔的時(shí)候我們就不知道從何處尋找了恕酸。實(shí)際上堪滨,這個(gè)過(guò)程是根據(jù)下面這個(gè)公式?jīng)Q定的:
shard = hash(routing) % number_of_primary_shards
routing 是一個(gè)可變值,默認(rèn)是文檔的 _id 蕊温,也可以設(shè)置成一個(gè)自定義的值袱箱。 routing 通過(guò) hash 函數(shù)生成一個(gè)數(shù)字,然后這個(gè)數(shù)字再除以 number_of_primary_shards (主分片的數(shù)量)后得到 余數(shù) 义矛。這個(gè)分布在 0 到 number_of_primary_shards-1 之間的余數(shù)发笔,就是我們所尋求的文檔所在分片的位置。
這就解釋了為什么我們要在創(chuàng)建索引的時(shí)候就確定好主分片的數(shù)量 并且永遠(yuǎn)不會(huì)改變這個(gè)數(shù)量:因?yàn)槿绻麛?shù)量變化了凉翻,那么所有之前路由的值都會(huì)無(wú)效了讨,文檔也再也找不到了。
3.7.6 新建制轰、索引前计、刪除文檔
新建、索引和刪除請(qǐng)求都是寫操作垃杖, 必須在主分片上面完成之后才能被復(fù)制到相關(guān)的副本分片男杈。
以下是在主副分片和任何副本分片上面 成功新建,索引和刪除文檔所需要的步驟順序:
- 客戶端向 Node 1 發(fā)送新建调俘、索引或者刪除請(qǐng)求势就。
- 節(jié)點(diǎn)使用文檔的 _id 確定文檔屬于分片 0 。請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到 Node 3脉漏,因?yàn)榉制?0 的主分片目前被分配在 Node 3 上。
- Node 3 在主分片上面執(zhí)行請(qǐng)求袖牙。如果成功了侧巨,它將請(qǐng)求并行轉(zhuǎn)發(fā)到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都報(bào)告成功, Node 3 將向協(xié)調(diào)節(jié)點(diǎn)報(bào)告成功鞭达,協(xié)調(diào)節(jié)點(diǎn)向客戶端報(bào)告成功司忱。
在客戶端收到成功響應(yīng)時(shí)皇忿,文檔變更已經(jīng)在主分片和所有副本分片執(zhí)行完成,變更是安全的坦仍。
3.7.7 查詢文檔
可以從主分片或者從其它任意副本分片檢索文檔
以下是從主分片或者副本分片檢索文檔的步驟順序:
- 客戶端向 Node 1 發(fā)送獲取請(qǐng)求鳍烁。
- 節(jié)點(diǎn)使用文檔的 _id 來(lái)確定文檔屬于分片 0 。分片 0 的副本分片存在于所有的三個(gè)節(jié)點(diǎn)上繁扎。 在這種情況下幔荒,它將請(qǐng)求轉(zhuǎn)發(fā)到 Node 2 。
- Node 2 將文檔返回給 Node 1 梳玫,然后將文檔返回給客戶端爹梁。
在處理讀取請(qǐng)求時(shí),協(xié)調(diào)結(jié)點(diǎn)在每次請(qǐng)求的時(shí)候都會(huì)通過(guò)輪詢所有的副本分片來(lái)達(dá)到負(fù)載均衡提澎。
在文檔被檢索時(shí)姚垃,已經(jīng)被索引的文檔可能已經(jīng)存在于主分片上但是還沒(méi)有復(fù)制到副本分片。 在這種情況下盼忌,副本分片可能會(huì)報(bào)告文檔不存在积糯,但是主分片可能成功返回文檔。 一旦索引請(qǐng)求成功返回給用戶谦纱,文檔在主分片和副本分片都是可用的看成。
3.7.8 更新文檔
以下是部分更新一個(gè)文檔的步驟:
- 客戶端向 Node 1 發(fā)送更新請(qǐng)求。
- 它將請(qǐng)求轉(zhuǎn)發(fā)到主分片所在的 Node 3 服协。
- Node 3 從主分片檢索文檔绍昂,修改 _source 字段中的 JSON ,并且嘗試重新索引主分片的文檔偿荷。 如果文檔已經(jīng)被另一個(gè)進(jìn)程修改窘游,它會(huì)重試步驟 3 ,超過(guò) retry_on_conflict 次后放棄跳纳。
- 如果 Node 3 成功地更新文檔忍饰,它將新版本的文檔并行轉(zhuǎn)發(fā)到 Node 1 和 Node 2 上的副本分片,重新建立索引寺庄。 一旦所有副本分片都返回成功艾蓝, Node 3 向協(xié)調(diào)節(jié)點(diǎn)也返回成功,協(xié)調(diào)節(jié)點(diǎn)向客戶端返回成功斗塘。
3.7.9 分布式檢索
一個(gè) CRUD 操作只對(duì)單個(gè)文檔進(jìn)行處理赢织,文檔的唯一性由 _index
, _type
, 和 routing
values的組合來(lái)確定。這表示我們確切的知道集群中哪個(gè)分片含有此文檔馍盟。
搜索需要一種更加復(fù)雜的執(zhí)行模型因?yàn)槲覀儾恢啦樵儠?huì)命中哪些文檔: 這些文檔有可能在集群的任何分片上于置。一個(gè)搜索請(qǐng)求必須詢問(wèn)我們關(guān)注的索引(index or indices)的所有分片的某個(gè)副本來(lái)確定它們是否含有任何匹配的文檔。
但是找到所有的匹配文檔僅僅完成事情的一半贞岭。在 search 接口返回一個(gè) page 結(jié)果之前八毯,多分片中的結(jié)果必須組合成單個(gè)排序列表搓侄。 為此,搜索被執(zhí)行成一個(gè)兩階段過(guò)程话速,我們稱之為 query then fetch 讶踪。
查詢階段
在初始查詢階段時(shí),查詢會(huì)廣播到索引中每一個(gè)分片拷貝(主分片或者副本分片)泊交。 每個(gè)分片在本地執(zhí)行搜索并構(gòu)建一個(gè)匹配文檔的優(yōu)先隊(duì)列乳讥。
查詢階段包含以下三個(gè)步驟:
- 客戶端發(fā)送一個(gè)
search
請(qǐng)求到Node 3
,Node 3
會(huì)創(chuàng)建一個(gè)大小為from + size
的空優(yōu)先隊(duì)列活合。 -
Node 3
將查詢請(qǐng)求轉(zhuǎn)發(fā)到索引的每個(gè)主分片或副本分片中雏婶。每個(gè)分片在本地執(zhí)行查詢并添加結(jié)果到大小為from + size
的本地有序優(yōu)先隊(duì)列中。 - 每個(gè)分片返回各自優(yōu)先隊(duì)列中所有文檔的 ID 和排序值給協(xié)調(diào)節(jié)點(diǎn)白指,也就是
Node 3
留晚,它合并這些值到自己的優(yōu)先隊(duì)列中來(lái)產(chǎn)生一個(gè)全局排序后的結(jié)果列表。
當(dāng)一個(gè)搜索請(qǐng)求被發(fā)送到某個(gè)節(jié)點(diǎn)時(shí)告嘲,這個(gè)節(jié)點(diǎn)就變成了協(xié)調(diào)節(jié)點(diǎn)错维。 這個(gè)節(jié)點(diǎn)的任務(wù)是廣播查詢請(qǐng)求到所有相關(guān)分片并將它們的響應(yīng)整合成全局排序后的結(jié)果集合,這個(gè)結(jié)果集合會(huì)返回給客戶端橄唬。
協(xié)調(diào)節(jié)點(diǎn)將這些分片級(jí)的結(jié)果合并到自己的有序優(yōu)先隊(duì)列里赋焕,它代表了全局排序結(jié)果集合。至此查詢過(guò)程結(jié)束仰楚。
取回階段
查詢階段標(biāo)識(shí)哪些文檔滿足搜索請(qǐng)求隆判,但是我們?nèi)匀恍枰』剡@些文檔,這是取回階段的任務(wù)僧界。
分布式階段由以下步驟構(gòu)成:
- 協(xié)調(diào)節(jié)點(diǎn)辨別出哪些文檔需要被取回并向相關(guān)的分片提交多個(gè) GET 請(qǐng)求侨嘀。
- 每個(gè)分片加載并 豐富 文檔,如果有需要的話捂襟,接著返回文檔給協(xié)調(diào)節(jié)點(diǎn)咬腕。
- 一旦所有的文檔都被取回了,協(xié)調(diào)節(jié)點(diǎn)返回結(jié)果給客戶端葬荷。
協(xié)調(diào)節(jié)點(diǎn)首先決定哪些文檔確實(shí)需要被取回涨共。例如,如果我們的查詢指定了 { "from": 90, "size": 10 } 宠漩,最初的90個(gè)結(jié)果會(huì)被丟棄举反,只有從第91個(gè)開(kāi)始的10個(gè)結(jié)果需要被取回。這些文檔可能來(lái)自和最初搜索請(qǐng)求有關(guān)的一個(gè)扒吁、多個(gè)甚至全部分片照筑。
深分頁(yè)
每個(gè)分片必須先創(chuàng)建一個(gè) from + size 長(zhǎng)度的隊(duì)列,協(xié)調(diào)節(jié)點(diǎn)需要根據(jù) number_of_shards * (from + size) 排序文檔,來(lái)找到被包含在 size 里的文檔凝危。
取決于你的文檔的大小,分片的數(shù)量和你使用的硬件晨逝,給 10,000 到 50,000 的結(jié)果文檔深分頁(yè)( 1,000 到 5,000 頁(yè))是完全可行的蛾默。但是使用足夠大的 from 值,排序過(guò)程可能會(huì)變得非常沉重捉貌,使用大量的CPU支鸡、內(nèi)存和帶寬。
四趁窃、ElasticSearch實(shí)際使用過(guò)程中會(huì)有什么問(wèn)題
4.1 分片的設(shè)定
分片數(shù)過(guò)小牧挣,數(shù)據(jù)寫入形成瓶頸,無(wú)法水平拓展
分片數(shù)過(guò)多醒陆,每個(gè)分片都是一個(gè)lucene的索引瀑构,分片過(guò)多將會(huì)占用過(guò)多資源
如何計(jì)算分片數(shù)
需要注意分片數(shù)量最好設(shè)置為節(jié)點(diǎn)數(shù)的整數(shù)倍,保證每一個(gè)主機(jī)的負(fù)載是差不多一樣的刨摩,特別的寺晌,如果是一個(gè)主機(jī)部署多個(gè)實(shí)例的情況,更要注意這一點(diǎn)澡刹,否則可能遇到其他主機(jī)負(fù)載正常呻征,就某個(gè)主機(jī)負(fù)載特別高的情況。
一般我們根據(jù)每天的數(shù)據(jù)量來(lái)計(jì)算分片罢浇,保持每個(gè)分片的大小在 50G 以下比較合理陆赋。如果還不能滿足要求,那么可能需要在索引層面通過(guò)拆分更多的索引或者通過(guò)別名 + 按小時(shí) 創(chuàng)建索引的方式來(lái)實(shí)現(xiàn)了嚷闭。
4.2 ES數(shù)據(jù)近實(shí)時(shí)問(wèn)題
ES數(shù)據(jù)寫入之后攒岛,要經(jīng)過(guò)一個(gè)refresh操作之后,才能夠創(chuàng)建索引凌受,進(jìn)行查詢阵子。但是get查詢很特殊,數(shù)據(jù)實(shí)時(shí)可查胜蛉。
ES5.0之前translog可以提供實(shí)時(shí)的CRUD挠进,get查詢會(huì)首先檢查translog中有沒(méi)有最新的修改,然后再嘗試去segment中對(duì)id進(jìn)行查找誊册。5.0之后领突,為了減少translog設(shè)計(jì)的負(fù)責(zé)性以便于再其他更重要的方面對(duì)translog進(jìn)行優(yōu)化,所以取消了translog的實(shí)時(shí)查詢功能案怯。
get查詢的實(shí)時(shí)性君旦,通過(guò)每次get查詢的時(shí)候,如果發(fā)現(xiàn)該id還在內(nèi)存中沒(méi)有創(chuàng)建索引,那么首先會(huì)觸發(fā)refresh操作金砍,來(lái)讓id可查局蚀。
4.3 深分頁(yè)問(wèn)題
解決方案1:服務(wù)端緩存 Scan and scroll API
為了返回某一頁(yè)記錄,其實(shí)我們拋棄了其他的大部分已經(jīng)排好序的結(jié)果恕稠。那么簡(jiǎn)單點(diǎn)就是把這個(gè)結(jié)果緩存起來(lái)琅绅,下次就可以用上了。根據(jù)這個(gè)思路鹅巍,ES提供了Scroll API千扶。它概念上有點(diǎn)像傳統(tǒng)數(shù)據(jù)庫(kù)的游標(biāo)(cursor)。
scroll調(diào)用本質(zhì)上是實(shí)時(shí)創(chuàng)建了一個(gè)快照(snapshot)骆捧,然后保持這個(gè)快照一個(gè)指定的時(shí)間澎羞,這樣,下次請(qǐng)求的時(shí)候就不需要重新排序了敛苇。從這個(gè)方面上來(lái)說(shuō)妆绞,scroll就是一個(gè)服務(wù)端的緩存。既然是緩存接谨,就會(huì)有下面兩個(gè)問(wèn)題:
- 一致性問(wèn)題摆碉。ES的快照就是產(chǎn)生時(shí)刻的樣子了,在過(guò)期之前的所有修改它都視而不見(jiàn)脓豪。
- 服務(wù)端開(kāi)銷巷帝。ES這里會(huì)為每一個(gè)scroll操作保留一個(gè)查詢上下文(Search context)。ES默認(rèn)會(huì)合并多個(gè)小的索引段(segment)成大的索引段來(lái)提供索引速度扫夜,在這個(gè)時(shí)候小的索引段就會(huì)被刪除楞泼。但是在scroll的時(shí)候,如果ES發(fā)現(xiàn)有索引段正處于使用中笤闯,那么就不會(huì)對(duì)它們進(jìn)行合并堕阔。這意味著需要更多的文件描述符以及比較慢的索引速度。
其實(shí)這里還有第三個(gè)問(wèn)題颗味,但是它不是緩存的問(wèn)題超陆,而是因?yàn)镋S采用的游標(biāo)機(jī)制導(dǎo)致的。就是你只能順序的掃描浦马,不能隨意的跳頁(yè)时呀。而且還要求客戶每次請(qǐng)求都要帶上”游標(biāo)”。
解決方案2:Search After
Scroll API相對(duì)于from+size方式當(dāng)然是性能好很多晶默,但是也有如下問(wèn)題:
- Search context開(kāi)銷不小谨娜。
- 是一個(gè)臨時(shí)快照,并不是實(shí)時(shí)的分頁(yè)結(jié)果磺陡。
針對(duì)這些問(wèn)題趴梢,ES 5.0 開(kāi)始推出了Search After機(jī)制可以提供了更實(shí)時(shí)的游標(biāo)(live cursor)漠畜。它的思想是利用上一頁(yè)的分頁(yè)結(jié)果來(lái)提高下一頁(yè)的分頁(yè)請(qǐng)求。
參考
Mastering Elasticsearch
從原理到應(yīng)用坞靶,Elasticsearch詳解
https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
https://www.elastic.co/cn/blog/frame-of-reference-and-roaring-bitmaps
Lucene8.0新特征 DocValues改進(jìn)
談一談es的優(yōu)勢(shì)和限制
聊聊MySQL憔狞、HBase、ES的特點(diǎn)和區(qū)別
NoSQL 開(kāi)篇——為什么要使用 NoSQL
為什么使用NoSQL
分布式環(huán)境下的分頁(yè)
Lucene 查詢?cè)砑敖馕?/a>
https://www.cnblogs.com/sessionbest/articles/8689030.html