昆仑分布式数据库存储集群 Fullsync 机制

2022-04-07 00:00:00 数据库 客户端 发送 事务 节点

一、背景


昆仑分布式数据库使用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等待队列,然后去处理其他连接中收到的请求。

主节点收到ACK后会对等待队列中的会话做释放条件检查,满足释放条件条件的会话会被释放,也就是返回成功状态给客户端。在等待备机ACK的过程中,用户回话并不占用工作线程。

如果超时(fullsync_timeout)未收到足够的ack来释放一个等待的会话时,kunlun-storage有两种策略,由全局变量disable_fullsync_on_slave_ack_timeout来控制:

  1. 如果disable_fullsync_on_slave_ack_timeout=1,那么fullsync会自动退化为异步。这样后续等待的事务将不再做fullsync等待。当主节点再次收到备机ack后,会自动启用fullsync机制。


  2. 如果disable_fullsync_on_slave_ack_timeout=0,那么fullsync等待超时的会话,会返回错误(错误号9000)给客户端,对于昆仑数据库集群来说,就是计算节点收到了这个错误,会触发主备切换。



2. 备节点

备机收到事件组(event group,即binlog事务,包括普通显式事务,XA事务阶段,XA事务第二阶段,DDL语句,autocommit语句这几种类型。下文简称EG)的终止binlog事件(XID_EVENT,XA_PREPARE_LOG_EVENT或者DDL事务后,它会决定是否需要把收到的若干个EG写到relay log文件并且刷到持久存储系统中(即flush&fsync relay log),然后发送ACK给主节点来确认持久化了这些收到的EG。

这个决定基于小化资源消耗和优化性能来做出---如果备机收到了足够多的EG(配置参数:fullsync_fsync_ack_least_txns)或者足够量的binlog(配置参数:fullsync_fsync_ack_least_event_bytes) ,或者太久没有发送ACK了( fullsync_fsync_ack_wait_max_milli_secs), 他就会flush&fsync relay log然后发送ACK。

一个ACK包含这些信息:备机的server_id,落盘的后一个EG在主节点binlog中的终止位置(文件编号和偏移值)。

主节点收到一个备机的ACK后就可以确信这个备机收到并持久存储了ACK位置之前的所有EG。
 
使用fullsync_relaylog_fsync_ack_level 全局变量来控制一个备机节点的Fullsync机制在flush&fsync relay log和发送ACK的行为,其含义如下:
fullsync_relaylog_fsync_ack_level
备机行为
不flush或者fsync relay log也不发送ACK
1
flush relay  log后发送ACK
2
Flush&fsync  relay log后发送ACK
 
在主节点上打开log_fullsync_replica_acks 可以在mysql运行日志中记录每一个收到的ACK,这个功能仅仅用于调试备机ACK机制,在生产系统中千万不要打开否则会严重影响性能。

备机有两种方法发送ACK给主节点,这两种方法都要求备机使用mysql客户端库连接主节点,这样每个备节点有两个连接连到主节点,一个是备机的IO线程的连接,另一个是备机发送ACK的连接。

在此连接中备机发送kunlun-storage特有的COM_BINLOG_ACK命令或者发送kunlun-storage可以理解的SQL语句,前者性能更好,但是后者可以让各种第三方binlog存储组件向主节点发送ACK。

  1. COM_BINLOG_ACK使用kunlun-storage的客户端库文件及其mysql.h 头文件编译程序,然后调用 mysql_send_binlog_ack() 函数发送ACK。kunlun-storage fullsync功能使用此方法发送ACK给其主节点。

  2. SLAVE server_id CONSISTENT TO file_index offsetSQL 语句这种方法可以使用任何社区版mysql客户端库,kunlun-storage的主节点可以正确处理该语句,把它当作确认ACK。此方法特别适合各种binlog存储组件。


3. Kunlun-storage Fullsync的状态变量

这些状态变量可以帮助DBA观察fullsync的运行情况和性能,并且作为辅助调节fullsync配置参数的依据。其意义在表格中,都是简单的英语,相信大家都能看懂,因此不再翻译了。

status variable name
meaning
fullsync_received_replica_acks
NO. of received replica acks
fullsync_old_acks_received 
NO. of received ACKs that are  obsolete,i.e. an obsolete ACK ACKs a position already ACK'ed by previously  received ACKs.
fullsync_txns_acked
NO.of txns the replica ACK'ed
fullsync_txns_fully_acked_before_wait
NO. of txns pre-ACK'ed before it  starts to wait --- when the txn tries to wait for ack, its receives all  needed ACKs from slaves
fullsync_txns_acked_before_wait
NO. of txns partly ACK'ed before  it starts to wait, when the txn tries to wait for ack, its receives part of  all needed ACKs from slaves
fullsync_txns_long_wait_warnings_for_acks
NO. of txns long wait warnings for  ACKs. although the wait doesn't timeout, it's still long enough to trigger a  fullsync warning.
fullsync_txns_timed_out_waiting_for_acks
NO. of txns timed out waiting for  ACKs 
fullsync_txns_received_by_replica 
NO. of txns received by the  replica
fullsync_relay_log_syncs
NO. of relay log syncs.
fullsync_acks_sent_to_master
NO. of ACKs sent to master
fullsync_num_txns_in_acked_group
set by a replica, NO. of txns  flushed and fsync'ed corresponding to latest ACK
fullsync_replica_skipped_old_trx_acks
NO. of times the replica skipped sending  ACKs because received txns are too old
fullsync_replica_ack_upto_file and  fullsync_replica_ack_upto_offset;
fullsync replicas have ACKed upto  this position(file and offset within master's binlog file).
fullsync_replica_fully_acked_upto_file;  and fullsync_replica_fully_acked_upto_offset;
fullsync replicas have fully ACKed  upto this position(file and offset within master's binlog file).
 

4. Fullsync配置参数

Kunlun-storageFullsync支持丰富的配置参数让用户在性能、资源消耗和一致性方面取得适当的平衡。这些变量都是MySQL的全局变量,其意义和用法说明见下面的表格,都是简单的英语,相信大家都能看懂,因此不再翻译了。

Fullsync  Variables 
meanings
fullsync_consistency_level
At end of transaction commit, whether and how to wait  for fullsync replica ACKs before replying the client that a transaction has  committed. 0: no wait; 99: wait for simple majority replicas; 100: wait for  all replicas; [1, 98]: wait for this number of ACKs.
fullsync_relaylog_fsync_ack_level
When fullsync is enabled, how should the replica fsync  relay log and/or reply an ACK to primary after it write its received event  group(s) to relay log file.\t" "0: don't fsync or send ACK; 1:  don't fsync but send ACK; 2: fsync and send ACK
fullsync_fsync_ack_least_event_bytes
Accumulate at least this many relay log bytes before  fsync'ing the relay log and sending an ACK.
fullsync_fsync_ack_least_txns
Accumulate at least this many event groups before  fsync'ing the relay log and sending an ACK.
fullsync_fsync_ack_wait_max_milli_secs
Replica nodes wait for more event groups to arrive at  most this many milli-seconds before fsync'ing the relay log and sending an  ACK.
skip_fullsync_replica_acks_older_than
If a replica is this many milli-seconds later than the  primary node, skip fsync'ing the relay log or sending ACKs.
fullsync_warning_timeout
If a replica ACK arrives this many milli-seconds since  the transaction started to wait for it, write a warning in error log.
fullsync_timeout
If a replica ACK doesn't arrive after this many  milli-seconds since the transaction started to wait for it, return error to  client and write an error in error log.
log_fullsync_replica_acks
Whether log replica ACKs to mysqld error log. Note that  when fullsync is enabled there can be a huge amount of such logs which are  seldom used.
enable_fullsync
Whether enable fullsync mechanism.
disable_fullsync_on_slave_ack_timeout
Whether disable fullsync when replicas do not ACK in  time and timeout happened, if this is false, then the primary node can't be  written when it has no running replicas.
 


Kunlun-storage Fullsync的优势


与MySQL的半同步(semisync)插件相比,kunlun-storage 的fullsync机制有如下优势。

等待备机确认期间,客户端会话及其事务不占用工作线程。这样就可以避免大量工作线程阻塞等待备机的ACK,导致线程池为了处理来自其他客户端会话的持续大量到来的请求不得不启动更多的工作线程,消耗过多系统资源。

备机会聚集若干个事务的binlog后(可配置),才对relay log做fsync,确保binlog落盘。这样不仅可以避免备机断电或者其OS crash或者重启导致备机丢失了近的relay log的严重问题,还不会对存储设备造成巨大的写入负载。达到了性能,延时和存储资源消耗之间的完美平衡。

Fullsync有灵活的配置能力,让用户在高可用性、数据强一致性和性能之间做出灵活的控制和取舍。

Fullsync提供丰富的运行状态信息,方便DBA监控fullsync的运行时状态,为有效的fullsync相关配置提供完整的信息

DBA可以配置主节点去等待若干个(可配置)备机返回ACK,从而达到更高的容错级别。比如对于某些高价值业务,DBA可以配置一主四备,让主节点为每个事务等待2个备机ACK。

任何一个事务提交操作完成后在返回给客户端之前,必须等待收到两个备机的ACK,这个事务提交状态才能返回给客户端。

同时,DBA还可以配置一个备机的特定channel是否发送ACK,即使这个备机的fullsync_relaylog_fsync_ack_level为1或者2,达到灵活配置集群高可用架构的目标。

 

点击阅读原文

推荐阅读

KunlunBase架构介绍
KunlunBase技术优势介绍
KunlunBase技术特点介绍
KunlunBase集群基本概念介绍

END

昆仑数据库是一个HTAP NewSQL分布式数据库管理系统,可以满足用户对海量关系数据的存储管理和利用的全方位需求。
应用开发者和DBA的使用昆仑数据库的体验与单机MySQL和单机PostgreSQL几乎完全相同,因为首先昆仑数据库支持PostgreSQL和MySQL双协议,支持标准SQL:2011的 DML 语法和功能以及PostgreSQL和MySQL对标准 SQL的扩展。同时,昆仑数据库集群支持水平弹性扩容,数据自动拆分,分布式事务处理和分布式查询处理,健壮的容错容灾能力,完善直观的监测分析告警能力,集群数据备份和恢复等 常用的DBA 数据管理和操作。所有这些功能无需任何应用系统侧的编码工作,也无需DBA人工介入,不停服不影响业务正常运行。
昆仑数据库具备全面的OLAP 数据分析能力,通过了TPC-H和TPC-DS标准测试集,可以实时分析新的业务数据,帮助用户发掘出数据的价值。昆仑数据库支持公有云和私有云环境的部署,可以与docker,k8s等云基础设施无缝协作,可以轻松搭建云数据库服务。
请访问 http://www.kunlunbase.com/ 获取更多信息并且下载昆仑数据库软件、文档和资料。
KunlunBase项目已开源
【GitHub:】
https://github.com/zettadb
【Gitee:】
https://gitee.com/zettadb

相关文章