项目场景:
用户通过订单领域服务下单,订单领域服务把订单数据记录到MySQL关系数据库中。canal数据处理中间服务通过读取MySQL的binlog,通过tcp连接发送到数据处理服务,数据处理服务聚合数据并记录到宽表的mongodb中。
接到阿里云通知要对rds进行升级,运维选择在业务低峰期24点进行rds升级。
问题描述
第二天早上8点半左右收到客户反应,用户正常下单后,在后台无法查看到相关订单。
原因分析:
- 通过客户反馈,用户可以正常下单,但是后台无法查看到订单,加上昨晚进行阿里云rds升级。初步判断MySQL同步到mongodb链路出现问题。
- 验证判断,通过订单号在MySQL可以查询到数据,但是在mongobd中无法查询到数据。
- 进一步验证判断,在数据处理服务中没有发现订单同步日志,进入canal服务器,直观发现MySQL binlog position 失败的错误日志(java.io.IOException: Received error packet: errno = 1236, sqlstate = HY000 errmsg = Could not find first log file name in binary log index file)。
- 由此定位到问题为:阿里云RDS实例迁移导致canal服务标记的MySQL binlog position错误,从而造成canal无法同步数据到MongoDB;
解决方案:
快速回复数据同步方案
- 查找mysql的binlog日志位置:在MySQL执行命令SHOW MASTER STATUS;
- 设置canal获取binlog的首地址:
进入canal服务器,执行 cat cd canal/conf/example/meta.dat{"clientDatas":[{"clientIdentity":{"clientId":1001,"destination":"example","filter":""},"cursor":{"identity":{"slaveId":-1,"sourceAddress":{"address":"192.168.21.60","port":3306}}, "postion":{"gtid":"","included":false,"journalName":"mysql-bin.000005","position":47543372,"serverId":1739,"timestamp":1644288846000}}}],"destination":"example"}[root@centos example]#
文件信息如下:
clientId 可以参考:canal/logs/example/meta.log
address:主库ip
port:主库端口
journalName : binlog名称。
position:开始同步的位置
timestamp : 延迟的时间(写0会从journalName开头开始同步)。
destination : 实例名(默认应该和当前目录名一致)
修改meta.dat文件中的“journalName”和“position”信息。 - 重启canal服务(但是之前部分数据可能没有同步)
补偿方案
- 由于canal恢复同步的position位置binlog日志没有包含丢失的全部订单数据。所以需要编写代码把阿里云RDS升级到canal恢复同步数据这段时间的订单数据重新同步到mongodb。
- 编写按照订单创建时间同步数据到mongodb(注意兼容可能有些数据已经同步到mongodb)
总结
- canal服务增加监控,如果出现错误日志第一时间今天告警。
- RDS升级时的binlog保持24小时,方便出现类似问题可以进行数据恢复。
- 预留数据同步批零补偿接口,方便进行数据补偿。