系列
canal源碼解析(2)—位點(diǎn)的實(shí)現(xiàn)
概述
????這篇文章的目的是為了講清楚canal的HA機(jī)制,至于什么是HA機(jī)制直接套用canal官網(wǎng)原話,因?yàn)槲易哉J(rèn)為沒法描述的更好。而我直接從代碼的角度去分析如何實(shí)現(xiàn)HA的,其實(shí)也就是zookeeper的分布式鎖的使用方法。
? ? 摘錄自官網(wǎng)的一段原話:
????canal的HA分為兩部分,canal server和canal client分別有對應(yīng)的ha實(shí)現(xiàn):
????canal server: 為了減少對mysql dump的請求,不同server上的instance要求同一時間只能有一個處于running,其他的處于standby狀態(tài)。
????canal client: 為了保證有序性,一份instance同一時間只能由一個canal client進(jìn)行g(shù)et/ack/rollback操作,否則客戶端接收無法保證有序。
canal HA 架構(gòu)圖
說明
? ? 圖片來自官網(wǎng)的剪切,講述的很清楚,就不再多說什么了,后面會基于這個圖從代碼角度展開講解。
canal server HA
????canal server的HA是其實(shí)我覺得從我自己的理解應(yīng)該分為兩個角度去講解,一個是在啟動的時候搶占并負(fù)責(zé)啟動提供服務(wù),另外一個是在發(fā)生fail-over后搶占并負(fù)責(zé)啟動提供服務(wù)。
? ? 能把這兩個過程講解清楚我覺得就夠了,就能理解server的HA機(jī)制了,也基本了解了如何通過zookeeper去實(shí)現(xiàn)互斥鎖。
? ? 最后我們需要問自己的一個問題,就是發(fā)生HA切換的時候狀態(tài)數(shù)據(jù)同步在兩個切換的server之間進(jìn)行同步呢,很簡單,因?yàn)槲覀兊臄?shù)據(jù)都是記錄在zookeeper上的。
server 啟動HA
? ? server在啟動過程中,通過以下幾步來實(shí)現(xiàn)搶占服務(wù)啟動,入口類在CanalController。
????1、對臨時節(jié)點(diǎn)(/otter/canal/destinations/xxxx/running)進(jìn)行監(jiān)聽。
????2、通過創(chuàng)建臨時節(jié)點(diǎn)來搶占鎖,成功就提供服務(wù)。
????3、搶占鎖成功后啟動embededCanalServer開始提供服務(wù)。
????4、創(chuàng)建的臨時節(jié)點(diǎn)內(nèi)部將自己的ip+port暴露出去給client使用。
說明
? ? 啟動服務(wù)的入口函數(shù),別看是runningMonitor,其實(shí)是內(nèi)部負(fù)責(zé)啟動canal instance實(shí)例的。
說明
? ? 這里最重要的一個點(diǎn)就是對canal的臨時節(jié)點(diǎn)監(jiān)控用于在fail-over的時候能夠感知到并及時啟動stand-by的canal server提供服務(wù)。
說明
? ? 負(fù)責(zé)創(chuàng)建臨時節(jié)點(diǎn)來確認(rèn)自己是否能夠提供服務(wù),這其實(shí)通過zookeeper的特性來實(shí)現(xiàn)的。
說明
????真正啟動canal instance的過程,負(fù)責(zé)同步mysql的數(shù)據(jù)到canal instance。
server fail-over ha
????server 在fail-over過程能夠及時發(fā)現(xiàn)并完成切換的原因是通過zookeeper的watch機(jī)制來實(shí)現(xiàn),如果watch的節(jié)點(diǎn)消失了那么其他監(jiān)聽的canal server都能感知到并發(fā)起新一輪的搶占并提供服務(wù)。
? ? 需要區(qū)分兩個zookeeper事件,分別是節(jié)點(diǎn)內(nèi)容變更事件、節(jié)點(diǎn)刪除事件,下面有具體說明。
? ? 關(guān)鍵字:zookeeper的watch機(jī)制,通知,重新?lián)屨肌?/p>
說明
? ? 這里區(qū)分了兩種情況,節(jié)點(diǎn)內(nèi)容變更事件、節(jié)點(diǎn)本身消失事件。對于這兩種情況區(qū)分簡單區(qū)分一下進(jìn)行說明。我估計(jì)很多人跟我的疑惑一樣,為啥要區(qū)分這兩個事件呢,其實(shí)我的猜測是如果節(jié)點(diǎn)刪除了說明這個服務(wù)停止了跟mysql的同步也就結(jié)束了,但是如果節(jié)點(diǎn)內(nèi)容變更了,可能因?yàn)槠渌恍┰颍┤缥覀兪謩有薷膠k節(jié)點(diǎn)內(nèi)容之類的,這個時候我們需要處理連接釋放的過程。
? ? 節(jié)點(diǎn)本身消失處理是handleDataDeleted函數(shù)內(nèi)部的操作,可以看出來其實(shí)就做一件事情,重新開始新一輪的搶占,initRunning就是我們剛剛講的搶占邏輯,可以翻看start-ha-3這個圖片。唯一的區(qū)別是節(jié)點(diǎn)消失事件前提供服務(wù)的如果是自身就具有優(yōu)先搶占的權(quán)利,否則就隨機(jī)進(jìn)行個delay操作避免同時大面積并發(fā)搶占。
? ? 我們重點(diǎn)關(guān)注下節(jié)點(diǎn)內(nèi)容變更的事件吧,之所以需要額外關(guān)注這個事件是因?yàn)橹虚g涉及到如果是如果變更前是自身就需要釋放連接資源。
資源釋放過程
說明
? ? 在收到節(jié)點(diǎn)內(nèi)容變更事件后就開始進(jìn)入資源釋放過程
說明
? ? 停止canal的embededCanalserver的服務(wù),結(jié)束從mysql的數(shù)據(jù)同步。
canal client HA
? ? 整體來說,canal client的HA和canal server的HA機(jī)制是一模一樣的,它的實(shí)現(xiàn)邏輯其實(shí)在創(chuàng)建cluster client的時候用的封裝zookeeper的客戶端,然后zookeeper的客戶端去檢測canal server節(jié)點(diǎn)內(nèi)容的變化并重新初始化連接而已。
說明
? ? 這個地方很明顯看出來,我們首先連接的zookeeper,原因應(yīng)該很清楚,因?yàn)槲覀冃枰獜膠ookeeper獲取提供服務(wù)的canal server的地址,在/otter/canal/destinations/destination/running節(jié)點(diǎn)去獲取。
說明
? ? 這部分其實(shí)就是client和zookeeper交互的部分,負(fù)責(zé)實(shí)時感知節(jié)點(diǎn)變化并重新初始化連接,保證client端的HA。