• MySQL 高可用(上)

    背景

    MySQL的高可用方案在生产环境中应用非常普遍,顾名思义,它的存在意义就是为了保证数据库可以实现高可用,不阶段的为我们服务。 那么当前都有哪些比较常用的高可用技术呢?

    MySQL的各种高可用方案,大多是基于以下几种基础来部署的:

    1. 基于主从复制;
    2. 基于Galera协议;
    3. 基于NDB引擎;
    4. 基于中间件/proxy;
    5. 基于共享存储;
    6. 基于主机高可用;

    那么,这么多方案,到底哪个才是适合自己的使用场景呢?   或者说我们衡量一套高可用方案的标准是什么呢?

    1. 故障切换响应时间(这个是很重要的一个因素)
    2. 服务资源的利用率(有些高可用的框架导致备份从库占用过多)
    3. 切换后对线上服务的影响(比如切换后是否会造成数据紊乱,或无法提供线上服务)
    4. 维护成本和难度(出问题了还是得运维亲自上啊)
    5. 是否具有灵活的二次开发特性(可以改造适用于自己的生产环境)
    6. 是否会产生脑裂等常见的问题

    我们后面赘述的方案都将经历上述标准的考验!

    基于主从复制的高可用方案

    1. 双节点主从复制的高可用方案

    双节点是小型规模数据库的最常态。 搞两台服务器,分别搭建两个MySQL,做个一主一从或者双主模式,在master节点发生故障后,利用keepalived/heartbeat的高可用机制实现快速切换到slave节点。

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2016-12-24-%e4%b8%8a%e5%8d%8811-27-01

    两台机器分别安装了keepalived,用一个虚IP(VIP)实现mysql服务器的主备自动切换功能。当master宕掉后,keepalived会自动接管这个VIP,使用slave继续提供服务。在这样的集群中,Master对外提供全部的服务,Slave处于备份状态。这是最简单的高可用架构!那么他的质量如何呢? 我们用上面的标准来衡量他一下:

    高可用特性 特性(个人意见,仅供参考)
    故障响应时间 很快,秒级(当然这个也和keepalived配置的故障切换方式有关系)
    服务资源的利用率 较低,从库基本上没有投入使用,只是处于备份状态。
    切换后对线上服务的影响 较大(这个得根据keepalived配置的故障切换方式,也和主从延迟等状态有关系。单纯的切换IP很快,但是如果想要做到主库宕掉以后的差错补齐的话恐怕还需要一定的时间)
    维护成本和难度 较简单(但是直接切换IP后,如果故障切换的不是很完美,那么后续的数据修复就比较麻烦)
    是否具有灵活的二次开发特性 说白了keepalived只是一个虚IP的切换机制,至于什么时候切换,怎样切换得自己来掌控,个人觉得其实这样也好。 可以根据自己的业务场景来配置。
    是否会产生脑裂等常见的问题 可能会

    接下来我们试着搭建这样一套最简单的MySQL高可用架构。

    1. 搭建一个拥有正常复制状态的主从结构,具体过程可参考之前的博文(Linux搭建mysql5.7 GTID 主从复制环境

    2. 安装配置keepalived,具体可参考之前的博文(http://www.foreverlakers.com/tag/keepalived/),我这里将我的keepalived配置文件贴出来供参考

    Master :

    Slave :

    test_shutdown.sh :

    3. 分别在Master 和 Slave上启动keepalived 进程,就会看到在Master的eth0网卡上多了一个VIP,10.75.250.1.

    4.  然后我们测试将Master上面的MySQL进程shutdown,发现VIP立刻被切换在Slave上面,Successed!

    上面的过程看似非常简单,但其实存在很多缺陷和漏洞,例如:

    1. 如果Master 宕机时主从有延迟,那么就会造成数据的永久丢失。
    2. 当Master所在的服务器恢复正常后,我们的系统不能自动的去发现它并恢复。
    3. 如果从库的配置劣与主库,那么有可能在故障切换之后从库也发生问题。

    那么我们应该怎么解决这些问题呢 ?

    1. MySQL 开启双1 参数(酌情而定)保证服务器宕机时,Master本身不会丢失数据。
    2. 使用MySQL的半同步复制来避免主从延迟,或者用MySQL的高版本并发复制尽量减少主从延时,或利用NFS等工具实时备份binlog。
    3. 开启GTID复制模式,并且打开Slave的log-slave_updates参数。
    4. 把两个主从节点的auto_increment_increment(自增步长)和auto_increment_offset(自增起始值)设成不同值。其目的是为了避免master节点意外宕机时,可能会有部分binlog未能及时复制到slave上被应用,从而会导致slave新写入数据的自增值和原先master上冲突了,因此一开始就使其错开;当然了,如果有合适的容错机制能解决主从自增ID冲突的话,也可以不这么做;
    5. 加强从库的硬件配置。
    6. keepalived的检测机制需要适当完善,不能仅仅只是检查mysqld进程是否存活,或者MySQL服务端口是否可通,还应该进一步做数据写入或者运算的探测,判断响应时间,如果超过设定的阈值,就可以启动切换机制。
    7. keepalived最终确定进行切换时,还需要判断slave的延迟程度。需要事先定好规则,以便决定在延迟情况下,采取直接切换或等待何种策略。直接切换可能因为复制延迟有些数据无法查询到而重复写入。

    其实,到这里我们可能会想,能不能将MHA或者MMM这类型的成熟且开源的高可用解决方案应用在这种只有一主一从的场景中呢?这样的话,就会方便很多?其实也是可以的,不过这个扯起来就有些远了,我们后面在讲MHA的时候再具体谈谈吧。

    这里稍微再扯一点关于宕机后的主库恢复。 比如宕机的主库服务器 A 经过运维处理恢复正常了,这时候新的主库B 已经在正常工作了,我们应该怎么将它重新纳入我们的集群中呢?  再想直接做主库是不现实了,那么做从库需不需要重新拉备份呢 ?

    遇到这种情况,第一步应该做的是在B执行show slave status 拿到当时事故发生时B的复制状态,在A上执行show master status得到A的binlog记录信息,对比两者来确认当时事故发生时,是否有主从延迟导致的数据丢失。 如果发现在B上得到的Relay_Master_Log_File和Exec_Master_Log_Pos与A 执行show master status的结果一致,那么可能事故并没有造成数据丢失。但是如果前者大于后者,那么就要确认是否有数据丢失,并针对性的进行恢复。

    然后A是否需要重做也是分情况的。如果你没有开启GTID,那么或许可以尝试着去拿到B上show slave status 的结果,记录当时事故发生点对应的relay-log,并从relay-log中解析出B当时具体发生的事务。  然后去对比B的binlog看这些事务刚好发生在B本身的哪个file和pos 。如果确认了,或许可以尝试着直接从A上change master到B上。 否则就只能重做了。

    如果开启了GTID,那么事情就会简单许多。 可以很容易就找到那个position,并跟上复制。

    2. 多节点主从复制高可用方案

    如果我们把上面的双节点简单扩展一下,变成如下的架构:

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2016-12-24-%e4%b8%8b%e5%8d%886-01-11

    其他的都一样,只是在Master后面又多加了几个新的Slave。 当Master出问题的时候,Keepalived依旧将VIP飘到了Slave 1上,但最大的问题就在于其他的Slave也需要将自己的复制源从Master改为Slave1 。 复制源修改的命令语法很简单即CHANGE MASTER TO MASTER_HOST='xxx', MASTER_LOG_FILE='xxx', MASTER_LOG_POS=nnnn。而难点在于,由于同一个事务在每台机器上所在的binlog名字和位置都不一样,那么怎么找到Master当前同步停止点,对应Server 1master_log_filemaster_log_pos是什么的时候就成为了难题。这也就是为什么M-S复制集群需要使用MMM,MHA这样的额外管理工具的一个重要原因。 这个问题在5.6的GTID出现后,就显得非常的简单。由于同一事务的GTID在所有节点上的值一致,那么根据Slave2当前停止点的GTID就能唯一定位到SLave1上的GTID。甚至由于MASTER_AUTO_POSITION功能的出现,我们都不需要知道GTID的具体值,直接使用CHANGE MASTER TO MASTER_HOST='xxx', MASTER_AUTO_POSITION命令就可以直接完成failover的工作。

    但这里还有一个问题,假如Slave 2 或者 Slave 3在Master出事故的时候它的复制进度比Slave 1还快呢?  也就是说Slave 2 的数据还领先于Slave 1 ,这时候即使使用了GTID 也无济于事了,因为Slave 2 即将应该执行的Position在Slave 1中根本就没有执行过呢,它又怎么能给你呢?   所以,在进行change master之前,还得有一步差异化数据的抵消,即将所有slave中选出那个在Master出问题后复制进度最快的,将它的binlog日志作用到其他Slave上,使其他Slave的复制进度和他保持一致。 然后就可以随便推荐一台作为新的主库了。  MHA 就是这样做的。

    所以,一般这种复制形式就可以应用MHA等开源解决方案去保证数据库的高可用。

    基于Galera协议的高可用方案

    最近,Galera又火了一把,不过可惜的是不是因为他自己。2016年12.12日,MySQL官方发布了Group Replication(GR),提供了MySQL集群化解决方案。 在此之前,应用最多最广最受欢迎的应该就是Gelera了。于是人们开始拿两者做各种对比了。甚至网上有很多人说Gelara将死。 不过作为支撑N载集群化解决方案的Gelera本身的价值是不可估量的。国内很多大公司至今都依赖于它实现MySQL的集群化。

    Galera是Codership提供的多主数据同步复制机制,可以实现多个节点间的数据同步复制以及读写,并且可保障数据库的服务高可用及数据一致性。
    基于Galera的高可用方案主要有MariaDB Galera Cluster和Percona XtraDB Cluster(简称PXC),目前PXC用的会比较多一些。

    Gelera的实现架构示意图见下(图片摘自网络):

    yy1

    如上,在底层采用wsrep接口实现数据在多节点间的同步复制。

    yy

    如上,客户端请求update更新数据,galera集群中一台服务器收到请求后,本地进程反馈OK,client则提交需要commit更改的数据,server收到提交事务后,所有对数据的更改都会被write-set收集起来,并将write-set的记录内容发送给其他节点。write-set会在每个节点执行之前都会进行认证certification,若认证通过,则节点应用write-set记录更改数据;若认证失败,该节点将discard丢弃write-set,其他节点则回滚rollback该事务。

    作为Gelera 中的佼佼者,PXC是最受欢迎的,他都有哪些特性呢?

    PXC的优点

    • 服务高可用;
    • 数据同步复制(并发复制),几乎无延迟;
    • 多个可同时读写节点,可实现写扩展,不过最好事先进行分库分表,让各个节点分别写不同的表或者库,避免让galera解决数据冲突;
    • 新节点可以自动部署,部署操作简单;
    • 数据严格一致性,尤其适合电商类应用;
    • 完全兼容MySQL;

    虽然有这么多好处,但也有些局限性:

    • 只支持InnoDB引擎;
    • 所有表都要有主键;
    • 不支持LOCK TABLE等显式锁操作;
    • 锁冲突、死锁问题相对更多;
    • 不支持XA;
    • 集群吞吐量/性能取决于短板;
    • 新加入节点采用SST时代价高;
    • 存在写扩大问题;
    • 如果并发事务量很大的话,建议采用InfiniBand网络,降低网络延迟;

    事实上,采用PXC的主要目的是解决数据的一致性问题,高可用是顺带实现的。因为PXC存在写扩大以及短板效应,并发效率会有较大损失,类似semi sync replication机制。

    说实话,Gelera我也没有用过,仅仅停留在理论层而已,并没有时间经验。所以也没有什么深入的讲解,日后若有幸用到,可以试试。

     

    参考:

    MySQL高可用方案选型参考

     

     

  • KeepAlived基本概念

    背景

    Keepalived技术经常被用来做高可用方案。 是运维人员不可或缺的工具,这里从基础学习他的原理和使用。

    Keepalived介绍

    Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障,类似的工具还有heartbeat、corosync、pacemaker。但是它一般不会单独出现,而是与其它负载均衡技术(如lvs、haproxy、nginx)一起工作来达到集群的高可用。

    那么keepalived和Heartbeat、Corosync、有什么区别,他们各自又有什么优劣呢?

    其实,Heartbeat、Corosync是属于同一类型,Keepalived与Heartbeat、Corosync,根本不是同一类型的。Heartbeat或Corosync是基于主机或网络服务的高可用方式;简单的说就是,Keepalived的目的是模拟路由器的高可用,Heartbeat或Corosync的目的是实现Service的高可用。Heartbeat或Corosync是实现服务的高可用,常见的组合有:

    Heartbeat v3(Corosync)+Pacemaker+NFS+Httpd 实现Web服务器的高可用、Heartbeat v3(Corosync)+Pacemaker+NFS+MySQL 实现MySQL服务器的高可用。

    所以一般Keepalived是实现前端高可用,常用的前端高可用的组合有,就是我们常见的LVS+Keepalived、Nginx+Keepalived、HAproxy+Keepalived。

    而总结一下,Keepalived中实现轻量级的高可用,一般用于前端高可用,且不需要共享存储,一般常用于两个节点的高可用。而Heartbeat(或Corosync)一般用于服务的高可用,且需要共享存储,一般用于多节点的高可用。

    Keepalived是什么

    Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节点的状态。它根据TCP/IP参考模型的第三、第四、第七层交换机制检测每个服务节点的状态,如果某个服务节点出现异常,或工作出现故障,Keepalived将检测到,并将出现故障的节点从集群系统中剔除,而在故障节点恢复正常后,Keepalived又可以自动将此服务节点重新加入集群系统。这些工作全部自动完成,不需要人工干涉,需要人工完成的只是修复出现故障的节点。

    三层(网络层)故障检测方式:在网络层主要有四个协议:互联网协议IP、互联网控制报文协议ICMP、地址转换协议ARP,以及反向地址转换协议RARP。Keepalived在网络层采用的最常用的工作方式是通过ICMP协议向集群中的每个节点发送一个ICMP包(类似于Ping实现的功能),如果某个节点没有返回响应数据包,那么认为此节点发生了故障,Keepalived将报告此节点失效,并从服务器集群中剔除故障节点。

    四层(传输层)故障检测方式:在传输层主要有两个协议,TCP以及UDP,而Keepalived在传输层就是利用TCP协议的端口链接和扫描技术来判断集群节点是否正常。比如,对于常见的web服务默认的80端口、SSH服务默认的22端口等,Keepalived一旦在传输层探测到这些端口没有响应数据的返回,就认为这些端口发生异常,然后强制将此端口对应的节点从服务器集群中移除。

    七层(应用层)故障检测方式:在应用层,可以运行FTP、TELNET、SMTP、DNS等各种不同类型的高层协议,Keepalived的运行方式也更加全面化和复杂化,用户可以通过自定义Keepalived的工作方式。例如,用户可以通过自己编写程序来运行Keepalived,而Keepalived将根据用户的设定检测各种程序或服务是否正常,如果Keepalived的检测结果与用户设定不一样时,Keepalived将把对应的服务从服务器中移除。

    Keepalived原理:

    1 . VRRP协议

    Keepalived 后来加入了VRRP功能,目的是解决静态路由出现的单点故障问题VRRP全称 Virtual Router Redundancy Protocol,即 虚拟路由冗余协议。可以认为它是实现路由器高可用的容错协议,即将N台提供相同功能的路由器(其实就是目标集群)组成一个路由器组(Router Group),这个组里面有一个master和多个backup,但在外界看来就像一台一样,构成虚拟路由器,拥有一个虚拟IP(vip,也就是路由器所在局域网内其他机器的默认路由),占有这个IP的master实际负责ARP相应和转发IP数据包,组中的其它路由器作为备份的角色处于待命状态。master会发组播消息,当backup在超时时间内收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master,保证路由器的高可用

    yy

    如上图,对于来自互联网的请求来说,它只面向VIP,而正常情况下,这个VIP是配置在作用为Master和Slave的lvs主机上的。如果Master正常,那么所有的请求会走线路1. 而如果一旦Master出现了故障,那么Keepalived会自动将访问都切至线路2由slave提供服务。 这样就实现了高可用

    那么Keepalived又是怎么发现Master出问题了,然后让backup顶上去的呢?

    —— 在VRRP协议实现里,虚拟路由器使用 00-00-5E-00-01-XX 作为虚拟MAC地址,XX就是唯一的 VRID (Virtual Router IDentifier),这个地址同一时间只有一个物理路由器占用(所以对外永远是一个IP)。在虚拟路由器里面的物理路由器组的Master通过多播IP地址 224.0.0.18 来定时发送通告消息。每个Router都有一个 1-255 之间的优先级别,级别最高的(highest priority)将成为主控(master)路由器。通过降低master的优先权可以让处于backup状态的路由器抢占(pro-empt)主路由器的状态,两个backup优先级相同的IP地址较大者为master,接管虚拟IP。

    在一个虚拟路由器中,只有作为MASTER的VRRP路由器会一直发送VRRP通告信息(VRRPAdvertisement message),BACKUP不会抢占MASTER,除非它的优先级(priority)更高。当MASTER不可用时(BACKUP收不到通告信息), 多台BACKUP中优先级最高的这台会被抢占为MASTER。这种抢占是非常快速的(<1s),以保证服务的连续性。由于安全性考虑,VRRP包使用了加密协议进行加密。

    注: VRRP协议的主要存在意义是为了保证高可用,上面的三层、四层、五层检测模式的主要意义是对服务器集群状态的监控和检测,不要搞混了。

    Keepalived 安装配置

    keepalived可以认为是VRRP协议在Linux上的实现,主要有三个模块,分别是core、check和vrrp。

    • core模块为keepalived的核心,负责主进程的启动、维护及全局配置文件加载和解析。
    • check负责健康检查,包括常见的各种检查方式。
    • vrrp模块是来实现VRRP协议的。
    一. 下载安装:

    $ wget http://www.keepalived.org/software/keepalived-1.2.2.tar

    $ tar -zxvf keepalived-1.2.2.tar.gz 

    $ cd keepalived-1.2.2 

    $ ./configure

    $ make && make install

    $ chkconfig --add keepalived

    $ chkconfig --level 35 keepalived on

    yy

    也可以选择yum直接安装。

     

    二. 配置

    Keepalived安装完毕后,配置文件默认放在/etc/keepalived/keepalived.conf,Keepalived的所有配置均在这个配置文件中完成。 由于Keepalived.conf 文件中可配置的选项比较多,这里根据配置文件所实现的功能,将Keepalived配置分为三类,分别是全局配置(Global Cnfiguration),VRRPD配置和LVS配置。

    1. 全局配置 

    全局配置主要以“global_defs作为标识”,在“global_defs区域内的都是全局配置选项”。主要分为两部分:

    第一部分:告警邮件相关设置,如下:

    yy

    第二部分: 静态地址和路由配置,基本原理和/etc/sysconfig/network-scripts下的配置一样,一般不建议在这里配置。

    2. VRRPD配置

    VRRPD功能是所有配置的核心,主要用来实现Keepalived的高可用功能。VRRPD配置又可分为三个类:

    • VRRP同步组(synchroization group)
    • VRRP实例(VRRP Instance)
    • VRRP脚本

    —— VRRP同步组配置:

    ——VRRP实例配置:

    注: 从上面的配置看,这台机器的VI_1是被默认设置为Master的router,也就是说它相当于我们上图中的线路1中的LVS,那么默认情况下,我们在这台服务器上执行ip a命令应该是可以看到VIP 10.23.34.45 存在于这台机器的。

    那么对应的另一台机器作为Backup他的这个设置我想我们也应该可以想的来:

    注:默认情况下这台备份机器上面是不存在虚拟IP 10.23.34.45 的。只有Master出问题了,他才会接过这个IP的大旗,扛起承担流量的重任。

    —— VRRP 脚本配置:

    3. LVS相关配置

    这段配置仅当此node节点被配置为LVS时才需要添加,注意这里LVS配置并不是指真的安装LVS然后用ipvsadm来配置他,而是用keepalived的配置文件来代替ipvsadm来配置LVS,这样会方便很多,一个配置文件搞定这些,维护方便,配置方便。

    这里LVS配置主要分为两部分:

    • 虚拟主机组配置
    • 虚拟主机配置

    虚拟主机组和VRRP同步组一样都是为了将具有相同特性的虚拟主机划分为一组统一配置。这里不再详赘。

    ——虚拟主机配置:

    配置完以后在Slave上修改对应的State和Priority优先级即可,然后在Master上和Slave上同时启动keepalived进程,我们就可以在Master上和Slave上分别执行 ipvsadm -ln 查看虚拟主机的状态:

    在Master机器上执行 ipvsadm -ln:

    在Slave机器上执行  ipvsadm -ln:

    如上,看到Master和Slave上面配置是一样的,只不过slave上没有活跃的链接,也就是说请求都走了Master,因为VIP在Master上,Slave上并没有。

    到此为止,我们的Keepalived的安装配置就讲完了,我想大概心里已经有个概念了。 如果这时候,有一个需求让我们分别在两台机器A、B上搭建两台互为主备的Nginx服务器。具体该怎么做呢?   这个留给自己心里去盘算吧。

    Keepalived 实现Nginx的高可用

    默认情况下,keepalived能够实现当我们的主web宕机或者网络出现故障时进行切换,但如果仅是nginx进程出现故障,我们就需要写一点实时监控nginx进程状态的脚本,即如果进程出现问题我们就进行切换。

    1. nginx监控脚本

    该脚本检测ngnix的运行状态,并在nginx进程不存在时尝试重新启动ngnix,如果启动失败则停止keepalived,准备让其它机器接管。

    也可以根据自己的业务需求,总结出在什么情形下关闭keepalived,如 curl 主页连续2个3s没有响应则切换:

    2. Keepalived配置

    在其它备机BACKUP上,只需要改变 state MASTER -> state BACKUPpriority 101 -> priority 100mcast_src_ip换成本机的IP即可。

    注: 如果发生Master的切换,会有log记录在/var/log/message里面。

     

    参考:

    http://seanlook.com/2015/05/18/nginx-keepalived-ha/

    http://lansgg.blog.51cto.com/5675165/1179636