ElasticSearch作為一款開源的全文搜索引擎在如今的軟件開發(fā)得到了越來越廣泛的應(yīng)用训柴,在業(yè)務(wù)功能開發(fā)方面,可以選用ElasticSearch提供比數(shù)據(jù)庫查詢更強(qiáng)大的搜索方式嘉裤,同時(shí)基于搜索結(jié)果評分(權(quán)重)和高亮讓我們很輕易地通過它實(shí)現(xiàn)一個(gè)站內(nèi)的搜索引擎面哥。
ElasticSearch VS 數(shù)據(jù)庫
剛接觸ElasticSearch(ES)時(shí)我們經(jīng)常將它與數(shù)據(jù)庫類比起來學(xué)習(xí),從結(jié)構(gòu)上:
- Indices類似于數(shù)據(jù)庫的database
- Type類似于數(shù)據(jù)庫的table
- Fields類似于數(shù)據(jù)表的列
- Documents類似于數(shù)據(jù)表的行(即每條記錄)
同時(shí),數(shù)據(jù)庫提供的搜索語法都能在ES上找到影子拂募,比如數(shù)據(jù)庫提供AND、OR邏輯運(yùn)算符窟她,ES中有must, should陈症,而數(shù)據(jù)庫的如“l(fā)ike”等文字匹配功能在ES中則更加強(qiáng)大。
盡管如此震糖,ES本質(zhì)上的定位仍是一個(gè)搜索引擎录肯。NoSQL和ES一樣都有著相同松散的結(jié)構(gòu),雖然我們也有一些討論是否可以用ES來替代非關(guān)系型數(shù)據(jù)庫(撇開ES是不是一種NoSQL)吊说,但是一個(gè)現(xiàn)實(shí)是ES和NoSQL依舊是互有利弊论咏;再者优炬,傳統(tǒng)關(guān)系型數(shù)據(jù)庫的事務(wù)性、多表關(guān)聯(lián)結(jié)構(gòu)也是ES無法提供的厅贪。
所以蠢护,在實(shí)際的開發(fā)過程中,關(guān)系型數(shù)據(jù)庫养涮、NoSQL葵硕、ES依舊是相輔相成的關(guān)系,我們一般只會(huì)在較復(fù)雜的搜索場景下會(huì)選用ES提供搜索服務(wù)贯吓,而其源數(shù)據(jù)依舊來自于數(shù)據(jù)庫贬芥,所以這就引出了ES與數(shù)據(jù)庫之間的數(shù)據(jù)同步問題。
全量數(shù)據(jù)導(dǎo)入
在第一次將存儲(chǔ)在數(shù)據(jù)庫里面的數(shù)據(jù)導(dǎo)入到ES需要執(zhí)行全量導(dǎo)入宣决,當(dāng)后續(xù)有數(shù)據(jù)更新時(shí)通過消息隊(duì)列通知ES更新數(shù)據(jù)。
使用消息隊(duì)列實(shí)現(xiàn)ES增量同步
消息隊(duì)列在軟件開發(fā)領(lǐng)域是一個(gè)十分常見的名詞昏苏。
在操作系統(tǒng)層面尊沸,我們可以利用消息隊(duì)列做進(jìn)程間的通信;在一個(gè)單體應(yīng)用贤惯,比如Android應(yīng)用洼专,利用一個(gè)MessageQueue類來解決UI線程與耗時(shí)子線程之間的界面刷新問題,在物聯(lián)網(wǎng)領(lǐng)域孵构,基于發(fā)布/訂閱模型模型的MQTT協(xié)議被廣泛應(yīng)用于平臺(tái)對海量設(shè)備的消息分發(fā)屁商,而在分布式系統(tǒng),以及最近幾年日益熱門的微服務(wù)架構(gòu)中颈墅,是一個(gè)十分常用的實(shí)現(xiàn)異步消息蜡镶、解耦應(yīng)用、最終一致性的組件恤筛。
常見的消息隊(duì)列采用“發(fā)布-訂閱”模式官还,初入門者幾乎可以認(rèn)為這是個(gè)“觀察者模式”。
目前常用的消息隊(duì)列框架有Kafka毒坛、RabbitMQ望伦。
消息隊(duì)列實(shí)現(xiàn)增量同步的方式,是在主服務(wù)對數(shù)據(jù)庫進(jìn)行創(chuàng)建煎殷、刪除屯伞、修改一條記錄時(shí),發(fā)布一條主題消息給消息隊(duì)列豪直,同時(shí)同步服務(wù)需要訂閱相關(guān)主題劣摇,這樣消息隊(duì)列就可以將更新的記錄轉(zhuǎn)發(fā)給同步服務(wù),同步服務(wù)再根據(jù)消息的內(nèi)容在ES里面進(jìn)行更新記錄顶伞。
消息隊(duì)列實(shí)現(xiàn)增量同步除了可以解耦主服務(wù)和同步服務(wù)饵撑,還有一個(gè)好處就是保證同步的容錯(cuò)性剑梳,比如當(dāng)數(shù)據(jù)庫添加一條記錄時(shí),如果直接采用HTTP的方式(可能是一個(gè)post請求)與同步服務(wù)取得聯(lián)系時(shí)出現(xiàn)連接失敗滑潘、post請求失敗的時(shí)候垢乙,如果不采取任何措施這條記錄就會(huì)無法得到同步。而消息隊(duì)列的失敗重發(fā)的機(jī)制可以很好的解決這個(gè)問題语卤,同時(shí)消息隊(duì)列追逮,F(xiàn)IFO(先進(jìn)先出)的機(jī)制也保證了消息轉(zhuǎn)發(fā)的順序。
ES索引更改后怎樣做無縫重建
ES索引更改發(fā)生在ElasticSearch 索引結(jié)構(gòu)發(fā)生變化粹舵,比如隨著業(yè)務(wù)的發(fā)展對Type中字段的增減以及字段類型的更改钮孵,或者發(fā)生在ES版本升級帶來的結(jié)構(gòu)變化時(shí),例如ES 5.0版本將之前的string類型拆分為text和keyword類型眼滤,當(dāng)我們希望對ES進(jìn)行版本升級時(shí)巴席,那么之前的string類型就不可再用了。
與常見的Web服務(wù)的藍(lán)綠部署實(shí)現(xiàn)無宕機(jī)升級類似诅需,ES無縫升級也可以類比實(shí)現(xiàn)漾唉。Web服務(wù)的藍(lán)綠部署的原理是使用LoadBalancer(負(fù)載均衡器)做流量切換,新舊服務(wù)都有不同的訪問URL堰塌,但是只有LoadBalancer的URL對外可訪問赵刑,即:
- 服務(wù)升級前:負(fù)載均衡指向舊服務(wù)V1
- 服務(wù)升級中:發(fā)布新服務(wù)V2,負(fù)載均衡依舊指向舊服務(wù)场刑,此時(shí)存在新舊服務(wù)同時(shí)存在
- 服務(wù)升級完成:新服務(wù)V2啟動(dòng)完成般此,負(fù)載均衡切換指向,將訪問流量導(dǎo)向新服務(wù)V2
- 服務(wù)升級完成:負(fù)載均衡切換指向后停掉舊服務(wù)V1
ES索引的別名
ES提供了通過索引別名(alias)來訪問索引的方式:比如
curl -XPOST 'http://localhost:9200/_aliases' -d
{
"actions": [
{"add": {"index": "test_20181007", "alias": "test"}}
]
}
就為索引test_20181007
創(chuàng)建了一條別名test
牵现,這樣訪問localhost:9200/test/_search
和localhost:9200/test_20181007/_search
都可以搜索索引里面的內(nèi)容铐懊。
ES的別名的存在為ES的無縫升級和切換提供了可能,類似于負(fù)載均衡切換指向一樣瞎疼,我們可以讓ES別名在升級前后居扒,指向新舊不同版本的索引即可。
ES無縫升級
- 新建帶版本的新索引
PUT /test_v2
{
"settings": { ... any settings ... },
"mappings": {
"type_one": { ... any mappings ... },
}
}
- 暫停增量更新
由于在升級期間我們不希望后續(xù)的記錄更新到舊索引上丑慎,所以需要將消息隊(duì)列進(jìn)行暫停(pause)操作喜喂,在新索引創(chuàng)建成功后再開啟。
- 暫停增量更新
- 執(zhí)行全量數(shù)據(jù)導(dǎo)入
- 切換對外別名指向
一個(gè)別名可以指向多個(gè)索引竿裂,所以我們在添加別名到新索引的同時(shí)必須從舊的索引中刪除它玉吁。這個(gè)操作需要原子化,這意味著我們需要使用 _aliases 操作:
- 切換對外別名指向
POST /_aliases
{
"actions": [
{ "remove": { "index": "test_v1", "alias": "test" }},
{ "add": { "index": "test_v2", "alias": "test" }}
]
}
- 刪除舊索引
DELETE /test_v1
- 開啟增量更新
這樣在升級過程中的數(shù)據(jù)庫中有更新的記錄將會(huì)在新索引上同步
- 開啟增量更新
我的博客即將入駐“云棲社區(qū)”腻异,誠邀技術(shù)同仁一同入駐进副。