怎么处理主备延迟导致的读写分离
分摊主库压力。client负载均衡,
中间代理层 proxy,客户端连接 proxy(根据请求类型和上下文决定分发路由)
1. 客户端直连,少了一层 转发,查询性能好,排查问题方便。连接信息在客户端连接层,主备切换、库迁移客户端感知,调整连接信息。信息冗余,架构很丑。伴随管理后端组件如 Zookeeper。
2. proxy 架构(更多),客户端不需关注后端连接维护、后端信息维护等工作,proxy 需高可用架构,相对复杂。
过期读”:主从延迟,更新后马上查询,从库查询,可能读到更新前状态。
处理过期读方案
强制走主库方案;
sleep 方案;
判断主备无延迟方案;
配合 semi-sync 方案;
等主库位点方案;
等 GTID 方案。
一、强制走主库方案
两类查询:
1. 最新结果发主库。看商品是否发布成功。
2. 可读旧数据发从库。晚几秒看到最新发布商品。
金融类的业务。读写压力都在主库,放弃扩展性
二、Sleep 方案
主库更新后,读从库之先 sleep,类似执行select sleep(1)(主备延迟在 1 秒之内, sleep 大概率拿最新)
用户体验不友好,但解决问题:商品发布后,用 Ajax(Asynchronous JavaScript + XML,异步 JavaScript 和 XML)显示客户端内容“新的商品”,不真查询。再刷新查看商品时,过了一段时间,达到sleep 目的
不精确,包含了两层意思:
1. 本来 0.5 秒就可拿结果(从库),等 1 秒;
2. 延迟超过 1 秒,还会过期读。
三、判断主备无延迟方案
第 25 篇文章, show slave status 里seconds_behind_master衡量主备延迟时间。
(1)从库查询前,seconds_behind_master 是否=0。不等于 ,等0 执行。
(2)对比位点:
Master_Log_File 和 Read_Master_Log_Pos,主库最新位点;
Relay_Master_Log_File 和 Exec_Master_Log_Pos,备库最新位点。
两组值完全相同,同步完成
(3)对比 GTID 集合
Auto_Position=1 ,主备关系GTID 协议
Retrieved_Gtid_Set,备库收到GTID 集合
Executed_Gtid_Set,备库执行完 GTID 集合
这两个集合相同,表示备库都同步完成
2、3 更准确,没有达到“精确”
事务 binlog 主备库之间状态:
1. 主库执行完,写入 binlog,反客户端;
2. binlog 主库发备库;
3. 备库执行 binlog 完成。
无延迟逻辑:“备库收到的日志都执行完成了”。但一部分日志,客户端提交备库,没收到日志状态
主库上执行完成了三个事务 trx1、trx2 和 trx3,其中:
1. trx1 和2 传到从库,执行完;
2. trx3 主库执行完,回复客户端,没有从库中。
B 查不到 trx3 出现了过期读
四、配合semi-sync
引入半同步复制semi-sync replication。
1. 提交时,主库binlog 发从
2. 从发回给主库ack,表收到
3. 主库收到ack 后,给客户端返回“完成”
在第 25 篇文章如果主库掉电,binlog 没发从库,会不会数据丢失?
异步复制可能丢失,semi-sync + 位点判断,解决(一主一备),避免过期读。
一主多从,从库查询两种情况:
1. 查询响应ack从库,读最新
2. 其他从库上,过期读
潜在问题,高峰期,主库位点或 GTID 集合更新快,两位一直不等,从库无法响应。查询不需要等到“主备完全同步”
等待位点 bad case。 1 到状态 4,一直延迟
客户端发完 trx1 更新后 select ,确保 trx1完成就可(3 查得预期)
semi-sync 配合判断主备无延迟方案,两个问题(等主库位点解决):
一主多从,过期读;过度等待
五、等主库位点方案
从库执行:select master_pos_wait(file, pos[, timeout]);//主库上文件名和位置;timeout 最多等 N 秒(可选)
返回正整数 M,从开始到应用完 file 和 pos (表示的 binlog 位置)执行多少事务
返回其他结果:
1. 异常,返回 NULL;
2. 等待超过 N 秒,返回 -1;
3. 执行过这个位置,返回 0。
先执行 trx1,再查询保证数据正确
1. trx1 更新完,show master status 得主库 File 和 Position;
2. 选从库,执行 select master_pos_wait(File, Position, 1);
4. 返回正整数,从库查询;否则主库执行
1 秒内返回正整数,查询正确。等待超时,放弃主库去查
步骤 5 主库查询语句,退化机制。
从库都延迟超过 1 秒,压力都跑主库上
不允许过期读,要么超时放弃,要么转主库查。做好限流
六、GTID 方案
开启了 GTID 模式,对应等待 GTID方案。
select wait_for_executed_gtid_set(gtid_set, 1); 等待直到执行事务包含gtid_set,返回 0;超时返回 1。
等位点中,执行后主库show master status。5.7.6 版本开始,更新后,GTID 返回客户端,GTID 减一次查询。
GTID 流程
1. trx1 更新后,返回包获取 GTID,记为 gtid1;
2. 选从库,执行 select wait_for_executed_gtid_set(gtid1, 1)
3. 返回 0,从库查询;否则主库查询
session_track_gtids = OWN_GTID,通过 API 接口mysql_session_track_get_first 返回包解析出 GTID 值
mysql_reset_connection 没有接口SQL 用法,提供给程序API(https://dev.mysql.com/doc/refman/5.7/en/c-api-functions.html)。
提交后,返回GITD 在客户端显示修改,
客户端代码中调用mysql_session_track_get_first 函数。
小结
一主多从做读写分离,读的方案。
不接受过期读,用等待位点和 GTID ,实际混合用
不需等就可水平扩展,写性能换来。
问题
GTID 主库大表DDL,可能会出现什么情况呢?如何避免?
主库10 分钟,提交后传备库10 分钟。主库 DDL 后再提交 GTID,备库10 分钟才查到。超时走主库。
低峰期都切到主库,等备库延迟追上,读切备
gh-ost也可解决
评论1
主从延迟,流量全到主库
1.从库SET sql_log_bin = OFF,然后DDL,从库及备主全做完,主从切换,同样的方式DDL。
2.从库DDL;从库GTID在主库上生成(利用生成空事务GTID方式)。切换,主库同样。
MM,写职责主库slave先停
评论2
proxy分布式数据库难点。MariaDB MaxScale
一主多从可以多到什么地步,一主十三从?
13从有点多,主库生成binlog快网卡被打爆。这么多得做级联。