滬江搜索平臺(tái)化之路

作者:曹林華
本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明作者及出處

背景

隨著滬江業(yè)務(wù)的高速發(fā)展以及數(shù)據(jù)爆炸式的增長(zhǎng),當(dāng)前公司各產(chǎn)線都有關(guān)于搜索方面的需求,但是目前的搜索服務(wù)系統(tǒng)由于架構(gòu)與業(yè)務(wù)上的設(shè)計(jì),不能很好的滿足各個(gè)業(yè)務(wù)線的期望,主要體現(xiàn)下面三個(gè)問(wèn)題:

  1. 不能支持對(duì)語(yǔ)句級(jí)別的搜索,大量業(yè)務(wù)相關(guān)的屬性根本無(wú)法實(shí)現(xiàn)
  2. 沒(méi)有任何搜索相關(guān)的指標(biāo)評(píng)價(jià)體系
  3. 擴(kuò)展性與維護(hù)性特別差

基于現(xiàn)狀,對(duì)行業(yè)內(nèi)的搜索服務(wù)做出充分調(diào)研,確認(rèn)使用 ElasticSearch 做底層索引存儲(chǔ),同時(shí)重新設(shè)計(jì)現(xiàn)有搜索服務(wù),使其滿足業(yè)務(wù)方對(duì)維護(hù)性、定制化搜索排序方面的需求。

整體技術(shù)架構(gòu)

滬江搜索服務(wù)底層基于分布式搜索引擎 ElasticSearch,ElasticSearch 是一個(gè)基于 Lucene 構(gòu)建的開(kāi)源,分布式,RESTful搜索引擎;能夠達(dá)到近實(shí)時(shí)搜索,穩(wěn)定,可靠,快速響應(yīng)的要求。

image

搜索服務(wù)整體分為 5 個(gè)子系統(tǒng)

  • 搜索服務(wù)(Search Server) : 提供搜索與查詢的功能
  • 更新服務(wù)(Index Server) : 提供增量更新與全量更新的功能
  • Admin 控制臺(tái) : 提供UI界面,方便索引相關(guān)的維護(hù)操作
  • ElasticSearch 存儲(chǔ)系統(tǒng) : 底層索引數(shù)據(jù)存儲(chǔ)服務(wù)
  • 監(jiān)控平臺(tái): 提供基于 ELK 日志與 zabbix 的監(jiān)控

外部系統(tǒng)接口設(shè)計(jì)

image
  • 查詢接口
    • 查詢接口提供http的調(diào)用方式,當(dāng)出現(xiàn)跨機(jī)房訪問(wèn)的時(shí)候,請(qǐng)使用http接口,其余都可以使用dubbo RPC調(diào)用
  • 增量更新接口
    • 數(shù)據(jù)增量更新接口采用提供MQ的方式接入。當(dāng)業(yè)務(wù)方出現(xiàn)數(shù)據(jù)更新的時(shí)候,只需將數(shù)據(jù)推送到對(duì)應(yīng)的MQ通道中即可。更新服務(wù)會(huì)監(jiān)聽(tīng)每個(gè)業(yè)務(wù)方通道,及時(shí)將數(shù)據(jù)更新到ElasticSearch中
  • 全量索引接口
    • 更新服務(wù)會(huì)調(diào)用業(yè)務(wù)方提供的全量Http接口(該接口需提供分頁(yè)查詢等功能)

全量更新

眾所周知,全量更新的功能在搜索服務(wù)中是必不可少的一環(huán)。它主要能解決以下三個(gè)問(wèn)題

  • 業(yè)務(wù)方本身系統(tǒng)的故障,出現(xiàn)大量數(shù)據(jù)的丟失
  • 業(yè)務(wù)高速發(fā)展產(chǎn)生增減字段或者修改分詞算法等相關(guān)的需求
  • 業(yè)務(wù)冷啟動(dòng)會(huì)有一次性導(dǎo)入大批量數(shù)據(jù)的需求

基于上面提到的問(wèn)題,我們與業(yè)務(wù)方合作實(shí)現(xiàn)了全量索引。但是在這個(gè)過(guò)程中,我們也發(fā)現(xiàn)一個(gè)通用的問(wèn)題。在進(jìn)行全量更新的時(shí)候,其實(shí)增量更新也在同時(shí)進(jìn)行,如果這兩種更新同時(shí)在進(jìn)行的話,就會(huì)有遇到少量增量更新的數(shù)據(jù)丟失。比如說(shuō)下面這個(gè)場(chǎng)景

  1. 業(yè)務(wù)方發(fā)現(xiàn)自己搜索業(yè)務(wù)index_1數(shù)據(jù)大量數(shù)據(jù)丟失,所以進(jìn)行索引重建。其中index_A是別名,就是我們通常說(shuō)alias,但是底層真正的索引是index_201701011200(建議:索引里面包含時(shí)間屬性,這樣就能知道是什么創(chuàng)建的)
  2. 首先創(chuàng)建一個(gè)新的索引index_201706011200,然后從數(shù)據(jù)中拉出數(shù)據(jù)并插入ES中,并記錄時(shí)間戳T1,最后索引完成的時(shí)間戳為T2,并切換搜索別名index_1指向index_201706011200。
  3. 索引創(chuàng)建成功之后的最新數(shù)據(jù)為T1這個(gè)時(shí)刻的,但是T1到T2這段時(shí)間的數(shù)據(jù),并沒(méi)有獲取出來(lái)。同時(shí)index_201701011200老索引還在繼續(xù)消費(fèi)MQ中的數(shù)據(jù),包括T1到T2時(shí)間內(nèi)的缺少數(shù)據(jù)。
  4. 所以每次索引重建的時(shí)候,都會(huì)缺少T1T2時(shí)間內(nèi)的數(shù)據(jù)。

最后,針對(duì)上面這個(gè)場(chǎng)景,我們提出通過(guò)zookeeper分布式鎖來(lái)暫停index consumer的消費(fèi),具體步驟如下

  1. 創(chuàng)建new_index
  2. 獲取該index 對(duì)應(yīng)的別名,來(lái)修改分布式鎖的狀態(tài)為stop
  3. index consumer監(jiān)控stop狀態(tài),暫停索引數(shù)據(jù)的更新
  4. new_index索引數(shù)據(jù)創(chuàng)建完畢,更新分布式鎖狀態(tài)為start
  5. index consumer監(jiān)控start狀態(tài),繼續(xù)索引數(shù)據(jù)的更新
image

這樣的話,我們就不用擔(dān)心在創(chuàng)建索引的這段時(shí)間內(nèi),數(shù)據(jù)會(huì)有缺少的問(wèn)題。相信大家對(duì)于這種方式解決全量與增量更新數(shù)據(jù)有所體會(huì)。

集群無(wú)縫擴(kuò)容

數(shù)據(jù)量爆炸式的增加,導(dǎo)致我們ES集群最終還是遇到了容量不足的問(wèn)題。在此背景下,同時(shí)結(jié)合ES本身提供的無(wú)縫擴(kuò)容功能,我們最終決定對(duì)線上ES集群進(jìn)行了在線的無(wú)縫擴(kuò)容,將從原來(lái)的3臺(tái)機(jī)器擴(kuò)容為5臺(tái),具體步驟如下

  • 擴(kuò)容前準(zhǔn)備
    • 目前我們線上已經(jīng)有3臺(tái)機(jī)器正在運(yùn)行著,其中node1為master節(jié)點(diǎn),node2和node3為data節(jié)點(diǎn),節(jié)點(diǎn)通信采用單播的形式而非廣播的方式。
    • 準(zhǔn)備2臺(tái)(node4與node5)機(jī)器,其中機(jī)器本身配置與ES配置參數(shù)需保持一致
  • 擴(kuò)容中增加節(jié)點(diǎn)
    • 啟動(dòng)node4與node5(注意一個(gè)一個(gè)啟動(dòng)),啟動(dòng)完成之后,查看node1,2,3,4,5節(jié)點(diǎn)狀態(tài),正常情況下node1,2,3節(jié)點(diǎn)都已發(fā)現(xiàn)node4與node5,并且各節(jié)點(diǎn)之間狀態(tài)應(yīng)該是一致的
  • 重啟master node
    • 修改node1,2,3節(jié)點(diǎn)配置與node4,5保持一致,然后順序重啟node2與node3,一定要優(yōu)先重啟data node,最后我們?cè)谥貑ode1(master node).到此為止,我們的線上ES集群就在線無(wú)縫的擴(kuò)容完畢
image

部署優(yōu)化

  • 查詢與更新服務(wù)分離
    • 查詢服務(wù)與更新服務(wù)在部署上進(jìn)行物理隔離,這樣可以隔離更新服務(wù)的不穩(wěn)定對(duì)查詢服務(wù)的影響
  • 預(yù)留一半內(nèi)存
    • ES底層存儲(chǔ)引擎是基于Lucene,Lucenede的倒排索引是先在內(nèi)存中生成,然后定期以段的形式異步刷新到磁盤上,同時(shí)操作系統(tǒng)也會(huì)把這些段文件緩存起來(lái),以便更快的訪問(wèn)。所以Lucene的性能取決于和OS的交互,如果你把所有的內(nèi)存都分配給Elasticsearch,不留一點(diǎn)給Lucene,那你的全文檢索性能會(huì)很差的。所有官方建議,預(yù)留一半以上內(nèi)存給Lucene使用
  • 內(nèi)存不要超過(guò)32G
    • 跨32G的時(shí)候,會(huì)出現(xiàn)一些現(xiàn)象使得內(nèi)存使用率還不如低于32G,具體原因請(qǐng)參考官方提供的這篇文章 Don’t Cross 32 GB!
  • 盡量避免使用wildcard
    • 其實(shí)使用wildcard查詢,有點(diǎn)類似于在數(shù)據(jù)庫(kù)中使用左右通配符查詢。(如:*foo*z這樣的形式)
  • 設(shè)置合理的刷新時(shí)間
    • ES中默認(rèn)index.refresh_interval參數(shù)為1s。對(duì)于大多數(shù)搜索場(chǎng)景來(lái)說(shuō),數(shù)據(jù)生效時(shí)間不需要這么及時(shí),所以大家可以根據(jù)自己業(yè)務(wù)的容忍程度來(lái)調(diào)整

總結(jié)

本章主要介紹滬江搜索服務(wù)的整體架構(gòu),重點(diǎn)對(duì)全量更新中數(shù)據(jù)一致性的問(wèn)題,ES在線擴(kuò)容做了一定的闡述,同時(shí)列舉了一些滬江在部署ES上做的一些優(yōu)化。本文主要目,通過(guò)讀過(guò)滬江搜索實(shí)踐,能夠給廣大讀者帶來(lái)一些關(guān)于搭建一套通用搜索的建議。另外,關(guān)于搜索服務(wù)中排序以及打分的問(wèn)題,會(huì)在后續(xù)的滬江技術(shù)學(xué)院中發(fā)布。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容