您的位置:首页 > 数据库 > MariaDB

Mariadb高可用方案初步研究

2020-07-16 16:51 1976 查看

mariadb是mysql的一个重要分支,与mysql完全兼容,可以完全理解为mysql的存在。现在我们讨论一下mariadb的高可用方案。mariadb的常见的高可用方案有:主从复制架构和Galera,本篇文章首先会简单介绍各个方案的基本原理,然后记录部署的过程,接着去测试。

一、主从复制

复制过程

主从复制架构是mariadb默认的高可用方案,采用主从架构,一主多从的模式,主库负责写数据库,从库负责读数据库,利用binglog来保证主从一致性,是一种异步复制的模式。

​ 主库 A 的更新流程:A在接受一个来自客户端的更新请求之后,首先在undolog 内存中写入,然后存入硬盘,在redolog恢复日志 prepare 阶段完成之后,写入 binlog ,最后再 commit ,完成 A这边的一套完整的执行内部事务的更新逻辑。

​ 从库B的同步流程:B 和 A 之间维持了一个长链接,在B上,我们会设置A的账号信息,以及日志位置和偏移量,同步时,我们会主动执行一次 start slave 命令,启动 io_thread 和 sql_thread 两个线程 。io_thread 与A建立请求,主库 A 接受请求,然后检验,把A的binlog 发送给B 。B终于拿到A 的binlog ,写到本地日志即relay log 。 sql_thread 处理B上的 relay log ,解析binlog。

主从延迟问题

​ 主从延迟问题是主从结构最常出现的问题,可能会导致过期读的问题,可能的原因有:

  • 主备机器性能不一致,往往备库会比主库机器配置差,这个问题可以采用对称部署来解决
  • 备库上随意的无压力控制的操作,影响同步操作,就是说备库上压力大,可以采用一主多从的架构分散压力;
  • 可能是大事务,这种时候我们只能人为的去避免了;
  • 如果备库执行日志的速度持续低于主库生成日志的速度 ,我们可以提高sql_thread的数量进行并行复制。

如何读写分离

​ 由于主从的特性,所以我们可以做成读写分离的模式,这个需要代理层的实现。我是选择proxysql作为代理层,如何进行读写分离的部署,后续安排。。。。

二、Galera

​ Galera是一种多主多活的集群架构,该集群中的mariadb实例是对等的,互为主从,当客户端读写数据时,可连接任一实例。对于读操作,从每个节点读取到的数据都是相同的。对于写操作,当数据写入某一节点后,集群会将其同步到其它节点。这种架构是一种高冗余架构。

复制原理

同步复制和异步复制

​ galera采用的是同步复制,相比于mysql默认的异步复制:

1、同步复制保证了整个集群的数据一致性,无论何时在任何节点执行相同的select查询,结果都一样。

2、由于所有节点数据一致,单个节点崩溃不需要执行复杂耗时的故障切换,也不会造成丢失数据或停止服务。

3、同步复制允许在集群中的所有节点上并行执行事务,从而提高读写性能。

基于认证的复制

​ Galera Cluster 实现了基于认证的复制,它使用集群间通信和事务排序的技术来实现同步复制。 事务首先会在一个节点执行,当事务需要提交时,会需要一个集群协商的认证过程来确保全局的一致性,只有能够保证全局一致性的事务才会被成功提交,是一种典型的乐观锁机制。

​ 上图描述了Galera复制的过程,文字描述如下:

​ 1、先在本地执行一个事务,在它执行

commit
之前,这个事务的信息和修改涉及到的所有主键被合并到一个写集中,数据库会将这个写集广播到其他所有节点。

​ 2、然后这个写集复制到其它节点,被加到每个节点的slave trx queue中进行认证测试,认证时候会使用写集中的主键信息。 如果认证测试失败,那么这个写集被丢弃,事务进行回滚操作。如果认证测试成功,事务就一定会被执行。

​ 3、所有的事务在每个节点中都是独立认证,而且是串行进行,而且每个节点中的slave trx queue中的事务顺序是一致的,因此他们能够保证一起提交一起回滚,减少了两阶段提交中的回馈机制,这样就不需要等待所有节点都提交完才返回给客户端,提高了性能。

