產(chǎn)品提了個(gè)每秒 20W 次的檢索需求,架構(gòu)如何演進(jìn)?
產(chǎn)品提了一個(gè)需求:
我想做一個(gè)內(nèi)容檢索功能,不復(fù)雜,100億數(shù)據(jù),每秒10萬查詢而已,兩個(gè)星期能上線嗎?
大部分工程師未必接觸過“搜索內(nèi)核”,但互聯(lián)網(wǎng)業(yè)務(wù),基本會(huì)涉及“檢索”功能。以同城的帖子業(yè)務(wù)場(chǎng)景為例,帖子的標(biāo)題,帖子的內(nèi)容有很強(qiáng)的用戶檢索需求,在業(yè)務(wù)、流量、并發(fā)量逐步遞增的各個(gè)階段,應(yīng)該如何實(shí)現(xiàn)檢索需求呢?

原始階段-LIKE
創(chuàng)業(yè)階段,常常用這種方法來快速實(shí)現(xiàn)。
數(shù)據(jù)在數(shù)據(jù)庫中可能是這么存儲(chǔ)的:
t_tiezi(tid, title, content)滿足標(biāo)題、內(nèi)容的檢索需求可以通過LIKE實(shí)現(xiàn):
select tid from t_tiezi where content like ‘%天通苑%’這種方式確實(shí)能夠快速滿足業(yè)務(wù)需求,存在的問題也顯而易見:
- 效率低,每次需要全表掃描,計(jì)算量大,并發(fā)高時(shí)cpu容易100%;
- 不支持分詞;
初級(jí)階段-全文索引
如何快速提高效率,支持分詞,并對(duì)原有系統(tǒng)架構(gòu)影響盡可能小呢,第一時(shí)間想到的是建立全文索引:
alter table t_tiezi add fulltext(title,content)使用match和against實(shí)現(xiàn)索引字段上的查詢需求。
全文索引能夠快速實(shí)現(xiàn)業(yè)務(wù)上分詞的需求,并且快速提升性能(分詞后倒排,至少不要全表掃描了),但也存在一些問題:
- 由于全文索引利用的是數(shù)據(jù)庫特性,搜索需求和普通CURD需求耦合在數(shù)據(jù)庫中:檢索需求并發(fā)大時(shí),可能影響CURD的請(qǐng)求;CURD并發(fā)大時(shí),檢索會(huì)非常的慢;
- 數(shù)據(jù)量達(dá)到百萬級(jí)別,性能還是會(huì)顯著降低,查詢返回時(shí)間很長,業(yè)務(wù)難以接受;
- 比較難水平擴(kuò)展;
中級(jí)階段-開源外置索引
為了解決全文索引的局限性,當(dāng)數(shù)據(jù)量增加到大幾百萬,千萬級(jí)別時(shí),就要考慮外置索引了。外置索引的核心思路是:索引數(shù)據(jù)與原始數(shù)據(jù)分離,前者滿足搜索需求,后者滿足CURD需求,通過一定的機(jī)制(雙寫,通知,定期重建)來保證數(shù)據(jù)的一致性。
原始數(shù)據(jù)可以繼續(xù)使用Mysql來存儲(chǔ),外置索引如何實(shí)施?
Solr,Lucene,ES都是常見的開源方案。其中,ES(ElasticSearch)是目前最為流行的。
Lucene雖好,潛在的不足是:
- Lucene只是一個(gè)庫,需要自己做服務(wù),自己實(shí)現(xiàn)高可用/可擴(kuò)展/負(fù)載均衡等復(fù)雜特性;
- Lucene只支持Java,如果要支持其他語言,必須得自己做服務(wù);
- Lucene不友好,這是很致命的,非常復(fù)雜,使用者往往需要深入了解搜索的知識(shí)來理解它的工作原理,為了屏蔽其復(fù)雜性,還是得自己做服務(wù);
為了改善Lucene的各項(xiàng)不足,解決方案都是“封裝一個(gè)接口友好的服務(wù),屏蔽底層復(fù)雜性”,于是有了ES:
- ES是一個(gè)以Lucene為內(nèi)核來實(shí)現(xiàn)搜索功能,提供RESTful接口的服務(wù);
- ES能夠支持很大數(shù)據(jù)量的信息存儲(chǔ),支持很高并發(fā)的搜索請(qǐng)求;
- ES支持集群,向使用者屏蔽高可用/可擴(kuò)展/負(fù)載均衡等復(fù)雜特性;
目前,快狗打車使用ES作為核心的搜索服務(wù),實(shí)現(xiàn)業(yè)務(wù)上的各類搜索需求,其中:
- 數(shù)據(jù)量最大的“接口耗時(shí)數(shù)據(jù)收集”需求,數(shù)據(jù)量大概在10億左右;
- 并發(fā)量最大的“經(jīng)緯度,地理位置搜索”需求,線上平均并發(fā)量大概在2000左右,壓測(cè)數(shù)據(jù)并發(fā)量在8000左右;
所以,ES完全能滿足10億數(shù)據(jù)量,5k吞吐量的常見搜索業(yè)務(wù)需求。
高級(jí)階段-自研搜索引擎
當(dāng)數(shù)據(jù)量進(jìn)一步增加,達(dá)到10億、100億數(shù)據(jù)量;并發(fā)量也進(jìn)一步增加,達(dá)到每秒10萬吞吐量;業(yè)務(wù)個(gè)性也逐步增加的時(shí)候,就需要自研搜索引擎了,定制化實(shí)現(xiàn)搜索內(nèi)核了。
到了定制化自研搜索引擎的階段,超大數(shù)據(jù)量、超高并發(fā)量為設(shè)計(jì)重點(diǎn),為了達(dá)到“無限容量、無限并發(fā)”的需求,架構(gòu)設(shè)計(jì)需要重點(diǎn)考慮“擴(kuò)展性”,力爭(zhēng)做到:增加機(jī)器就能擴(kuò)容(數(shù)據(jù)量+并發(fā)量)。
同城的自研搜索引擎E-search初步架構(gòu)圖如下:

