美文网首页
入坑MySQL组复制

入坑MySQL组复制

作者: 有财君 | 来源:发表于2019-05-29 21:40 被阅读0次

    1. MySQL复制技术简介

    1.1 MySQL复制技术的简介

    MySQL的复制经历了如下几个阶段:

    • 异步复制:最传统的复制集群采用的就是这种形式的复制,Master只负责通知Slave取binlog,但是是否正确取走并回放Master是不管的;

    • 半同步复制:这种方式在MySQL5.7中得到了加强,大致的算法是Master仅仅将事务标记为prepare,直到Slave返回binlog转存本地成功的ACK后才将事务真正的提交;

    • 组复制:即MGR技术,通过实现Paxos算法来保证集群数据的高可用性,具体的算法是添加了一个一致性层,提交事务之前发送集群广播,只有获得一致性层同意之后才能提交事务。Paxos协议很复杂,如果有时间会在后面附上其简化版Raft协议的介绍。

    我们可以把异步复制和半同步复制成为传统复制,而将MGR称为新技术。事实上,官方在推出增强型半同步复制时已经宣称MySQL可以提供金融级别的数据一致性保证,而很多云厂商基于MySQL增强型半同步复制的数据库产品也宣布自己支持金融级别的安全性。

    下图是传统异步复制的原理示意图:

    异步复制

    事务的提交和Slave是否正确转存binlog之间没有联系,传统的复制在数据一致性方面一直饱受诟病。

    下图是增强型半同步复制的原理示意图:

    半同步复制

    任何一个事务的提交仅仅是标记为提交,我们可以用分布式系统中常见的两阶段提交的概念来理解这种方式,只有当集群中大于一定数量的节点返回了ACK之后,事务才会被真正的提交。

    下图是本文中重点论述的MGR的原理示意图:

    组复制

    如图,MGR中实现了一个一致性层,这是实现了Paxos协议的地方,当一个事务将要被提交时,会在一致性层发送广播,这个广播包含的内容主要有具体的行变更和被变更的行号,并且会给这个事务一个全局事务号,这意味着所有的节点都要以同样的顺序接收同样的广播,这涉及到Paxos协议的具体实现,在这里不具体展开描述了。

    总结MGR的技术特点就是增加了一致性层,一个事务的提交,只有当一致性层决定同意之后才能进行。这样就保证了数据的强一致性,Paxos协议的设计初衷就是保证分布式集群的数据一致性的。

    Paxos协议在保证了一致性的同时还会保证高可用性,一个节点数为n(n为奇数)的集群,其可容忍的失效节点为(n-1)/2个,也就是说我们应该提供一个至少三节点的MGR集群。

    1.2 MGR的高可用

    MGR有一套故障检测机制,大致描述如下:

    1. 检测到有一台节点可能死掉了,可以是分布在每个节点上的故障检测服务广播心跳断掉了;
    2. 发起集群中的投票,如果获得多数票,则认为该节点真的死掉了;
    3. 集群决定将已死节点摘除,继续对外提供服务。

    如果一个节点被摘除出去,但是实际上并没有死掉(可能因为网络原因,心跳无法发送出去),它会假设其他节点都死掉了(该节点本身不知道自己被摘除了),并且此时已经不存在一致性层了,为了数据安全,该节点拒绝对外继续提供服务。

    基于上述事实,如果一个n节点的集群中只有一台机器存活时,集群将无法提供服务。

    在此重新提一下集群的容灾能力:

    一个节点数为n(n为奇数)的集群,其至多可以容忍(n-1)/2个节点失效。

    2. MGR IN ACTION

    MGR有两种模式:单主模式和多主模式。其中单主模式是默认模式。

    <a name="vPhOw"></a>

    2.1 单主模式

    单主模式中,只有设置为primary的节点有写入能力,其他节点是只读节点。这种模式下,集群中的primary节点出现故障时会进行重新选举的过程:

    image.pngimage.png

    因为其余secondary节点没有写的能力,因此需要重新选出一个primary节点来提供服务。这个选举的过程是Paxos协议保证的。

    现在大部分的分布式集群是基于Raft协议实现的,Raft协议只会支持单主模式的实现,因此现存的大部分分布式数据库系统,都是单点写入,即便是实现了分片,在每一个片中也只是一个节点在提供写服务。

    <a name="yrzPW"></a>

    2.1 多主模式

    多主模式中,集群中所有的节点都可以是priamry,这样也就不存在单主模式中的选举的概念了,那么多主模式的故障处理应该是这样的:

    image.pngimage.png

    2.2 MGR的要求和限制

    MGR有下述要求:

    • 只能选择InnoDB引擎
    • 每个表必须有主键
    • 仅支持IPv4网络
    • 对网络环境要求高

    MGR对参数的要求如下:

    • 必须配置log-bin参数
    • 必须开启log-slave-updates
    • 必须将binlog-format配置成row格式
    • 必须关闭binlog-checksum参数
    • 必须将gtid-mode设置为开启状态
    • 设置master-info-repository=TABLE
    • 设置relay-log-info-repository=TABLE
    • 设置transaction-write-set-extraction=XXHASH64
    • 可选择配置slave-parallel-workers=N,slave-preserve-commit-order=1,slave-parallel-type=LOGICAL_CLOCK

    MGR有如下限制:

    • GAP Lock,这个其实并不影响什么,不需要额外关心,Gap Lock是InnoDB的一种锁算法,具体实现参见附录中的参考资料;
    • 不支持Lock Tables等语句;
    • 不支持SERIALIZABLE隔离级别,实际上这个隔离级别除了测试的时候,没有实用价值;
    • 多主模式下,不允许在不同节点上同一张表上同时做ddl和dml;
    • 多主模式不支持级联外键,MySQL一般情况下也不推荐用外键;
    • 多主模式下不要使用select ... for update,可能会引起死锁;
    • 不再允许复制过滤。

    2.3 代理层

    观察一下下面这张图:

    image.pngimage.png

    这是官方给出的MGR结构示意图,其中的Clients我们可以理解为上层的服务。从这个角度上看,服务需要知道所有的存储层细节,这也就意味着我们的服务需要对所有的配置进行更改。

    对于一个数据库存储层来说,我们需要做的是让上层服务不管是使用单节点,双主结构,一主多从结构或者MGR都可以用同一种配置,不管底层存储结构如何变更,服务永远感觉是一个节点。

    其连接串也尽量保持简单:

    jdbc:mysql://IP:PORT/DB
    

    为了满足这一需求,将存储层和业务层进行隔离是有必要的。在我们现在的系统中,我们的双主架构同样不直接和服务进行接触,而是通过一个VIP来进行隔离。

    增加了代理层的概念之后,上面的架构会变成如下图的样子:

    image.pngimage.png

    这样,不管存储层变成什么结构,只要变更代理的配置即可,对于上层业务来说是没有感知的。代理层一般选择比较轻量级的实现方案,现在比较优秀的实现方案是Percona公司工程师开发的ProxySQL。

    当然,我们对代理层的要求至少是代理要自动发现MGR集群的故障切换,自动识别新的primary节点,在现在的版本下,ProxySQL是可以做到的。它通过集群中的READ_ONLY参数进行识别,自动将新的primary节点加入到自己的配置表中。

    但是引入Proxy之后还需要考虑Proxy的高可用,一般来说,都是采用双Proxy+keepalived的方案来实现Proxy的高可用。

    优秀的代理层工具还可以提供读写分离的能力。

    3. MGR的部署参考手册

    MGR部署至少要求三台机器,每台机器的MySQL都应该配置GTID,下面是GTID的相关参数:

    gtid_mode=on
    enforce_gtid_consistency=1
    log_slave_updates=1
    

    另外,有一些核心的MySQL参数,列举如下,必须按照列举的选项进行配置:

    binlog_format=row
    performance_schema=ON
    binlog_checksum=NONE
    
    ## group replication
    transaction_write_set_extraction = XXHASH64
    ## 这里随机生成一个UUID,一定要是UUID,每个节点都要保持一样的UUID
    loose-group_replication_group_name = "9ac06b4e-13aa-11e7-a62e-5254004347f9"
    loose-group_replication_start_on_boot = off
    ## 这是本机的IP,同时找一个端口,每个节点变更此参数为本机IP
    loose-group_replication_local_address = "192.168.150.131:23306"
    ## 这里是群组的所有机器
    loose-group_replication_group_seeds = "192.168.150.131:23306,192.168.150.134:23307,192.168.150.135:23308"
    loose-group_replication_bootstrap_group = off
    ## 这两个选项配置单主模式
    loose-group_replication_single_primary_mode = true
    loose-group_replication_enforce_update_everywhere_checks = false
    

    下面的步骤中,会在每一步说明该步骤要在哪些节点上执行。

    首先,在所有节点上安装插件,这是一个MySQL命令,需要在所有节点下执行:

    INSTALL PLUGIN group_replication SONAME 'group_replication.so';
    

    组复制是以插件形式提供的,因此必须首先执行该命令,否则后续步骤无法进行。

    在其中一台机器上(这台机器被当做主节点)执行下面的语句,这些都是SQL命令:

    -- 标记下面的语句不会被记录在binlog中
    SET SQL_LOG_BIN=0;
    -- 新建一个用于复制的用户
    grant replication slave on *.* to repl@'%' identified by 'repl';
    -- 这里会真的指定组复制
    change master to master_user='repl',master_password='repl' for channel 'group_replication_recovery';
    -- 一些参数配置
    set global group_replication_bootstrap_group=ON;
    -- 启动组复制
    start group_replication;
    
    SET SQL_LOG_BIN=1;
    

    完成了上述的操作之后,组复制会被启动起来,此时的集群内只有一台机器,接下来开始配置其他节点:

    SET SQL_LOG_BIN=0;
    grant replication slave on *.* to repl@'%' identified by 'repl';
    change master to master_user='repl',master_password='repl' for channel 'group_replication_recovery';
    set global group_replication_allow_local_disjoint_gtids_join=ON;
    start group_replication;
    SET SQL_LOG_BIN=1;
    

    这样就启动了secondary节点,此时在任意节点上执行这个SQL:

    SELECT * FROM performance_schema.replication_group_members;
    

    得到的结果应该是这样的:

    图片.png图片.png

    三个节点都处于ONLINE状态则表示集群状态正常。

    4. 小结

    到这里虽然搭建了MGR集群,但是还没有代理,因此也就暂时没有办法对外提供服务,在以后的文章中,我会仔细描述代理如何添加。

    相关文章

      网友评论

          本文标题:入坑MySQL组复制

          本文链接:https://www.haomeiwen.com/subject/lmwutctx.html