apply_db:这个步骤我的理解是就是将已经认证的改动应用到自己的节点上,这个步骤就可以利用多线程进行性能提升。

全局事务ID

​ 在 Galera Cluster 中,每个事务都有一个全局的事务ID(DTID),这个ID是唯一并且递增的;

​ GTID 由两部分组成:

  • State UUID:用来表示状态版本的 UUID
  • 序列号:一个 64 位的整数,用来表示这个事物在事物序列中的顺序位置

​ 当一个事务需要提交时,每个节点会将此事务的序列号与本节点最后一次成功提交的事务的序列号进行比较,在这两个事务之间的所有未提交的事务都会被用来进行主键冲突测试,如果需要提交的事务与在此区间的事务有主键冲突的可能,那么认证测试会失败。

流控原理

​ Galera集群内部使用一种称为流控的反馈机制来管理复制过程。流控保证所有节点执行事务的速度大于队列增长速度,从而避免丢失事务。

​ 实现原理:整个galera cluster中,同时只有一个节点可以广播消息(数据),每个节点都会获得广播消息的机会(获得机会后也可以不广播),当慢节点的待执行队列超过一定长度后,它会广播一个FC_PAUSE消息,所以节点收到消息后都会暂缓广播消息,直到该慢节点的待执行队列长度减小到一定长度后,galera cluster数据同步又开始恢复

三、部署

​ 所有的部署我都在k8s集群中完成,我部署了一个k8s单节点集群,利用helm进行部署,helm是k8s的包管理工具,类似于centos中的yum,以及ubuntu中的apt。这里我只部署了主从架构和galera。在开始之前先介绍一下helm

helm简介

​ 在helm中有这么几个概率需要简单了解一下。

Chart:一个 Chart是一个 Helm 包。它包含在 Kubernetes 集群内部运行应用程序,工具或服务所需的所有资源定义。把它想像为一个自制软件,一个 Apt dpkg 或一个 Yum RPM 文件的 Kubernetes 环境里面的等价物,也可以类比为docker中的镜像。

Repository:一个 Repository是 Charts 收集和共享的地方,类似于docker hub那样的。

Release:一个 Release是处于 Kubernetes 集群中运行的 Chart 的一个实例。一个chart通常可以多次安装到同一个群集中。每次安装时,都会创建一个新 release。

​ 一个chart包包含如下内容:

testapi-chart
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── NOTES.txt
│   └── service.yaml
└── values.yaml

​ 这是一个标准的chart包,我们主要关注

templates
values.yaml
。templates这个文件夹中是k8s的资源描述文件模板,模版里面的内容可以通过 values.yaml里面的内容去渲染,因此我们在部署的时候主要是修改values.yaml中的内容

安装helm

​ 这里我使用的是helm3,安装helm3比较简单,如果是helm2就比较麻烦了,helm3和helm2最大的区别是,helm3没有tiller(helm2的服务端),由于国内的环境,tiller比较难安装,安装完成以后还需要一些配置才可以使用,所以不推荐。

wget https://storage.googleapis.com/kubernetes-helm/helm-v3.2.1-linux-amd64.tar.gz

tar -zxvf helm-v3.2.1-linux-amd64.tar.gz

cd linux-amd64/

cp helm /usr/local/bin/

此时helm安装完毕后,设置仓库,这里我使用的是

bitnami
的仓库

helm repo add bitnami https://charts.bitnami.com/bitnami

部署主从

首先我们先下载mariadb的chart,这个命令helm2没有

helm pull bitnami/mariadb

解压下载的chart,然后我们需要根据自己的需求更改

values.yaml
,然后用这个文件去覆盖原chart包中
values.yaml
。这里要注意持久卷的挂载,可以选择不挂载,或者自己先创建好pvc,不然就无法启动

helm insatll mariadb -f mariadb/values.yaml mariadb-7.6.1.tgz

稍等一会后,一个一主两从的架构就部署好啦,是不是很简单!可以通过修改values.yaml中replicas值可以改变从库的数量。

部署Galera

在部署galera的时候,没有用官方给的chart,原因是galera集群如果节点全部挂掉的情况下,需要最先启动最新的节点,也就是

