如何設計百萬級商品數據實時同步的秒級搜索系統?

設計要求在用戶輸入搜索內容時,要能從商家名稱和商品名稱兩個維度去搜索,搜索出來的結果,按照準確率排序,並按商家所屬商品的關聯關係,來組合數據結構,同時提供 API 給業務系統調用。


背景很簡單,現實蠻複雜!我們面臨以下幾個難題:

  • 商家數據庫和商品數據庫是多臺不同的服務器,並且數據量達百萬級,如何才能實現跨數據庫的數據同步呢?
  • 商家和商品的數據是有從屬關係的,不然就會把肯德基的香辣雞腿堡掛到麥當勞去,這就尷尬了!
  • 商家商品數據是經常更新的,比如修改價格、庫存、上下架等,那搜索服務可不能搜出一堆過時的數據,如果客戶明明搜出來的商品,點進去後卻已下架了,那麼客戶就要吐槽了!如何實現搜索數據與源數據庫增刪改均實時同步呢?


帶著以上三個問題,我們開始了搜索服務的整體架構設計。


系統架構設計思路


為了設計出合適的系統架構,我們分析了現狀:


首先,商家數據和商品數據分別存儲在 2 個獨立的 MySQL8 數據庫,為滿足商家數據和商品數據的關聯,我們需要將兩個庫中所需要的表實時 ETL 到我們的搜索系統數據庫。


其次,數據從商家、商品數據庫 ETL 到搜索系統數據庫後,需要實時的組合成為商家關聯商品數據結構,並以父子文檔的格式,存儲到 ES 中。


最後,商家、商品數據庫的增刪改操作,需要實時的同步到 ES 中,也就是 ES 中的數據,需要支持實時的增加、刪除和修改。


為此,我們設計了 2 個 Canal 組件,第一個 Canal 實現數據 ETL,把商家、商品數據庫的某些表及字段,抽取到搜索服務數據庫。


再利用第二個 Canal,讀取搜索服務 MySQL 數據庫的 Binlog,實時傳輸到 Kafka 消息隊列,再由 canal adapter 對數據進行關聯、父子文檔映射等,將處理好的數據存儲到 ElasticSearch 中。


具體系統架構設計如下圖所示:

如何設計百萬級商品數據實時同步的秒級搜索系統?

商家商品搜索系統架構設計


項目實戰


環境及軟件說明


<code>操作系統:CentOS 7
canal:canal.adapter-1.1.4,canal.deployer-1.1.4
kafka:kafka_2.12-2.3.0
ElasticSearch:elasticsearch-6.3.2
kibana:kibana-6.3.2/<code>

用 Canal 實現數據 ETL 到 MySQL8


這個步驟是利用 Canal 從 2 個獨立的 MySQL8 數據庫中,抽取需要的表到搜索服務的 MySQL 數據庫。


①安裝 canaldeployer


解壓 canal.deployer-1.1.4.tar.gz,並配置 canal deployer。


進入 canaldeployer/conf 目錄,修改 canal.properties 文件,主要配置 serverMode、MQ 和 destination 三部分。


首先,我們 serverMode 修改為 Kafka 模式,增加系統緩衝能力以及提高系統穩定性:

如何設計百萬級商品數據實時同步的秒級搜索系統?

serverMode


接著,配置 Kafka 的 MQ 信息(Kafka 請自行安裝):

如何設計百萬級商品數據實時同步的秒級搜索系統?

Kafka MQ 信息


最後,配置需要實例化的 instance,這裡配置了 3 個,表示 canal deploy 會啟動這 3 個實例,同步 MySQL 的 Binlog 到 Kafka 的 Topic 內。


如下圖所示:

如何設計百萬級商品數據實時同步的秒級搜索系統?

destinations 實例配置


配置 canal deployer instance:進入 canaldeployer/conf/example 目錄,發現有一個 instance.properties 文件,這是 Canal 給的示例,我們可以參考其配置。


我們拷貝整個 example 目錄,並重命名為上個步驟配置的 destination 之一,如 xxxsearch。


進入 xxxsearch 目錄,編輯 instance.properties 文件,主要配置源數據庫信息、所需數據表及字段,以及指定 Kafka 的 Topic 名。


這樣源數據庫的 Binlog 就會轉換為 Json 數據,並實時的通過 canal deployer 傳輸到 Kafka 該 Topic 中。


如下所示:

如何設計百萬級商品數據實時同步的秒級搜索系統?

canaldeploy instance 源數據庫配置

如何設計百萬級商品數據實時同步的秒級搜索系統?

canaldeploy instance kafka topic配置


進入 canaldeployer/bin 目錄,執行 ./startup.sh,啟動 canal deployer 及所屬實例。至此 canal deployer 搭建完成。


②安裝 canal.adapter


我們需要利用 canal.adapter 將 Kafka Topic 中的 binlog json 數據,經過清洗轉換等操作,存儲到 MySQL8 中。由於 Canal 原生是不支持 MySQL8 的,故我們需要做一些調整。


增加 MySQL8 連接驅動:解壓 canal.adapter-1.1.4.tar.gz,進入 canaladapter/lib 目錄,移除 mysql-connector-java-5.1.40.jar,導入 mysql-connector-java-8.0.18.jar。


配置 canal adapter,使數據輸出到 MySQL8:進入 canaladapter/conf 目錄,編輯 application.yml 文件,主要配置消費 Kafka、源數據庫信息和搜索系統數據庫信息。


