一、背景
昆仑分布式数据库使用MySQL做存储节点,称为kunlun-storage。Kunlun-storage目前最新版本基于percona-mysql-8.0.26开发,在此社区版本基础上,我们补充了MySQL的XA事务和binlog复制方面的容错和数据一致性漏洞,增加了kunlun数据库集群需要的若干功能,并且增强了其性能。
我们也一直在合并上游版本,持续汇集MySQL社区的最新成果到kunlun-storage中。
在Kunlun-storage Fullsync机制开发完成之前,我们一直在使用MySQL Group Replication(MGR)实现存储集群高可用。
为了实现更好的数据写入性能包括更高的吞吐量和更短的延时,以及降低对存储系统和网络带宽的消耗,并且在高可用方面实现更加灵活的策略,我们在kunlun-storage中设计并开发了Fullsync高可用机制。
二、Kunlun-storage Fullsync功能简介
Kunlun-storage Fullsync概况和原理
昆仑数据库的Fullsync机制是一种存储集群的高可用机制,它用于确保一个存储集群在发生节点故障、网络分区等问题时,该集群中存在可用的备机含有所有向用户确认提交成功的事务的binlog,以便可以按需选举出新的主节点,确保集群持续可以写入,实现高可用。
昆仑数据库的Fullsync机制基于MySQL久经考验的Row Based Replication(RBR)binlog复制机制,实现了主备复制的强同步,也就是确保主节点上提交的每一笔事务---包括显式普通事务(即begin 。。。Commit),autocommit的update/delete/insert语句,以及XA事务---在完成内部的事务提交流程(即engine log和binlog flush&sync和engine commit 这三个阶段)之后,持续等待直到收到了足够数量的备机的确认(ACK)之后,才向客户端(在昆仑数据库中就是计算节点)确认这个事务成功提交。
一个ACK是一个binlog文件标识和偏移值的组合,它代表的是这个位置之前的binlog都已经被这个备机收到并且持久存储(刷盘)。
这样,所有那些在主节点的binlog文件中其binlog存储在此位置之前的事务都得到了确认,它们的提交操作就都可以返回成功状态给客户端了。
一个备机发送该ACK是向其主节点确认收到并持久化(刷盘)了一组事务的binlog到其relay log文件中。只有主节点收到这个确认,才向客户端返回事务提交成功的确认状态,客户端收到此结果后才能发送下一条SQL语句给昆仑数据库。
只有向客户端返回事务成功提交(或prepare),昆仑分布式数据库才有义务保障这样的事务的改动不丢失(即ACID的D,Durability)。
Kunlun-storage Fullsync的前提条件
Kunlun-storageFullsync机制需要一组特定的参数组合才能正常工作。
Kunlun-storage自带的参数配置模版文件中含有经过我们开发团队调优之后的参数设置,其中包含了fullsync功能需要的参数设置。
Kunlun数据库集群的所有存储节点实例都是使用其自带的参数模版创建的。
具体来说包括以下参数:
-
gtid_mode=on,enforce_gtid_consistency=1
log_slave_updates=ON
-
binlog_format=row, i.e. 使用Row based replication
-
所有主备节点都使用binlog
-
会话都使用binlog,即sql_log_bin=true。如果把一个会话的sql_log_bin设置为false则此会话中fullsync机制不工作但是其他会话中fullsync仍然工作。
-
enable_fullsync = ON 打开fullsync全局开关
-
thread_handling=2或者0, 即kunlun-storage的fullsync机制适用于线程池(thread_handling=2)以及每个线程处理一个事务(thread_handling=0)的情况。
Kunlun-storage Fullsync的功能设计与实现
1. 主节点
kunlun-storage的fullsync机制是一种after-commit的同步模式。
在处理用户会话thd的工作线程thr 完成事务T提交或者prepare(XA prepare)并且还未向客户端确认成功(即发送OK包)之前,主节点检查事务T的binlog是否已经收到了足够数量的备机的ACK(备机的ACK 确认收到若干个事务的binlog)---此条件称为释放条件。
如果释放条件满足那么thr直接返回成功状态给客户端并且完成本次请求处理,否则工作线程thr就把会话对象thd放到fullsync ack等待队列,然后去处理其他连接