wsrep_last_committed
值最大的那个节点,目的是为了不丢失数据。这样就需要人工干预,这是不能忍的啊。。。因此通过github找到大佬的方案:https://github.com/jijeesh/kubernetes-mariadb-galera,部署步骤包含在里面,不在说明。

原理:在Mariadb的基础上,加入了一层用shell写的entrypoint层和etcd进行交互,定时向etcd报告

wsrep_cluster_state_comment
wsrep_last_committed
的值,作为启动集群时候的参考。

wsrep_cluster_state_comment:节点状态
wsrep_last_committed:最后提交的事务序列号

原文:https://severalnines.com/database-blog/deploy-homogeneous-galera-cluster-etcd

四、高可用测试

​ 高可用测试的目的是为了测试节点挂掉后,整个集群是否能够提供服务,并且整个集群挂掉后恢复后数据是否丢失。这里我的测试过程是就是干掉pod来观察集群的状态,比较简单,因此就不放测试的过程,直接放结论。

主从

1、主节点挂掉后,整个集群只能读不能写;

2、从节点其中一个挂掉后不会产生任何影响;

3、整个集群挂掉后,重新起来后数据仍然可访问;

galera

1、只要存在一个或者以上的节点存活,服务不受影响,可正常读写,等待其他节点恢复正常后,数据自动同步;

2、同时删除所有的pod后,意味着关闭整个集群,集群会自动进行重启,重启以后数据没有丢失,可继续提供服务;

五、压力测试

我使用的是

sysbench
进行测试,分别测试单机、galera的tps和qps,以及读写性能。主从我没测,因为没部署好

测试环境:8核16GB,k8s集群,系统为centos7

1、先创建一个sysbench的pod并进入pod内

kubectl run sysbench-client --rm --tty -i --restart='Never' --image  docker.io/severalnines/sysbench:latest --namespace default --command -- bash

2、执行以下命令,在sbtest数据库中创建10个表,每个表中数据为100000条,线程数是100个,测试时长为5min,mysql-host可以通过

kubectl get svc
查看,需要先
prepare
,然后
run
,测试完毕后
cleanup

sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua
--mysql-host=galera-mariadb-galera
--mysql-port=3306  --mysql-user=root
--mysql-password=123456
--mysql-db=test --oltp-test-mode=complex
--oltp-tables-count=10
--oltp-table-size=100000
--threads=100
--time=300
--report-interval=10 run

经过测试后,我们得出:

方案 TPS QPS 95th percentile
单机 1482 29657 145ms
galera 828 12243 612ms

​ 测试完发现galera集群的性能只有单机版的50%左右,就是感觉不太对啊,后来才明白没有控制变量,应该保证每个pod的资源配额保持一致!

​ 因此为了进一步认证,接下来限制pod的资源上限继续进行测试,每个pod分配的资源为:0.25cpu\3GB,重复上面步骤,得出结论:

方案 TPS QPS 95th percentile
单机 61 1231 2680ms
galera 148 2987 1191ms

​ 这个测试数据还是比较正常的,因此接下来的测试都会进行资源配额。

​ 通过查阅资料,我们发现在galera集群中有参数

wrep_slave_threads
对性能影响非常大,这个参数表示节点中有多少线程来应用到从属的写集中。接下来测试这个参数对性能影响到底有多大?

​ 测试环境:每个pod分配的资源为:0.25cpu\3GB

wsrep_slave_threads TPS QPS 95th percentile
2 98 2028 3040ms
4 62 1255 6026ms
8 83 1716 3639ms
16 95 1775 2880ms
32 104 2124 2449ms
64 132 2678 1618ms
128 148 2987 1191ms

​ 可见这个参数对性能的影响还是比较明显的,官方建议我们这个值的大小最好要大于cpu核心数的两倍,但是也不要太高,需要我们根据自己的环境去选择合适的大小。

总结

​ 总的说来,galera集群兼顾了性能和高可用,是一种可以考虑的高可用方案,但是仍然存在一些比较严重的问题,比如脑裂等问题,这个需要去解决;对于一个读多写少的环境,采用主从结构可能是一个更好的选择,主从架构的测试后续会安排上。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: