这篇文章总结了之前对Galera replication的调研,内容包括Galera特性,原理,Galera cluster配置,参数及性能等
Galera replication是什么
MySQL DBA及开发应该都知道MySQL源生复制及semi-sync半同步复制,它们都基于MySQL binlog,原生复制是完全异步的,master不需要保证slave接收并执行了binlog,能够保证master最大性能,但是slave可能存在延迟,主备数据无法保证一致性,在不停服务的前提下如果master宕机让slave顶上,就会丢失数据,semi-sync在异步复制基础上增加了数据保护的考虑,master必须确认slave收到binlog后(但不保证slave执行了事务)才能最终提交事务,在没有退化(延迟较大时可能发生)成异步复制之前可以保证数据安全,此时master挂掉之后,slave可以在apply完所有relay log后切换成master提供读写服务
Galera replication是codership提供的MySQL数据同步方案,具有高可用,易于扩展等特点,它将多个MySQL节点组织成一个cluster
Galera replication特性
1. 同步复制,主备无延迟
2. 支持多主同时读写,保证数据一致性
3. 集群中各节点保存全量数据
4. 节点添加/删除,自动检测和配置
5. 行级别并行复制
6. 不需要写binlog
相对于MySQL源生复制和semi-sync,Galera replication比较有吸引力的特性:
1. 同步复制,主备无延迟,master宕机后slave可以立即顶上并提供服务(semi-sync需要apply完所有relay log)
2. 事务冲突检测保证数据一致性,多个节点可以同时读写数据,可以极大简化数据访问
3. 行级别并行复制,MySQL 5.6之前slave sql线程只有一个,这个长期饱受诟病,是导致slave落后master的主要原因
Galera replicateion限制
1. 集群至少3个节点(2个节点也可以运行)
2. 存储引擎:Innodb / XtraDB / Maria
3. 不支持的SQL:LOCK / UNLOCK TABLES / GET_LOCK(), RELEASE_LOCK()…
4. 不支持XA Transaction
目前可用的产品:MariaDB Galera Cluster 和 Percona XtraDB Cluster
Galera replication原理
Galera replication是一种Certification based replication,保证one-copy serializability,理论基于这两篇论文:Don’t be lazy, be consistent 和 Database State Machine Approach
算法示意图
图片来自上面两篇论文
算法伪代码(Certification包含了后续流程,来自上面两篇论文)
事务执行协议
遵守deferred update replication,事务在commit时才复制到其他节点,执行过程分为4个阶段:
1.Local read phase a) 本地(client连接到的节点)执行事务Ti,但不真正提交,真正提交之前进入Send phase 2.Send phase a) 若事务只读,直接提交,结束(多版本,只读事务不加锁) b) 将事务的写操作封装成WS(Write Set,基于行),广播到所有节点(包括自身) 3.Lock / Certificaion phase a) 对收到的WS中的每个WSi(X) i. 若X没有被加锁,对X加锁 ii. 若X已被Tj加锁且Tj处于Local read phase/Send phase,回滚Tj,对X加锁 iii. Certification based conflict detect 4.Write phase a) 若检测出冲突,回滚Ti b) 否则,执行WS,提交事务后释放锁资源 c) 对于源节点,提交事务并向client返回结果 |
客户端/Galera节点信息交互图
图片来自mysqlperformanceblog
Galera replication采取的是乐观策略,即事务在一个节点提交时,被认为与其他节点上的事务没有冲突,首先在本地“执行”(之所以带引号,是因为事务没有执行完)后再发送到所有节点做冲突检测,存在两种情况下需要回滚事务:
1. WS复制到其它节点,被加到每个节点的slave trx queue中,与queue中前面的trxs在做certification test时发现冲突
2. WS通过了certification test后被保证一定会执行,在它执行过程中,如果该节点上有与其冲突的local trxs(Local phase),回滚local trxs
Galera提供了两个状态参数记录冲突:
wsrep_local_cert_failures:certification test中未通过的trx数目
wsrep_local_bf_aborts:apply trxs(已经通过certification test)时,回滚的local trxs(open but not commit)数目
因此事务在commit节点广播后,节点之间不交换“是否冲突”的信息,各个节点独立异步的处理该事务,certification based replication协议保证:
1. 事务在所有节点上要么都commit,要么都rollback/abort
2. 事务在所有节点的执行顺序一致
Certification based replication所依赖的基础技术:
Group Communication System
1) Atomic delivery (事务传输要么成功传给了所有节点,要么都失败)
2) Total order (事务在所有节点中的顺序一致)
3) Group maintenance (每个节点知道所有节点的状态)
传统的2PC(两阶段提交)做法
1. 2PC 事务结束时,所有节点数据达到一致
2. 协调者与参与者之间通信,参与者之间无连接
3. 受网络状态影响较大
4. 两次通信,需要得到每个参与者的反馈后才能决定是否提交事务
因此Galera replicateion相对于2PC减少了网络传输次数,消除了等待节点返回“决定是否冲突”的时间,从而可以提高了性能
Galera replication原理总结
1. 事务在本地节点执行时采取乐观策略,成功广播到所有节点后再做冲突检测
2. 检测出冲突时,本地事务优先被回滚
3. 每个节点独立、异步执行队列中的WS
4. 事务T在A节点执行成功返回客户端后,其他节点保证T一定会被执行,因此有可能存在延迟,即虚拟同步
Galera flow control
galera是同步复制(虚拟同步)方案,事务在本地节点(客户端提交事务的节点)上提交成功时,其它节点保证执行该事务。在提交事务时,本地节点把事务复制到所有节点后,之后各个节点独立异步地进行certification test、事务插入待执行队列、执行事务。然而由于不同节点之间执行事务的速度不一样,长时间运行后,慢节点的待执行队列可能会越积越长,最终可能导致事务丢失。
galera内部实现了flow control,作用就是协调各个节点,保证所有节点执行事务的速度大于队列增长速度,从而避免丢失事务。实现原理和简单:整个galera cluster中,同时只有一个节点可以广播消息(数据),每个节点都会获得广播消息的机会(获得机会后也可以不广播),当慢节点的待执行队列超过一定长度后,它会广播一个FC_PAUSE消息,所以节点收到消息后都会暂缓广播消息,直到该慢节点的待执行队列长度减小到一定长度后,galera cluster数据同步又开始恢复
flow control相关参数:
gcs.fc_limit:待执行队列长度超过该值时,flow control被触发,对于Master-Slave模式(只在一个节点写)的galera cluster,可以配置一个较大的值,对启动多写的galera cluster,较小的值比较合适,因为较大待执行队列长度意味着更大的冲突,默认值16
gcs.fc_factor:当待执行队列长度开始小于(gcs.fc_factor*gcs.fc_limit)时,数据同步恢复,默认0.5
gcs.fc_master_slave:galera cluster是否为Master-Slave模式,默认
安装MariaDB Galera Cluster
安装准备:
1. MariaDB Galera Cluster 5.5.28a RC
1) https://downloads.mariadb.org/mariadb-galera/5.5.28a/
2) patched MariaDB 5.5.28,代码中增加了Galera Library API(wsrep API),并在事务、锁、handler等模块添加/修改了调用逻辑
2. Galera wsrep provider
1) https://launchpad.net/galera/+download
2) Galera Library的实现,其中实现了group communication system, certification
编译安装
1. MariaDB Galera Cluster 5.5.28a RC
1) 与MariaDB基本相同,cmake时增加两项:-DWITH_WSREP=ON , -DWITH_INNODB_DISALLOW_WRITES=1.
2. Galera wsrep provider: 源码编译后得到libgalera_smm.so(需要用到scons)
参数配置(每个节点)
wsrep_provider = /path/to/libgalera_smm.so
wsrep_cluster_address = cluster connection URL(后面详细介绍)
binlog_format = ROW
default_storage_engine = INNODB
innodb_autoinc_lock_mode = 2
innodb_locks_unsafe_for_binlog = 1
选配:(可以提高性能,galera保证不丢数据)
innodb_flush_log_at_trx_commit = 2
构建集群(三个节点)
节点名称 | IP地址 |
---|---|
galera_node1 | 10.0.0.11 |
galera_node2 | 10.0.0.22 |
galera_node3 | 10.0.0.33 |
新建Galera Cluster
以galera_node1作为第一个节点新建集群,在my.cnf中配置参数:
wsrep_cluster_address = gcomm:// wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.11 wsrep_node_name = galera_node1 wsrep_sst_method = rsync |
添加galera_node2节点
在my.cnf中配置wsrep_cluster_address为node1的ip或者hostname
wsrep_cluster_address = gcomm://10.0.0.11 wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.22 wsrep_node_name = galera_node2 wsrep_sst_method = rsync |
添加galera_node3节点
在my.cnf中配置wsrep_cluster_address为node1的ip或者hostname
wsrep_cluster_address = gcomm://10.0.0.11 wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.33 wsrep_node_name = galera_node3 wsrep_sst_method = rsync |
多实例配置
因为测试机器资源有限,需要在同一台机器上启动多个mysqld实例,为每个mysqld配置两个端口号(一个是mysql server端口号,默认3306;另外一个是wsrep端口号,默认4567),并修改部分wsrep配置参数,例如:
节点名称 | IP地址 | SERVER PORT | WSREP PORT | WSREP配置 |
---|---|---|---|---|
galera_node1 | 127.0.0.1 | 3306 | 4405 | wsrep_cluster_address=gcomm:// wsrep_node_address=127.0.0.1:4405 port=3306 |
galera_node2 | 127.0.0.1 | 3307 | 4407 | wsrep_cluster_address=gcomm://127.0.0.1:4405 wsrep_node_address=127.0.0.1:4407 port=3307 |
galera_node3 | 127.0.0.1 | 308 | 4409 | wsrep_cluster_addres=gcomm:// 127.0.0.1:4405 wsrep_node_address=127.0.0.1:4409 port=3308 |
启动后在每个节点执行:
|
当看到下述状态时:
wsrep_connected=ON wsrep_ready=ON wsrep_cluster_status =Primary wsrep_cluster_size=3(节点个数) |
则galera集群建立成功,如下图所示:
说明:
1. MariaDB Galera Cluster 5.5.28a RC源码安装,在编译时若没有打开-DWITH_WSREP=ON, -DWITH_INNODB_DISALLOW_WRITES=1,或者没有配置任何wsrep相关参数,它运行时就是一个普通的mysqld实例
2. Galera cluster复制不依赖于binlog文件,因此mysql-binlog和log-slave-updates都可以不配置,当然如果需要记录binlog,也可以打开
3. 需要以wsrep_cluster_address = gcomm://启动第一个节点后,才能相继添加其他节点
Galera相关参数配置
InnoDB 相关参数
galera补丁版的mysql在cmake时需要指定:
-DWITH_WSREP=ON , -DWITH_INNODB_DISALLOW_WRITES=1
galera 目前只支持Innodb/xtradb/mariad存储引擎
default_storage_engine = INNODB
为了降低冲突,下列两项需要设置
innodb_autoinc_lock_mode = 2
innodb_locks_unsafe_for_binlog = 1(gap不加锁)
选配:(可以提高性能,galera保证不丢数据)
innodb_flush_log_at_trx_commit = 2
选配:galera可以不写binlog,注释binlog路径理论上可以提高性能
#log-bin
#log-slave-updates=1
wsrep 相关参数
wsrep参数都是以wsrep_开头的(30+个),其中有一个字符串参数(wsrep_provider_options)可以配置50+个更底层的参数。
可以通过“show variables like wsrep%”查看,wsrep_开头参数,点击查看详情
列举几个重要的参数:
wsrep_auto_increment_control:控制auto_increment_increment=#nodes和auto_increment_offset=#node_id,默认ON wsrep_causal_reads:默认是在本地节点读,读到的可能不是最新数据,开启后将读到最新数据,但会增加响应时间,默认OFF wsrep_certify_nonPK:为没有显示申明主键的表生成一个用于certification test的主键,默认ON wsrep_cluster_address: 启动节点时需要指定galera cluster的地址,作为cluster中第一个启动的节点,wsrep_cluster_address=gcomm://,对于后续启动的节点,wsrep_cluster_address=gcomm://node1,node2,node3 wsrep_cluster_name: 所有node必须一样, 默认my_test_cluster wsrep_convert_LOCK_to_trx:将LOCK/UNLOCK TABLES转换成BEGIN/COMMIT,默认OFF wsrep_data_home_dir:galera会生成一些文件,默认使用mysql_data_dir,默认mysql_data_dir wsrep_node_name:节点名称 wsrep_on:session/global,设置为OFF时,事务将不会复制到其他节点,默认ON wsrep_OSU_method:Online Schema Update设置,TOI/RSU(MySQL >= 5.5.17),默认TOI wsrep_provider:libgalera_smm.so的路径,若没有配置,galera复制不会启动,默认none wsrep_provider_options:很长的字符串变量,可以配置很多group communication system相关参数,很长很长... wsrep_retry_autocommit:事务在冲突时重新尝试的次数,默认1 wsrep_slave_threads:并行复制的slave线程数,默认4 wsrep_sst_method:Snapshot State Transter方法:mysqldump/rsync/xt,默认mysqldump |
wsrep_provider_options
该参数是一个字符串,包含了group communication system中很多参数设置,配置时使用分号隔开:
wsrep_provider_options=”key_a=value_a;key_b=value_b;key_c=value_c”,点击查看详情
列举其中部分重要参数:
evs.send_window:节点一次可以发送的消息数目,默认4 evs.user_send_window:其与evs.send_window之间的差别类似于max_connections与max_user_connection,默认2 gcs.fc_factor:flow control参数,默认0.5 gcs.fc_limit:flow control参数,默认16 gcs.fc_master_slave:flow control参数,默认NO gcs.recv_q_hard_limit:接收队列的占用的最大内存,默认LLONG_MAX gcs.recv_q_soft_limit:当接收队列占用内存超过(gcs.recv_q_hard_limit*gcs.recv_q_soft_limit),复制被延迟,默认0.25 gmcast.listen_addr:节点用于接收其它节点消息的地址,默认tcp://0.0.0.0:4567 pc.checksum:是否对发送的消息做checksum,默认true pc.ignore_sb:是否忽略split brain,默认false |
一个例子
binlog_format=row default-storage-engine = INNODB innodb_autoinc_lock_mode = 2 innodb_locks_unsafe_for_binlog = 1 wsrep_provider = /u01/mariadb-galera/lib/libgalera_smm.so wsrep_cluster_address = "gcomm://192.168.xxx.01" wsrep_cluster_name = galera wsrep_node_address = 192.168.xxx.xxx wsrep_node_name = slave wsrep_sst_method = rsync wsrep_slave_threads = 16 wsrep_provider_options="gcache.page_size=128M;gcache.size=2G;gcs.fc_limit=512;gcs.fc_factor=0.9;evs.send_window=256;evs.user_send_window=128" |
Galera status variables
Galera提供了很多以wsrep_开头状态参数监控mysql状态,通过show status like ‘wsrep%’可以查看:
wsrep_local_state_uuid:应该与wsrep_cluster_state_uuid一致,如363acc29-9160-11e2-0800-4316271a76e4 wsrep_last_committed:已经提交事务数目,所有节点之间相差不大,可以用来计算延迟 wsrep_replicated:从本地节点复制出去的write set数目 wsrep_replicated_bytes:从本地节点复制出去的write set的总共字节数 wsrep_received:本地节点接收来自其他节点的write set数目 wsrep_received_bytes:本地节点接收来自其他节点的write set的总共字节数 wsrep_local_commits:从本地节点发出的write set被提交的数目,不超过wsrep_replicated wsrep_local_cert_failures:certification test失败的数目 wsrep_local_bf_aborts:certification test通过的write set执行过程中回滚的与其冲突的本地事务 wsrep_local_replays:事务被回滚(bf abort)重做的数目 wsrep_local_send_queue:发送队列的长度 wsrep_local_send_queue_avg:从上次查询状态到目前发送队列的平均长度,>0.0意味着复制过程被节流了 wsrep_local_recv_queue:接收队列的长度 wsrep_local_recv_queue_avg:从上次查询状态到目前接收队列的平均长度,>0.0意味着执行速度小于接收速度 wsrep_flow_control_paused:从上次查询状态到目前处于flow control的时间占比,如0.388129 wsrep_flow_control_sent:从上次查询状态到目前节点发送出的FC_PAUSE消息数目,如1 wsrep_flow_control_recv:从上次查询状态到目前及节点接收的FC_PAUSE消息数目,如1 wsrep_cert_deps_distance:可以并行执行的write set的最大seqno与最小seqno之间的平均差值,如1851.825751 wsrep_apply_oooe:队列中事务并发执行占比,值越高意味着效率越高 wsrep_commit_window:平均并发提交窗口大小 wsrep_local_state:节点的状态,取值1-6 wsrep_local_state_comment:节点的状态描述,比如Synced wsrep_incoming_addresses:集群中其它节点的地址,多个地址之间用逗号分隔 wsrep_cluster_conf_id:集群节点关系改变的次数(每次增加/删除都会+1) wsrep_cluster_size:集群节点个数 wsrep_cluster_state_uuid:集群uuid,所有节点应该一样,如:363acc29-9160-11e2-0800-4316271a76e4 wsrep_cluster_status:集群的目前状态,取值:PRIMARY(正常)/NON_PRIMARY(不一致) wsrep_connected:节点是否连接到集群,取值:ON/OFF wsrep_local_index:节点id wsrep_provider_name:默认Galera wsrep_provider_vendor:默认Codership Oy |
一个截图:
如何检查节点是否加入到集群
1. wsrep_cluster_state_uuid应该与其它所有节点相同
2. wsrep_cluster_conf_id应该与其它所有节点相同
3. wsrep_cluster_size应该是所有节点的数目
4. wsrep_cluster_status取值应该是:Primary
5. wsrep_ready取值应该是ON
6. wsrep_connected取值应该是ON
判断复制过程是否出现问题
wsrep_flow_control_paused,正常情况下,其取值应该接近于0.0,大于0.0意味着有‘慢节点’影响了集群的速度,可以尝试通过增大wsrep_slave_threads来解决
找出最慢的节点
wsrep_flow_control_sent,wsrep_local_recv_queue_avg两个值最大的节点
参考:galera status,galera monitoring
性能测试
由于galera同步复制在每个写事务提交时都增加了replicate trx和certification test的开销,因此性能远远低于异步MySQL实例
测试场景
使用TPCC进行测试,包含3组数据:
1、normal mysql: baseline,单个mysql server
2、galera (RTT: 0.5ms): 2-nodes galera cluster,单节点读写
3、galera (RTT: 15.2ms): 2-nodes galera cluster,单节点读写
tpmC结果:
TPS结果:
测试结论:
1. 相对于异步MySQL实例,Galera replication性能下降约50% ~ 60%左右
2. Galera最大性能不受RTT影响,RTT 较小时(0.5ms),在达到最大性能之前(32并发),性能下降并不明显 (32并发下降25%,16并发性能下降更低),RTT较大时(15.2ms),在达到最大性能之前(64并发),相对于norml mysq性能下降一直到很明显,当压力逐渐增大,由于group io的原因,galera性能在达到最大时还会提高
Galera replication for MySQL学习资料
1. codership官网
2. mysqlperformanceblog搜索中PXC(Percona XtraDB Cluster)