Canal v1.1.4版本避坑指南
阿新 • • 發佈:2020-08-07
## 前提
在忍耐了很久之後,忍不住爆發了,在掘金髮了條沸點(下班時發的):
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-1.png)
這是一個**令人悲傷的故事**,這條情感爆發的沸點好像被遮蔽了,另外小水渠(`Canal`意為水道、管道)上線一段時間,不出坑的時候風平浪靜,一旦出坑令人想屎。重點吐槽幾點:
- 目前最新的`RELEASE`版本為`v1.1.4`,釋出於`2019-9-2`,快一年沒更新了。
- `Issue`裡面堆積了十分多未處理或者沒有迴應的問題,有不少問題的年紀比較大。
- `master`分支經常提交異常的程式碼,構建不友好,因為`v1.1.4`比較多問題,也曾經想過用`master`程式碼手動構建,匯入專案之後決定放棄,誰試試誰知道,可以嘗試對比匯入和構建`MyBatis`的原始碼。
這些都只是表象,下面聊聊踩過的坑。
## 解析執行緒阻塞問題
這個基本是每個使用`Canal`的開發者的必踩之坑。`$CANAL_HOME/conf/canal.properties`配置檔案中存在一行註釋掉的配置:`canal.instance.parser.parallelThreadSize = 16`。該配置用於指定解析器例項併發執行緒數,如果註釋了會導致解析執行緒阻塞,得到的結果就是什麼都不會發生。
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-2.png)
註釋解除即可,建議使用預設值`16`。
## 表結構快取異常阻塞問題
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-4.png)
這是`Issue`裡面很大部分提問者提到但是久未解決的問題,也就是表結構元資料的儲存問題(配置項裡面使用了`tsdb`也就是時序資料庫的字眼,下面就稱為`tsdb`功能)。
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-3.png)
預設開啟`tsdb`功能,也就是會通過`h2`資料庫快取解析的表結構,但是實際情況下,如果上游變更了表結構,`h2`資料庫對應的快取是不會更新的,這個時候一般會出現神奇的解析異常,異常的資訊一般如下:
```shell
Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: column size is not match for table:資料庫名稱.表名稱,新表結構的欄位數量 vs 快取表結構的欄位數量;
```
該異常還會導致一個可怕的後果:解析執行緒被阻塞,也就是`binlog`事件不會再接收和解析。這個問題筆者也檢視過很多`Issue`,大家都認為是一個嚴重的`BUG`,目前認為比較可行的解決方案是:禁用`tsdb`功能(真的夠粗暴),也就是`canal.instance.tsdb.enable`設定為`false`。如果不禁用`tsdb`功能,一旦出現了該問題,必須要**先停止**`Canal`服務,接著**刪除**`$CANAL_HOME/conf/目標資料庫例項標識/h2.mv.db`檔案,然後**啟動**`Canal`服務。
因為這個比較坑的問題,筆者在生產禁用了`tsdb`功能,並且添加了`DDL`語句的處理邏輯,直接打到釘釘預警上並且`@`整個群的人。
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-5.png)
每次看到這個預警都心驚膽戰。
## 日誌問題
如果剛好需要定位的`binlog`位點處於比較靠後的檔案,檔案數量比較多,會瘋狂列印尋位的日誌。之前嘗試過重啟一下子列印了幾`GB`日誌,超過`99%`是定位`binlog`檔案和`position`的日誌行。可以考慮通過修改`$CANAL_HOME/conf/logback.xml`(並不建議,不清楚原始碼容易造成其他新的問題)配置或者指定`$CANAL_HOME/conf/目標資料庫例項標識/instance.properties`的下面幾個屬性手動定位解析的起點:
```shell
canal.instance.master.journal.name=binlog的檔名
canal.instance.master.position=binlog的檔案中的位點
canal.instance.master.timestamp=時間戳
canal.instance.master.gtid=gtid的值
```
> 以上的手動定位解析的起點的屬性需要在下次重啟Canal之前更新或者註釋掉,否則會造成重新解析或者找不到檔案的嚴重後果!!!
**反正每次重啟`Canal`服務都驚心動魄,沒有一個開源軟體可以讓人有這種感覺**。因為生產的伺服器磁碟不是很充足,選配的時候只買了100`GB`,而且考慮到這些日誌本質上沒有太大意義,於是只能定期上去刪日誌,前期是手動刪,後來覺得麻煩寫了個`Shell`指令碼定時刪除久遠的日誌檔案。
## 雲RDS MySQL的使用問題
如果剛好使用了阿里雲的`RDS MySQL`,那麼有可能會遭遇更大的坑。主要問題是:
- `RDS MySQL`有磁碟空間優化規則,觸發了規則會把`binlog`檔案上傳到`OSS`,然後刪除本地的`binlog`檔案。
- 從`Canal`的文件來看,會自動拉取`OSS`上的`binlog`檔案進行解析,讓使用者無感知,但是此功能有`BUG`,一直無法正常使用。
- `RDS MySQL`是一個暗箱,出了問題只能通過`MySQL`的相關查詢去定位問題,沒有辦法進去伺服器檢視真實的現場。
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-6.png)
命中了這個問題,一般出現的異常是:
```shell
.................. sqlstate = HY000 errmsg = Could not find first log file name in binary log index file
```
可以基本確認這個功能是存在缺陷的,例如這裡有個[Issue-2596](https://github.com/alibaba/canal/issues/2596):
![](https://throwable-blog-1256189093.cos.ap-guangzhou.myqcloud.com/202008/f-u-c-k-c-a-n-a-l-7.png)
目前筆者的做法如下:
- 完全棄用`Canal`拉取`OSS`上的`binlog`檔案的功能。
- `RDS MySQL`儘可能擴容一下磁碟,調整策略讓儘可能多的`binlog`檔案儘可能久地保留在本地,讓它們被完全解析後再手動上傳或者命中了過期規則後自動上傳,這期間有很多東西需要額外收取費用,具體需要自行權衡。
> 讀取和解析OSS上的binlog檔案在目前(2020-08-05)的master分支上依然有BUG,想手動構建master分支的夥伴建議放棄幻想。
這個問題的嚴重後果是:**有比較大的可能性導致某段`binlog`檔案解析完全缺失**,除非可以把`binlog`檔案重新塞回去`RDS MySQL`裡面,否則需要做上下游手動同步功能。
## to be continue
除此之外,要注意`Canal`最好做主備部署,提交位點和叢集管理建議使用`Zookeeper`,而服務模式(`canal.serverMode`,目前支援`tcp`、`kafka`和`rocketmq`)建議選用`Kafka`(`master`分支上有`RabbitMQ`的聯結器支援,如果想嚐鮮可以手動構建一下),並且每個節點的資源要求比較高,筆者生產上每個節點使用了`2C8G`低主頻的`ECS`,感覺有點壓不住,特別時重啟例項的時候如果需要重新定位`binlog`位點,`CPU`在一段時間內使用率會飆高。
筆者發現了阿里雲的`DTS`就是使用了`Canal`作為基礎中介軟體進行資料同步的,說明它有被投產到實際應用場景中,真不希望它最終演變成廢棄的`KPI`任務專案。不知道往後還會遇到多少問題,如果碰到了也會持續更新本避坑指南。
(本文完 c-2-d e-a-20200805)
![](https://public-1256189093.cos.ap-guangzhou.myqcloud.com/static/wechat-account-logo.png)
這是公眾號《Throwable》釋出的原創文章,收錄於專輯《架構與實