ElasticSearch + Canal 開發千萬級的實時搜索系統【轉】

公司是作社交相關產品的,社交類產品對搜索功能需求要求就比較高,須要根據用戶城市、用戶ID暱稱等進行搜索。java

項目原先的搜索接口採用SQL查詢的方式實現,數據庫表採用了按城市分表的方式。但隨着業務的發展,搜索接口調用頻次愈來愈高,搜索接口壓力愈來愈大,搜索數據庫常常崩潰,從而致使搜索功能常常不能使用。數據庫

從上面的系統架構圖能夠看出,當用戶修改資料時,接口會修改用戶庫信息,接着觸發器會將改變的用戶信息寫入臨時表。定時腳本每隔1分鐘掃描一次臨時表,將變動的數據寫入到搜索庫中。當用戶再次請求搜索接口時,就能夠搜索到最新的數據。服務器

從技術層面分析,原搜索系統的設計有如下缺點:markdown

  • 搜索信息不實時。當用戶修改信息時,須要等待1分鐘的時間才能將最新的用戶信息同步到搜索數據庫中。
  • ID、暱稱搜索速度慢。按照地區分表的數據庫設計是爲了減輕數據庫壓力,保證大部分按照地區搜索的請求能正常響應。可是若是用戶按照ID或暱稱搜索,那麼咱們就須要對成千上萬個地區表全都搜索一次,這時間複雜度可想而知。不少時候按照暱稱和ID搜索速度太慢,須要10多秒才能響應。
  • 系統穩定性、拓展性以及處理能力差。這能夠歸結爲技術老舊,沒法知足業務需求。隨着搜索量的提高,對數據庫的壓力將會愈來愈大,而MySQL數據庫自然不適合用來應對海量的請求。如今已經有更加成熟的ElasticSearch能夠用來作搜索方面的業務。
  • 觸發器不便於管理。觸發器這種東西很差維護,而且擴展性不好,一旦修改的請求變多,極可能致使整個數據庫崩潰(用戶庫崩潰是很嚴重的)。

咱們總結一下新搜索系統須要解決的幾個問題:架構

  • 海量請求。幾百萬的請求毫無壓力,上千萬上億也要能夠扛得住。
  • 實時搜索。指的是當一個用戶修改了其數據以後,另外一個用戶能實時地搜索到改用戶。

海量請求。要扛得起海量的搜索請求,可使用ElasticSearch來實現,它是在Lucene的基礎上進行封裝的一個開源項目,它將Lucene複雜的原理以及API封裝起來,對外提供了一個易用的API接口。ElasticSearch如今已經普遍地被許多公司使用,其中包括:愛奇藝、百姓網、58到家等公司。數據庫設計

實時搜索。阿里有一個開源項目Canal,就是用來解決這個問題的,Canal項目利用了MySQL數據庫主從同步的原理,將Canal Server模擬成一臺須要同步的從庫,從而讓主庫將binlog日誌流發送到Canal Server接口。Canal項目對binlog日誌的解析進行了封裝,咱們能夠直接獲得解析後的數據,而不須要理會binlog的日誌格式。並且Canal項目整合了zookeeper,總體實現了高可用,可伸縮性強,是一個不錯的解決方案。post

通過一段時間的技術預研,咱們設計了整個搜索技術架構:spa

從架構圖能夠看出整個系統分爲兩大部分:設計

  • Canal數據變動服務平臺。這部分負責解析MySQL的binlog日誌,並將其解析後的數據封裝成特定的對象放到Kafka中。
  • Kafka數據消費方。這部分負責消費存放在Kafka中的消息,當消費方拿到具體的用戶表變動消息時,將最新的用戶信息存放到ES數據倉庫中。

Canal技術變動基礎平臺

由於考慮到將來可能有其餘項目須要監控數據庫某些表的變化,所以咱們將Canal獲取MySQL數據變動部分作成一個公用的平臺。當有其餘業務須要增長監控的表時,咱們能夠直接修改配置文件,重啓服務器便可完成添加,極大地提升了開發效率。日誌

在這一部分中,主要分爲兩大部分:Canal Server 和 Canal Client。

Canal Server端。Canal Server假裝成MySQL的一個從庫,使主庫發送binlog日誌給 Canal Server,Canal Server 收到binlog消息以後進行解析,解析完成後將消息直接發送給Canal Client。在Canal Server端能夠設置配置文件進行具體scheme(數據庫)和table(數據庫表)的篩選,從而實現動態地增長對數據庫表的監視。

Canal Client端。Canal Client端接收到Canal Server的消息後直接將消息存到Kafka指定Partition中,並將最新的binlogid發送給zookeeper集羣保存。

Kafka消息消費端

Canal技術變動平臺在獲取到對應的數據庫變動消息後會將其放到指定的Kafka分片裏,具體的業務項目須要到指定的Kafka片區裏消費對應的數據變動消息,以後根據具體的業務需求進行處理。

由於Canal變化是根據表爲最小單位進行地,所以我在實現方面定義了一個以表爲處理單位的MsgDealer接口:

public interface MsgDealer { void deal(CanalMsgVo canalMsgVo); }

搜索庫涉及對5個表的監視,所以我實現了5個對應的處理類:

針對不一樣表的數據變化,自動調用不一樣的實現類進行處理。

=================================================
相關文章
相關標籤/搜索