如下所示:

如何設計百萬級商品數據實時同步的秒級搜索系統?

ETL 到 MySQL8 配置


接著,進入 canaladapter/conf/rdb 目錄,以官方提供的 mytest_user.yml 為例,配置 Kafka Topic 名、源數據庫名、源數據表名,以及目標數據庫名和目標數據表名,建議一張表對應一個 yml 文件。

如何設計百萬級商品數據實時同步的秒級搜索系統?

ETL 表結構映射配置


啟動 canaladapter:進入 canaladapter/bin 目錄,執行 ./startup.sh,啟動 canal adapter,觀察 logs/adapter/adapter.log 日誌文件,手動在搜索系統數據庫新增一條記錄,看是否會打印如下日誌,即有 2 條記錄,一條 INFO,一條 DEBUG,則表示配置成功。

如何設計百萬級商品數據實時同步的秒級搜索系統?

canaladapter 日誌


至此,數據 ETL 階段搭建完成,數據可從兩個不同的 MySQL8 數據庫,實時同步到搜索服務的 MySQL 數據庫。


實現數據多表關聯、父子文檔映射


①配置第二個 Canal 的 canaladapter


進入 canaladapter/conf 目錄,編輯 application.yml 文件,主要配置消費 Kafka、搜索系統數據庫,和 ES 連接信息。


如下所示:

如何設計百萬級商品數據實時同步的秒級搜索系統?

canaladapter MQ 及 MySQL 配置

如何設計百萬級商品數據實時同步的秒級搜索系統?

canaladapter ES 配置


②配置多表關聯


進入 canaladapter/conf/es 目錄,vim mytest_user.yml,編輯多表關聯配置:

如何設計百萬級商品數據實時同步的秒級搜索系統?

多表關聯配置


注意,sql支持多表關聯自由組合, 但是有一定的限制:

  • 主表不能為子查詢語句。
  • 只能使用 left outer join 即最左表一定要是主表。
  • 關聯從表如果是子查詢不能有多張表。
  • 主 sql 中不能有 where 查詢條件(從表子查詢中可以有 where 條件但是不推薦, 可能會造成數據同步的不一致,比如修改了 where 條件中的字段內容)。
  • 關聯條件只允許主外鍵的'='操作不能出現其他常量判斷比如:on a.role_id=b.id and b.statues=1。
  • 關聯條件必須要有一個字段出現在主查詢語句中比如:on a.role_id=b.id 其中的 a.role_id 或者 b.id 必須出現在主 select 語句中。
  • ElasticSearch 的 mapping 屬性與 sql 的查詢值將一一對應(不支持 select *)。比如:select a.id as _id,a.name,a.email as _email from user,其中 name 將映射到 es mapping 的 name field,_email 將映射到 mapping 的 _email field,這裡以別名(如果有別名)作為最終的映射字段。這裡的 _id 可以填寫到配置文件的 _id: _id 映射。


③配置父子文檔


以官方的 biz_order.yml 為例,vim biz_order.yml,配置父子文檔映射:

如何設計百萬級商品數據實時同步的秒級搜索系統?

配置父子文檔映射


④在 ElasticSearch6 中,建立 index 和父子文檔映射關係


進入 Kibana 頁面,點擊 Dev Tools,執行如下命令,即可建立索引及父子文檔映射:

如何設計百萬級商品數據實時同步的秒級搜索系統?

建立 index 和父子文檔映射


其中,ES6 和 Kibana 的安裝,在此無特別配置,不做贅述。


⑤啟動 canal adapter


進入 canaladapter/bin 目錄,執行 ./startup.sh,啟動 canal adapter,觀察 logs/adapter/adapter.log 日誌文件,手動在搜索系統數據庫新增一條記錄,看是否會打印如下日誌,如打印則表示配置成功。

如何設計百萬級商品數據實時同步的秒級搜索系統?

正確配置 adapter 日誌示例


運行結果


現在,我們可以通過 Kibana 來執行 DSL 語句來查詢看看。


我們事先已在商家系統中增加了一個“肯德基”商店,然後在商品系統中添加了“西紅柿”和“新鮮西紅柿”2 個商品,並將商品關聯到“肯德基”上。


接著我們查詢“肯德基”或者“西紅柿”,得到以下是查詢的結果(去除了 ES 默認字段):

如何設計百萬級商品數據實時同步的秒級搜索系統?

通過 DSL 查詢的結果


由圖可見,我們可以通過商家名查詢商品,也可通過商品名查詢商店和商品,並且 Canal 支持數據的實時增刪改,所以 ES 的數據也會與商家系統和商品系統保持一致,同時數據結構包含商家及對應的商品,滿足業務需求。


總結


至此,基於 Canal、Kafka、MySQL8、ElasticSearch6 技術的商家商品搜索系統基礎框架搭建完成。


我們採用 canal deployer 實時讀取商家、商品系統的 MySQL 數據庫 Binlog,併發送至 Kafka。


接著由 canal adapter 消費 Kafka,並將 binlog json 數據進行多表關聯、父子文檔映射,最後存儲到 ES6 中,供上層搜索服務調用。


搜索服務系統最終成功上線,為公司百萬級商家商品提供實時數據同步,秒級搜索結果展示,達到業務要求,老闆說了,給研發團隊每人加個雞腿!想想還有點小激動,嘿嘿!


分享到:


相關文章: