業務背景說明:
本公司有一個業務場景是需要從A資料庫異構同步至B資料庫,在B資料庫進行一些邏輯統計查詢操作,大致如下圖:

當時設計的技術架構如下:
第一步:通過canal監聽A庫的binlog日志,將binlog日志資訊發送至kafka訊息佇列
第二步:部署消費者canal-kafka工程(純java撰寫),消費kafka訊息,異構原始資料,落B庫,canal-kafka可以多節點分片部署

該方案咋一看可能存在一些問題,如同步性能如何,sql執行順序問題如何保證,下面一一解答
biglog本身是有序的,寫入kafka時可以保證有序,如果canal-kafka單節點部署,順序消費那么,異構執行sql必定是有序的,但是這樣會遇到性能瓶頸,同步資料量一大,必定造成大量訊息阻塞,為了解決這一問題,canal-kafka必須得支持多節點分片部署,而kafka正好支持訊息的磁區功能,當一個訊息投遞至kafka時,可以選擇這條訊息至哪個磁區,一個磁區對應一個消費者,這樣大幅提高了消費能力,消費能力提高了但是引進一個新問題,sql執行順序問題,假設同一條資料的多個update陳述句,在不同的消費者執行,那么他們前后執行順序問題如何保障?于是乎,必須確保同一條資料,從insert以及后面的各條update陳述句必須得是同一個消費者消費訊息,有序執行,而canal擁有這一功能,參考文章鏈接:Canal Kafka RocketMQ QuickStart · alibaba/canal Wiki · GitHub ,可以查看 “mq順序性問題” 這一小節,簡單來說,每條資料在經過canal投遞至kafka時 ,對其主鍵進行hash,選擇其指定的kafka磁區,這樣之后這條資料修改均會投遞至當初insert的的那個磁區,這樣消費時又是有序消費,從而保證了異構資料的有序性(A庫單表資料對應B庫單表資料的情況),如下圖:

當然,因為是異構,所以存在以下三種比較麻煩的情況:①A庫的多表資料 對應 B庫的單表資料,②A庫的單表資料對應B的多表資料,③A庫多表資料對應B庫多表資料;第二種情況,在處理時比較簡單,只要新增,修改時改造多條B庫執行sql的陳述句,對于第一種跟第三種情況,就存在多個主鍵key都能造成某條B庫資料的更新,為了保證資料的一致性,就需要通過業務代碼來確保,舉個例子:A的a1表,a2表,a3表均會更新B庫的b1表資料,于是乎,當a1資料到達B時,需要回查a2,a3的資料,確定最后b1的執行sql,這樣才確保了最終一致性,第三種情況也類似,如下圖:

還有一種解決方案是設計合理的磁區key,因為前面是將各張表的主鍵進行hash操作后磁區,可能會導致順序錯亂,如果找到a1,a2,a3表的關聯關系,如果他們的關聯欄位是同一個,進行hash訊息磁區后能保證有序,可以達到轉化為單表對單表同步的效果,這樣提高的性能不是一點點,當然在同步策略中需要考慮在a1,a2,a3資料到達時b1表的資料是否已經生成,這些都需要在業務邏輯中保障,當然出現萬一a1,a2表的關聯欄位是 c1;a2,a3表的關聯欄位是c2,關聯欄位不是同一個,處理起來就不適用于此方法了,因為無論是對c1 hash磁區還是c2 hash磁區,都會對B庫的b1表更新,又會產生順序問題,
當然在資料一致性要求較低的情況下,可以在a1,a2,a3三張表中以更新頻率最高的的表作為更新標記,在業務中只當某張表(a1,a2,a3中的一張)更新時才更新b1表資料,這樣可以提高同步性能,
至此,將技術方案進行了簡單說明,若有遺漏未考慮到bug情況望指教,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/344161.html
標籤:其他
上一篇:ELK日志分析系統
