背景
隨着公司業務的高速發展以及數據爆炸式的增加,當前公司各產線都有關於搜索方面的需求,可是之前的搜索服務系統因爲架構與業務上的設計,不能很好的知足各個業務線的指望,主要體現下面三個問題:html
- 不能支持對語句級別的搜索,大量業務相關的屬性根本沒法實現
- 沒有任何搜索相關的指標評價體系
- 擴展性與維護性特別差
基於現狀,對行業內的搜索服務作出充分調研,確認使用 Elasticsearch 作底層索引存儲,同時從新設計現有搜索服務,使其知足業務方對維護性、定製化搜索排序方面的需求。node
總體技術架構
滬江搜索服務底層基於分佈式搜索引擎 ElasticSearch,ElasticSearch 是一個基於 Lucene 構建的開源,分佈式,Restful 搜索引擎;可以達到近實時搜索,穩定,可靠,快速響應的要求。算法
搜索服務總體分爲5個子系統數據庫
- 搜索服務( Search Server ) : 提供搜索與查詢的功能
- 更新服務( Index Server ) : 提供增量更新與全量更新的功能
- Admin 控制檯 : 提供 UI 界面,方便索引相關的維護操做
- ElasticSearch 存儲系統 : 底層索引數據存儲服務
- 監控平臺: 提供基於 ELK 日誌與 zabbix 的監控
外部系統接口設計
- 查詢
- 查詢接口提供 http 的調用方式,當出現跨機房訪問的時候,請使用http接口,其他均可以使用 dubbo RPC 調用
- 增量更新
- 數據增量更新接口採用提供 MQ 的方式接入。當業務方出現數據更新的時候,只需將數據推送到對應的 MQ 通道中便可。更新服務會監聽每一個業務方通道,及時將數據更新到 Elasticsearch 中
- 全量索引
- 更新服務會調用業務方提供的全量 Http 接口(該接口需提供分頁查詢等功能)
全量更新
衆所周知,全量更新的功能在搜索服務中是必不可少的一環。它主要能解決如下三個問題緩存
- 業務方自己系統的故障,出現大量數據的丟失
- 業務高速發展產生增減字段或者修改分詞算法等相關的需求
- 業務冷啓動會有一次性導入大批量數據的需求
基於上面提到的問題,咱們與業務方合做實現了全量索引。可是在這個過程當中,咱們也發現一個通用的問題。在進行全量更新的時候,其實增量更新也在同時進行,若是這兩種更新同時在進行的話,就會有遇到少許增量更新的數據丟失。好比說下面這個場景架構
- 業務方發現本身搜索業務 alias_A 數據大量數據丟失,因此進行索引重建。其中 alias_A 是別名,就是咱們一般說 alias ,可是底層真正的索引是index_201701011200 (建議:索引裏面包含時間屬性,這樣就能知道是什麼建立的)
- 首先建立一個新的索引 index_201706011200,而後從數據中拉出數據並插入ES 中,並記錄時間戳T1,最後索引完成的時間戳爲 T2 ,並切換搜索別名index_1 指向 index_201706011200。
- 索引建立成功以後的最新數據爲T1這個時刻的,可是 T1 到 T2 這段時間的數據,並無獲取出來。同時 index_201701011200 老索引還在繼續消費 MQ 中的數據,包括 T1 到 T2 時間內的缺乏數據。
- 因此每次索引重建的時候,都會缺乏 T1 到 T2 時間內的數據。
最後,針對上面這個場景,咱們提出經過 zookeeper 分佈式鎖來暫停 index consumer 的消費,具體步驟以下異步
- 建立 new_index
- 獲取該 index 對應的別名,來修改分佈式鎖的狀態爲 stop
- index consumer 監控 stop 狀態,暫停索引數據的更新
- new_index 索引數據建立完畢,更新分佈式鎖狀態爲start
- index consumer 監控 start 狀態,繼續索引數據的更新
這樣的話,咱們就不用擔憂在建立索引的這段時間內,數據會有缺乏的問題。相信你們對於這種方式解決全量與增量更新數據有所體會。elasticsearch
集羣無縫擴容
數據量爆炸式的增長,致使咱們 ES 集羣最終仍是遇到了容量不足的問題。在此背景下,同時結合 ES 自己提供的無縫擴容功能,咱們最終決定對線上ES集羣進行了在線的無縫擴容,將從原來的 3 臺機器擴容爲 5 臺,具體步驟以下分佈式
- 擴容前準備
- 目前咱們線上已經有 3 臺機器正在運行着,其中 node1 爲 master 節點,node2 和 node3 爲data節點,節點通訊採用單播的形式而非廣播的方式。
- 準備 2 臺( node4 與 node5 )機器,其中機器自己配置與 ES 配置參數需保持一致
- 擴容中增長節點
- 啓動 node4 與 node5 (注意一個一個啓動),啓動完成以後,查看node1,2,3,4,5 節點狀態,正常狀況下 node1,2,3 節點都已發現 node4 與 node5,而且各節點之間狀態應該是一致的
- 重啓 master node
- 修改 node1,2,3節點配置與 node4,5保持一致,而後順序重啓 node2與 node3 ,必定要優先重啓 data node,最後咱們在重啓 node1( master node).到此爲止,咱們的線上 ES 集羣就在線無縫的擴容完畢
部署優化
- 查詢與更新服務分離
- 查詢服務與更新服務在部署上進行物理隔離,這樣能夠隔離更新服務的不穩定對查詢服務的影響
- 預留一半內存
- ES 底層存儲引擎是基於 Lucene ,Lucene 的倒排索引是先在內存中生成,而後按期以段的形式異步刷新到磁盤上,同時操做系統也會把這些段文件緩存起來,以便更快的訪問。因此Lucene的性能取決於和OS的交互,若是你把全部的內存都分配給 Elasticsearch,不留一點給 Lucene,那你的全文檢索性能會不好的。全部官方建議,預留一半以上內存給 Lucene 使用
- 內存不要超過 32G
- 儘可能避免使用 wildcard
- 其實使用 wildcard 查詢,有點相似於在數據庫中使用左右通配符查詢。(如:*foo*z這樣的形式)
- 設置合理的刷新時間
- ES 中默認 index.refresh_interval 參數爲1s。對於大多數搜索場景來講,數據生效時間不須要這麼及時,因此你們能夠根據本身業務的容忍程度來調整
總結
本章主要介紹公司搜索服務的總體架構,重點對全量更新中數據一致性的問題, ES 在線擴容作了必定的闡述,同時列舉了一些公司在部署 ES 上作的一些優化。本文主要目的,但願你們經過閱讀滬江搜索實踐,可以給廣大讀者帶來一些關於搭建一套通用搜索的建議ide