<meta charset="utf-8">
一、es基本組成
elasticsearch設(shè)計(jì)的理念就是分布式搜索引擎评腺,底層其實(shí)還是基于lucene的夏漱,核心思想就是在多臺機(jī)器上啟動多個es進(jìn)程實(shí)例,組成了一個es集群薄疚。
es中存儲數(shù)據(jù)的基本單位是索引碧信,eg:現(xiàn)在要在es中存儲一些訂單數(shù)據(jù),你就應(yīng)該在es中創(chuàng)建一個索引街夭,order_idx,所有的訂單數(shù)據(jù)就都寫到這個索引里面去躏筏,一個索引差不多就是相當(dāng)于是mysql里的一張表板丽。 es基本組成單元,index -> type -> mapping -> document -> field趁尼。
index:想當(dāng)mysql的一張表埃碱。
tyep:type其實(shí)沒法跟mysql做對比,一個index里面可能又多個type酥泞,比如說:訂單相關(guān)的表砚殿,有實(shí)體訂單(手機(jī)、衣服芝囤、鞋子)似炎,又虛擬訂單表(游戲幣、點(diǎn)卡)等悯姊。一個index下面的的多個type里面基本大部分字段都一樣羡藐,只有個別字段不一樣。(很多情況下悯许,一個index里可能就一個type仆嗦,但是確實(shí)如果說是一個index里有多個type的情況,你可以認(rèn)為index是一個類別的表先壕,具體的每個type代表了具體的一個mysql中的表)
mapping:每個type都有一個mapping瘩扼,如果把type認(rèn)定為已個具體的一張表谆甜,那么mapping就可以看成是type的這張表的表結(jié)構(gòu)。
document:表(type)里面的一條數(shù)據(jù)就叫document集绰,這個和mongo很像店印;
field:每個document都有多個field,每個field代表了這個document中的一個字段的值倒慧。
二按摘、es的基本架構(gòu)
一個index,在es里面可以拆分成多個shard(相當(dāng)于kafka的partition(分區(qū)))纫谅,每個shard里面存儲部分?jǐn)?shù)據(jù)炫贤。正是由于這個shard構(gòu)成了分es分布式架構(gòu)的基礎(chǔ)。
每個shard都有一個primary shard付秕,負(fù)責(zé)寫入數(shù)據(jù)兰珍,對應(yīng)的還有幾個replica shard(primary shard的副本),primary shard數(shù)據(jù)寫入之后询吴,會同步到replica shard掠河。
通過這個replica shard數(shù)據(jù)的備份,實(shí)現(xiàn)了es的高可用架構(gòu)猛计。
注:每個節(jié)點(diǎn)的primary shard的副本replica shard不會和primary shard 在同一個節(jié)點(diǎn)上唠摹,如下圖。es集群會選舉一個master節(jié)點(diǎn)奉瘤,這個master節(jié)點(diǎn)負(fù)責(zé)管理工作勾拉,例如維護(hù)索引拉去元數(shù)據(jù),負(fù)責(zé)切換primary shard 和replica shard的身份盗温。如果master節(jié)點(diǎn)宕機(jī)藕赞,會重新選舉一個master節(jié)點(diǎn)。之前master節(jié)點(diǎn)的primary shard 對應(yīng)的replica shard會被新選舉出來的master指定為replica shard卖局,如果之前的機(jī)器恢復(fù)斧蜕,會重新給現(xiàn)在的primary shard重新分配一個replica shard,接著會把數(shù)據(jù)給同步過去砚偶,讓集群恢復(fù)正常批销。
[圖片上傳失敗...(image-826fd9-1573635121131)]
三、es操作數(shù)據(jù)的工作原理蟹演?
客戶端會選擇一個節(jié)點(diǎn)發(fā)送請求過去风钻,這個節(jié)點(diǎn)叫做協(xié)調(diào)節(jié)點(diǎn)(coordinating node),協(xié)調(diào)節(jié)點(diǎn)會對數(shù)據(jù)進(jìn)行路由到對應(yīng)的primary shard上酒请。
寫數(shù)據(jù)原理步驟:
1)骡技、通過協(xié)調(diào)節(jié)點(diǎn)寫入primary shard。先寫入buffer,數(shù)據(jù)在buffer里面是不會被搜索到的布朦,寫入buffer的同時會把數(shù)據(jù)吸入translog日志文件囤萤。
2)、buffer內(nèi)存不足時是趴,或者到一定的時間(這個可以設(shè)置涛舍,默認(rèn)是一秒),es就會把buffer的數(shù)據(jù)refresh到一個新的segment file中唆途,但是在refresh到segement file 之前富雅,es會將buffer里緩存的數(shù)據(jù)寫入 os cache(cpu 高速緩存)。這個時候用戶就可以在客戶端搜索到數(shù)據(jù)了肛搬。這個過程叫refresh没佑。(也可以手動調(diào)用es 的refresh的api)
為什么叫es是準(zhǔn)實(shí)時的?NRT温赔,near real-time蛤奢,準(zhǔn)實(shí)時。默認(rèn)是每隔1秒refresh一次的陶贼,所以es是準(zhǔn)實(shí)時的啤贩,因?yàn)閷懭氲臄?shù)據(jù)1秒之后才能被看到。
3)拜秧、重復(fù)1痹屹、2的步驟數(shù)據(jù)會不斷的被寫入buffer和translog,buffer的數(shù)據(jù)會不斷的生成一個個的segment file,每次refresh腹纳,buffer會被清空痢掠,tanslog 保留,隨著這個過程不斷的推進(jìn)嘲恍,translog會達(dá)到一定的長度,就會觸發(fā)commit操作雄驹。
4)佃牛、commit的第一步,就會先把buffer的數(shù)據(jù)刷新的os cache医舆,然后清空buffer俘侠。
5)、es會將一個commit point寫入磁盤文件蔬将,里面標(biāo)記著這次commit對應(yīng)的segment file爷速。(這點(diǎn)類似于kafka的offset)
6)、commit 會將os cache里面的數(shù)據(jù)強(qiáng)行fsync到磁盤中霞怀。
translog日志文件用來記錄還沒有被持久化到segment file 里的數(shù)據(jù)惫东,一旦機(jī)器重啟,es 會讀取translog里面的數(shù)據(jù),恢復(fù)到buffer和os cache中去廉沮。
7)颓遏、將現(xiàn)有的translog清空,然后在重啟一個tanslog滞时,此時整個commit才算完成叁幢。默認(rèn)每隔30分鐘會自動執(zhí)行一次commit,但是如果translog過大坪稽,也會觸發(fā)commit曼玩。整個commit過程叫flush操作。(也可以通過收到調(diào)用es api 觸發(fā)commit)
8)窒百、寫入translog之前其實(shí)也是先寫入os cache的黍判,默認(rèn)每隔5秒會寫入translog,這樣就有可能會造成五秒數(shù)據(jù)的丟失贝咙,當(dāng)然 也可以手動操作样悟,直接fsync到磁盤,但是這樣性能會很差庭猩。
刪除數(shù)據(jù)操作原理:
1)窟她、刪除的時候同樣客戶端會隨機(jī)到一個節(jié)點(diǎn)上,這個時候會生成一個 .del文件蔼水,將docId標(biāo)記為deleted狀態(tài)震糖。
2)、如果是更新操作趴腋,就是將原來的一條數(shù)據(jù)標(biāo)記為deleted 狀態(tài)吊说,然后重新寫入一條數(shù)據(jù)。
3)优炬、buffer每次refresh一次颁井,就會產(chǎn)生一個segment file,默認(rèn)情況下是一秒,segment file 會越來越多蠢护,此時會定期執(zhí)行merge(合并segment file,多個小的segment file合并成一個大的segment file)雅宾,這時會將標(biāo)記為deleted 數(shù)據(jù)給刪掉,這里其實(shí)也是一個commit point的操作葵硕。
整個es 的寫入操作眉抬,包含四個核心概念:refresh、flush懈凹、translog蜀变、merge
讀數(shù)據(jù)操作原理:
1)、數(shù)據(jù)寫入的時候會自動創(chuàng)建一個docId介评,當(dāng)然整個docId也可以手動指定库北,比如說orderId或者uesrId等。同時在寫入primary shard的時候也是根據(jù)docId進(jìn)行hash 計(jì)算,然后路由到對應(yīng)的 primary shard的 贤惯。
2)洼专、客戶端發(fā)動請求到任意一個節(jié)點(diǎn)時,協(xié)調(diào)節(jié)點(diǎn)會根據(jù)docId進(jìn)行路由孵构,將請求轉(zhuǎn)發(fā)到對應(yīng)的節(jié)點(diǎn)屁商,會使用round-robin隨機(jī)輪訓(xùn)算法,在primary shard 和replica shard中隨機(jī)選擇一個去負(fù)載颈墅,然后把搜到的docId反還給協(xié)調(diào)節(jié)點(diǎn)蜡镶,然后又協(xié)調(diào)節(jié)點(diǎn)去進(jìn)行數(shù)據(jù)的合并、排序恤筛、分頁等操作官还,然后在由協(xié)調(diào)節(jié)點(diǎn)根據(jù)docId去個節(jié)點(diǎn)拉去實(shí)際的document的信息,最終把數(shù)據(jù)返回給客戶端毒坛。
3)望伦、搜索的底層原理是倒排索引。
[圖片上傳失敗...(image-b6189b-1573635121131)]
四煎殷、es搜索優(yōu)化
根據(jù)es 數(shù)據(jù)的寫入原理分析:
在往es寫數(shù)據(jù)的時候屯伞,實(shí)際上都是寫入 os cache,只有在os cache里面的數(shù)據(jù)才能被客戶端給搜索到。
es 的底層嚴(yán)重依賴filesystem cache豪直,所以具體優(yōu)化方案如下:
1)劣摇、filesystem cache內(nèi)存不夠大,那么我們就在數(shù)據(jù)寫入的時候只把可能會出現(xiàn)搜索的字段非存入es,例如:商品信息弓乙,我們可以存商品的名稱末融,價格等相關(guān)信息。這樣在讀數(shù)據(jù)的時候同樣的內(nèi)存就可以讀取更多的數(shù)據(jù)暇韧。(多余的數(shù)據(jù)存入mysql或者采用 es + hbase等架構(gòu))勾习,所以es寫入的數(shù)據(jù)要小于等于或者略微大于es的filesystem file的容量。
2)懈玻、數(shù)據(jù)預(yù)熱
比如:微博可以事先把一些大V语卤,或者說平時看的人很多的數(shù)據(jù),通過后臺的一個系統(tǒng)酪刀,每隔一段時間就去自己觸發(fā)搜索,讓數(shù)據(jù)保持在filesystem file中钮孵。
3)骂倘、冷熱分離
關(guān)于es性能優(yōu)化,數(shù)據(jù)拆分巴席,將大量不搜索的字段历涝,拆分到別的存儲中去,這個就是類似于后面我最后要講的mysql分庫分表的垂直拆分。
es可以做類似于mysql的水平拆分荧库,就是說將大量的訪問很少堰塌,頻率很低的數(shù)據(jù),單獨(dú)寫一個索引分衫,然后將訪問很頻繁的熱數(shù)據(jù)單獨(dú)寫一個索引场刑。將冷數(shù)據(jù)寫入一個索引中,然后熱數(shù)據(jù)寫入另外一個索引中蚪战,這樣可以確保熱數(shù)據(jù)在被預(yù)熱之后牵现,盡量都讓他們留在filesystem os cache里,別讓冷數(shù)據(jù)給沖刷掉
4)邀桑、document模型設(shè)計(jì)
es的聯(lián)合查詢:
寫入es的時候瞎疼,搞成兩個索引,order索引壁畸,orderItem索引
order索引贼急,里面就包含id order_code total_price
orderItem索引,里面寫入進(jìn)去的時候捏萍,就完成join操作太抓,id order_code total_price id order_id goods_id purchase_count price
寫入es的java系統(tǒng)里,就完成關(guān)聯(lián)照弥,將關(guān)聯(lián)好的數(shù)據(jù)直接寫入es中腻异,搜索的時候,就不需要利用es的搜索語法去完成join來搜索了(相當(dāng)于一張表事先冗余關(guān)聯(lián)表的id字段这揣,這個和mongo很像)
5)悔常、分頁性能優(yōu)化
因?yàn)閑s 是分布式的所有的數(shù)據(jù)是不同的primary shard上存儲,假如說要查詢第一百頁的數(shù)據(jù)(每頁十條)给赞,假如又三臺機(jī)器机打,那么每個節(jié)點(diǎn),在查詢的時候都得把自己節(jié)點(diǎn)primary shard的前一百條數(shù)據(jù)給查出來片迅,然后交給協(xié)調(diào)節(jié)點(diǎn)去重新整合残邀,最終拿出第一百頁的十條數(shù)據(jù),這樣的話越往后越慢柑蛇。
方案:
a芥挣、不允許深度分頁。
b耻台、似于app里的推薦商品不斷下拉出來一頁一頁的空免,這種可以采用scroll api 去實(shí)現(xiàn)分頁。
五盆耽、es生產(chǎn)集群的部署架構(gòu)是什么蹋砚?每個索引的數(shù)據(jù)量大概有多少扼菠?每個索引大概有多少個分片?
1)es生產(chǎn)集群我們部署了5臺機(jī)器坝咐,每臺機(jī)器是6核64G的循榆,集群總內(nèi)存是320G
2)我們es集群的日增量數(shù)據(jù)大概是2000萬條,每天日增量數(shù)據(jù)大概是500MB墨坚,每月增量數(shù)據(jù)大概是6億秧饮,15G。目前系統(tǒng)已經(jīng)運(yùn)行了幾個月框杜,現(xiàn)在es集群里數(shù)據(jù)總量大概是100G左右浦楣。
3)目前線上有5個索引(這個結(jié)合你們自己業(yè)務(wù)來,看看自己有哪些數(shù)據(jù)可以放es的)咪辱,每個索引的數(shù)據(jù)量大概是20G振劳,所以這個數(shù)據(jù)量之內(nèi),我們每個索引分配的是8個shard油狂,比默認(rèn)的5個shard多了3個shard历恐。