如何正确新增字段

最近运维执行 DB 变更,给业务表 T_pay 新增字段 F_id,引起 DAO 模块读数据接口 GetBillInfo 出现大量找不到记录的失败。为什么只是新增 MySQL 字段,会引起模块接口失败?


1.原因分析

业务 MySQL 采用了读写分离的方式,写 Master 主机,读 Slave0 从机。这样的好处是读写负载被分布到不同机器,同时可以防止大量读引起 Master 故障。

看 DB 监控发现新增字段时,出现了大量的主备延时。什么是主备延时?

下图是主备同步的流程,Master 生成 binlog 后,dump_tread 线程将 binlog 同步传输给 Slave。Slave 上的 io_thread 线程接收数据并存储为中转日志 relog,最后由 sql_thread 线程将数据重放到引擎存储中。主备延时是从主机执行事务成功到备机 sql_thread 线程重放数据到最新事务 id 的时间差。

1.1.为什么 DB 新增字段会影响主备延时?

运维操作 DDL 变更时选择的策略是从主机变更,那么会先在 Master 进行 DDL 操作,再同步 binlog 到 Slave。

T_pay 表有 300M 大小,主库进行 DDL 时,会产生 mixed 的 binlog。从库 sql_thread 为单线程重放 binlog 日志,这个过程需要重建数据,占用线程时间长,造成 relaylog 堆积,产生延时。

1.2.主备延时会影响 master 上的写操作吗?

出现主备延迟只影响了 Slave0 上的 select,并没影响 Master 上的 insert、update。原因是主备延时不会影响半同步。

业务写 Master 时,会先写 binlog,只要有一个 Slave 返回 ACK,半同步就完成了。Slave 只要更新到 binlog 就返回 ACK 给 Master 了,然后 Slave上 的 sql_thread 进程可以慢慢重放数据。

1.3.出现读数据接口失败原因

用户先付款成功,会在 Master 上 InsertBillInfo 生成一条订单记录;然后在 Slave0 上 GetBillInfo 去读这条订单记录,但由于主备延时,这条订单记录还没有在从机上生成,所以出现找不到记录的失败。


2.如何变更

方案一:DAO 切换为写 Master 读 Master

优势:切换之后实时性更好,不会出现主备延时

劣势:DAO 在读写分离时,可以容忍读故障。例如,索引问题出现慢查询引发 DB 故障,此时只是影响读,业务可以正常运行。读写分离可以对这些场景进行兜底。如果切换为写 Master 读 Master,一旦出现故障,业务会不可用。可以考虑在读 Master 后变更 DB,观察业务情况后再判断是否需要切回 Slave。

风险:需要修改配置切换为读写 Master

方案二:低峰期从主机缓慢变更

优势:DB 变更已开始执行,这种方案不需要代码层面的修改

劣势:每个表之间的变更间隔必须加大,尽量让中间 sleep 的时间追齐前面表变更导致的延迟。不加间隔时大约需要执行 4 小时

风险:出现主备延时,导致销帐延迟

方案三:运维写脚本分开主备变更

优势:可以尽量减少备机延时

劣势:需要运维手写脚本来分开主备变更,属于非标准操作,风险较高

风险:运维手写脚本分开主备变更

方案四:从机读不到时再读 Master 兜底

优势:可以解决一部分主备延时问题

劣势:放大请求,有些订单本来就读不到

方案五:从机获取两个 Slave 的延时,选最优 Slave 读

优势:可以减轻主备延时

劣势:可能还是存在延时问题

方案六:低峰期挂公告停服再变更

优势:不需要开发和运维变更

劣势:MySQL 执行无法并行,执行时间 4 小时+,停服时间过长

风险:影响用户体验

结论

对比以上方案后,选择方案一进行变更。变更当晚又出现主备延时。但因为 GetBillInfo 读订单表已经切换到读 Master,所以不再出现读不到订单的问题。


3、主备延迟来源

在备库上执行 show slave status 命令查看 Seconds_Behind_Master 字段可以知道当前备库的延迟时间。

主备延时包含两部分时间损耗:主机传输 binlog 日志到备库;备机接收完 binlog 和执行完这个事务。在网络正常情况下,第一部分耗时很短,主备延迟主要由第二部分引起,也就是备库 sql_thread 线程消费 relay log 的速度比主库生产要慢。

除了上面业务中出现的场景会导致这种问题,还有哪些场景也会导致主备延迟?

1、备机机器性能比主机差,或者参数配置不同

2、备机负载压力大,比如在上面执行了数据统计分析语句、运维日常导出脚本

3、大事务,在主机上执行 1 min,在备机上可能重放数据也需要 1 min


参考

MySQL DDL 为什么成本高

MySQL 45 讲:MySQL 是这么保证高可用的?



Previous     Next
/
Published under (CC) BY-NC-SA in categories tagged with