(1) 上層proxy(粉色)是接入集群,為對(duì)外門戶,接受搜索請(qǐng)求,其無狀態(tài)性能夠保證增加機(jī)器就能擴(kuò)充proxy集群性能;
(2) 中層merger(淺藍(lán)色)是邏輯集群,主要用于實(shí)現(xiàn)搜索合并,以及打分排序,業(yè)務(wù)相關(guān)的rank就在這一層實(shí)現(xiàn),其無狀態(tài)性也能夠保證增加機(jī)器就能擴(kuò)充merger集群性能;
(3) 底層searcher(暗紅色大框)是檢索集群,服務(wù)和索引數(shù)據(jù)部署在同一臺(tái)機(jī)器上,服務(wù)啟動(dòng)時(shí)可以加載索引數(shù)據(jù)到內(nèi)存,請(qǐng)求訪問時(shí)從內(nèi)存中l(wèi)oad數(shù)據(jù),訪問速度很快:
- 為了滿足數(shù)據(jù)容量的擴(kuò)展性,索引數(shù)據(jù)進(jìn)行了水平切分,增加切分份數(shù),就能夠無限擴(kuò)展性能,如上圖searcher分為了4組
- 為了滿足一份數(shù)據(jù)的性能擴(kuò)展性,同一份數(shù)據(jù)進(jìn)行了冗余,理論上做到增加機(jī)器就無限擴(kuò)展性能,如上圖每組searcher又冗余了2份
如此設(shè)計(jì),真正做到增加機(jī)器就能承載更多的數(shù)據(jù)量,響應(yīng)更高的并發(fā)量。
簡單小結(jié)一下:
為了滿足搜索業(yè)務(wù)的需求,隨著數(shù)據(jù)量和并發(fā)量的增長,搜索架構(gòu)一般會(huì)經(jīng)歷這么幾個(gè)階段:
- 原始階段-LIKE;
- 初級(jí)階段-全文索引;
- 中級(jí)階段-開源外置索引;
- 高級(jí)階段-自研搜索引擎;
你們公司,經(jīng)歷到哪個(gè)階段了?
知其然,知其所以然。
思路比結(jié)論更重要。






























