美文网首页运维
keepalived+LVS使用两台机器实现mysql双主负载均

keepalived+LVS使用两台机器实现mysql双主负载均

作者: 1659b264cc28 | 来源:发表于2018-11-06 07:51 被阅读0次

    前段时间看了《大型网站系统与Java中间件实践》这本书,了解到大型网站构架的演进,大致上来说也是单机走向分布式集群来分摊访问压力。书中提到了很多常见的场景,比如数据库方面,当压力变大时可以实现读写分离、分库分表等,总体上是给出了通用解决方案和思路。

    分享下《大型网站系统与Java中间件实践》PDF,网上找不到带目录的,简单的用Adobe自己添加了目录(百度云地址

    网上搜mysql集群高可用方案结果是一大堆,也没有说哪个方案是相对比较好。看了很多文章介绍初步了解到下面的几种情况:

    1. 数据库一主多从实现读写分离
      mysql-proxy:原理上应该是通过lua脚本解析sql,写主库读从库,还能配置负载均衡
      mycat:也是统一拦截sql,还支持分表分库、读写分离,负载均衡等,好像比较强大。
    2. 负载均衡,把请求分发以分摊服务器压力
      LVS:LVS(Linux Virtual Server)是一个虚拟的服务器集群系统,可以在UNIX/LINUX平台下实现负载均衡集群功能, LVS内核模块IPVS从2.4.24以后已经成为Linux官方标准内核的一部分。LVS相关参考这篇文章高并发场景 LVS 安装及高可用实现
      haproxynginx:也是可以用来做负载均衡
    3. 高可用则需要定时检测节点,出现故障时自动转移
      keepalived:具体参考这篇写的比较好的文章keepalived实现服务高可用keepalived一开始就为LVS设计的,和LVS搭配比较简单。keepalived使用VRRP协议,限制的地方是使用arp的广播模式,只有同一网段才能使用,也就是局域网环境,然后还有脑裂的问题
      《从Paxos到Zookeeper 分布式一致性原理与实践》中对脑裂的描述

    MHA:比较成熟的高可用集群方案

    看了一下好像都有点复杂,决定先简单的实践下使用keepalived+LVS实现mysql高可用。

    draw.io
    上图是我们需要实现的流程构架,只使用两台机器,将LVS与RealServer合并在同一台机器上。而且我们还是使用LVS的DR模式。先介绍下LVS的DR模式:
    1. 假设我们客户端(client:192.168.1.101)请求我们负载均衡服务器上的VIP地址(192.168.1.200),则发送的请求中源IP为(192.168.1.101),目标IP为(192.168.1.200
    2. 路由器通过arp解析到负载均衡服务器mac地址,则转发请求到负载均衡服务器上。
    3. DR模式下负载均衡服务器不修改该请求的目标IP,即目标IP还是(192.168.1.200),而是修改请求的mac地址再转发到RealServer(真正调用的服务器),RealServer不经过负载均衡服务器而直接返回响应信息给client。
      DR模式参考网上的图
      LVSDR模式需要注意的点:
    • 默认情况下RealServer接收到目标IP是192.168.1.200的请求跟自己的IP地址不一致,则会直接抛弃这个请求导致无法访问。需要在RealServer的网卡lo接口上添加我们的VIP(192.168.1.200)来接收请求。lo是本地回环接口,当RealServer接收到目标IP是192.168.1.200的请求时,被当成本地程序服务处理,而不是直接丢弃。
    • 这个就是我们构建LVSDR模式时最普遍使用到的realserver脚本的其中一个作用

    按照网上很多的教程都是至少需要4台机器,其中keepalived+LVS部署到两台机作为单纯的负载均衡服务器,而keepalived则保证LVS负载均衡服务器的高可用,同时还支持realserver的健康检测,当其中一个realserver节点服务挂了,就将其排除出去。
    个人觉得两台机作为单纯负载均衡机会有点浪费,想直接将LVS和RealServer部署在同一台机器上,但是实际测试过程中确实是出现了请求的死循环,最后通过iptablesMARK标记请求的方式不触发LVS的slave机的负载均衡解决这个问题。

    一:首先本地使用虚拟机搭建实验环境

    因为keepalived使用要求是同一网段(局域网),这里使用了VirtualBox搭建CentOS-7环境。
    主要遇到下面几点问题:

    1. 网卡设置选择桥接模式

    目标是实现主机与虚拟机相互能ping通,虚拟机能上网,这里连接方式选择桥接模式并且网卡选择当前主机正在使用的网卡。

    桥接模式:像是局域网中的一台独立的主机,可以访问与局域网内任何一台机器相互访问
    NAT模式:可以通过主机实现上网,但不能访问主机。也可以添加多一个网卡2选择Host-only来实现虚拟机访问主机。

    桥接模式
    2. 虚拟机固定IP

    修改虚拟机为固定IP,目的是实验时IP地址不会变化而且容易记。

    • 主机本地cmd->ipconfig得到ipv4地址以及子网掩码和网关配置:
      获取主机ip
    • ifconfig -a查看除了lo回环接口的外的接口名称,并执行ifup 网卡接口名称启用网卡,可以看到这里名称不是一般默认的eth0
      查看网卡接口名称
    • 修改为固定ip:vi /etc/systemconfig/network-scripts/ifcfg-enp0s3
    BOOTPROTO=static
    IPADDR=192.168.1.110
    NETMASK=255.255.255.0
    GATEWAY=192.168.1.1
    DNS1=192.168.1.1
    DNS2=8.8.8.8
    ONBOOT=yes
    
    3. 关闭防火墙和SELinux,减少复杂度或额外干扰
    #关闭防火墙
    systemctl stop firewalld
    #开机禁用
    systemctl disable firewalld
    #关闭SELinux-》设置SELINUX=disabled并重启
    vi /etc/selinux/config
    

    然后我们创建了两台虚拟机:
    lvs-master:192.168.1.110
    lvs-slave:192.168.1.111

    二:安装keepalived实现服务的高可用以及配置LVS负载均衡
    1.安装keepalived
    yum -y install keepalived
    
    2.修改lvs-master配置文件:vi /etc/keepalived/keepalived.conf
    ! Configuration File for keepalived
    global_defs {
       router_id LVS_1  #lvs id,在一个网络内唯一
    }
    vrrp_instance VI_1 {
        state MASTER    #角色:MASTER主,BACKUP备
        interface enp0s3    #网卡接口
        virtual_router_id 51    #虚拟路由编号,主备一致
        priority 100    #定义优先级,数字越大优先级越高,主优先级大于备
        advert_int 1    #检查间隔,默认1s
        authentication {
            auth_type PASS
            auth_pass 1111
        }
        virtual_ipaddress {
            192.168.1.200   #虚拟IP(VIP)地址
        }
    }
    #定义LVS负载均衡的VIP port
    virtual_server 192.168.1.200 80 {
        delay_loop 6    #设置健康检查时间,单位秒
        lb_algo wrr     #设置负载调度算法
        lb_kind DR      #设置LVS实现负载的机制(NAT/TUN/DR)
        nat_mask 255.255.255.0
        persistence_timeout 0   #会话保持时间
        protocol TCP
        #定义real server的IP地址
        real_server 192.168.1.110 80 {
            weight 3    #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
            connect_port 80
            }
        }
        #定义real server的IP地址
        real_server 192.168.1.111 80 {
            weight 3    #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
            connect_port 80
            }
        }
    }
    #定义LVS的VIP port
    virtual_server 192.168.1.200 3306 {
        delay_loop 6        #设置健康检查时间,单位秒
        lb_algo wrr         #设置负载调度算法
        lb_kind DR          #设置LVS实现负载的机制(NAT/TUN/DR)
        nat_mask 255.255.255.0
        persistence_timeout 0       #会话保持时间
        protocol TCP
        #定义real server的IP地址
        real_server 192.168.1.110 3306 {
            weight 3        #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
                connect_port 3306
            }
        }
        #定义real server的IP地址
        real_server 192.168.1.111 3306 {
            weight 3        #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
                connect_port 3306
            }
        }
    }
    

    启动keepalived:service keepalived start
    关闭命令:service keepalived stop

    配置说明:
    ①这里两台机都需要安装keepalived作为Master主负载均衡服务器和Slave备机(salve机上的keepalived.conf配置只需要修改:state为BACKUP,priority 99 优先级低于Master机,其他配置跟Master机一致就可以了)
    ②interface 这里可以配置机器上的主网卡接口(执行ifconfig命令的第一个例如eth0)
    ③virtual_ipaddress 配置VIP,可配置多个
    ④virtual_server 配置LVS负载均衡,这里我配置多一个80端口先用来做测试
    ⑤lb_algo wrr是加权负载均衡,rr模式就是轮询负载均衡

    3.配置realserver脚本文件:

    ①进入/etc/init.d/目录cd /etc/init.d/
    ②创建并编辑脚本vi realserver

    SNS_VIP=192.168.1.200 #自定义VIP
    /etc/rc.d/init.d/functions
    case "$1" in
    start)
           ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP
           /sbin/route add -host $SNS_VIP dev lo:0
           echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
           echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
           echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
           echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
           sysctl -p >/dev/null 2>&1
           echo "RealServer Start OK"
           ;;
    stop)
           ifconfig lo:0 down
           route del $SNS_VIP >/dev/null 2>&1
           echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
           echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
           echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
           echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
           echo "RealServer Stoped"
           ;;
    *)
           echo "Usage: $0 {start|stop}"
           exit 1
    esac
    exit 0
    

    ③给与可执行权限chmod 755 realserver
    ④开启配置命令:service realserver start关闭service realserver stop

    1.之前有说到LVSDR模式中RealServer需要在lo本地回环接口配置VIP才能处理请求,而arp_ignorearp_announce作用是抑制ARP响应,局域网环境路由器通过ARP确定负载均衡服务器mac地址,而RealServer不应该回应arp请求
    2.我们使用service keepalived start启动 keepalived会发现主负载均衡服务器已经在enp0s3接口上自动增加了VIP地址,所以当主机作为负载均衡服务器时不需要启动realserver脚本,只作为RealServer(lvs-slave)时才启用。

    keepalived自动根据interface临时添加配置
    三:测试LVS负载均衡和keepalived的故障自动漂移
    1. 安装LVS管理工具ipvsadm
    yum -y install ipvsadm
    
    2. 查看LVS负载均衡配置详情ipvsadm -ln
    ipvsadm
    3. 安装httpd测试LVS负载均衡
    #安装Apache
    yum -y install httpd
    #添加测试首页
    cd /var/www/html
    touch index.html
    #同理在lvs-slave机上安装并新增首页
    echo "hello world! lvs-Master" > index.html
    

    在本地使用浏览器访问VIP地址可以打开页面

    纯页面貌似缓存情况严重,负载均衡效果一般
    通过主动关闭Master机上的keepalived模拟故障,执行ip a可以观察到slave机接口上VIP的变化
    关闭lvs-Master的keepalived自动漂移到lvs-slave
    4. 测试过程中容易发现cpu占用率飙升,请求死循环的情况

    安装tcpdump用于监控请求

    yum -y install tcpdump
    

    两台机keepalived启动时执行tcpdump -n tcp port 80,然后访问多次192.168.1.200页面,会发现请求一直在滚动,这时不访问页面也不会停止。

    请求死循环
    这种情况就导致我很困惑,keepalived负载均衡备机也会对请求再次使用LVS的负载均衡规则,关掉keepalived的话能解决这个问题,但是不能保证高可用,又没有发现什么参数设置可以让keepalived处于slave角色时不使用LVS负载均衡。
    直到我百度到这篇文章在同一台服务器上部署LVS和WEB,以及很多copy这篇文章的博客文章,里边也是说会导致死循环,然后主要流程是使用到了iptables mark打标志,然后keepalived配置中virtual_server针对这个标签调度,但是这里用mac地址我感觉有点问题。
    说实话看不懂
    四:使用iptables mark使得slave备机负载均衡无效化
    1. 总体目标是:让处于slave状态的备机不启用LVS负载均衡功能,但是要保持keepalived启用状态维持高可用,当slave状态升级成Master时,又使得LVS负载均衡功能恢复可用,就是两种状态之间是可以切换的。
    2. 分析:Master和Slave之间最大差别应该就是第一个网络接口enp0s3(eth0)上会临时设置VIP(192.168.1.200),如果keepalived有能识别到这个接口上没有这个VIP就不启用LVS负载均衡功能的参数配置就可以做到这点,但是没有。在上面那篇文章中,可以看到virtual_server参数配置负载均衡还有使用mark标签的方式,我们可以通过设置标签,使得LVS只处理打了标签的请求。
    //查看标签
    iptables -t mangle -L -n
    //给目标IP为VIP的输入请求打标签
    iptables -t mangle -A PREROUTING -d 192.168.1.200 -p tcp --dport 80 -j MARK --set-mark 1
    iptables -t mangle -A PREROUTING -d 192.168.1.200 -p tcp --dport 3306 -j MARK --set-mark 2
    //清空所有的标签
    iptables -F -t mangle
    
    1. 总体思路:
      ①master负载均衡主机打标签,通过virtual_server配置mark标签的方式只处理目标IP为VIP的请求
      ②slave备机清除所有标签,因为virtual_server配置mark标签方式,所有的请求都不会满足要求,也就是所有请求都不会被负载均衡
      ③当主备切换时,只需要把标签给打上或者清除就可以了
    2. 相应的配置如下:
      直接添加整合到realserver脚本
    SNS_VIP=192.168.1.200
    /etc/rc.d/init.d/functions
    case "$1" in
    start)
           ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP
           /sbin/route add -host $SNS_VIP dev lo:0
           echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
           echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
           echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
           echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
           sysctl -p >/dev/null 2>&1
           #清空mark标记,使得LVS负载均衡对所有请求不生效
           iptables -F -t mangle
           echo "RealServer Start OK"
           ;;
    stop)
           ifconfig lo:0 down
           route del $SNS_VIP >/dev/null 2>&1
           echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
           echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
           echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
           echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
           #LVS负载均衡只对mark标记的请求有效
           iptables -F -t mangle
           iptables -t mangle -A PREROUTING -d $SNS_VIP -p tcp --dport 80 -j MARK --set-mark 1
           iptables -t mangle -A PREROUTING -d $SNS_VIP -p tcp --dport 3306 -j MARK --set-mark 2
           echo "RealServer Stoped"
           ;;
    *)
           echo "Usage: $0 {start|stop}"
           exit 1
    esac
    exit 0
    

    keepalived.conf主要是主备切换时调用realserver脚本以及使用mark:下master配置slave类似

    ! Configuration File for keepalived
    global_defs {
       router_id LVS_1  #lvs id,在一个网络内唯一
    }
    vrrp_instance VI_1 {
        state MASTER    #角色:MASTER主,BACKUP备
        interface enp0s3    #网卡接口
        virtual_router_id 51    #虚拟路由编号,主备一致
        priority 100    #定义优先级,数字越大优先级越高,主优先级大于备
        advert_int 1    #检查间隔,默认1s
        authentication {
            auth_type PASS
            auth_pass 1111
        }
        virtual_ipaddress {
            192.168.1.200   #虚拟IP(VIP)地址
        }
        notify_master "/etc/init.d/realserver stop" #切到主 后执行的脚本
        notify_backup "/etc/init.d/realserver start" #切到备 后执行的脚本
    }
    #定义LVS的VIP port
    virtual_server fwmark 1{
        delay_loop 6    #设置健康检查时间,单位秒
        lb_algo wrr     #设置负载调度算法
        lb_kind DR      #设置LVS实现负载的机制(NAT/TUN/DR)
        nat_mask 255.255.255.0
        persistence_timeout 0   #会话保持时间
        protocol TCP
        #定义real server的IP地址
        real_server 192.168.1.110 80 {
            weight 3    #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
            connect_port 80
            }
        }
        real_server 192.168.1.111 80 {
            weight 3    #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 3
                delay_before_retry 3
            connect_port 80
            }
        }
    }
    #定义LVS的VIP port
    virtual_server fwmark 2{
        delay_loop 6        #设置健康检查时间,单位秒
        lb_algo wrr         #设置负载调度算法
        lb_kind DR          #设置LVS实现负载的机制(NAT/TUN/DR)
        nat_mask 255.255.255.0
        persistence_timeout 0       #会话保持时间
        protocol TCP
        #定义real server的IP地址
        real_server 192.168.1.110 3306 {
            weight 3        #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 5
                delay_before_retry 6
                connect_port 3306
            }
        }
        real_server 192.168.1.111 3306 {
            weight 3        #配置节点权重,越大权重越高
            TCP_CHECK {
                connect_timeout 10
                nb_get_retry 5
                delay_before_retry 6
                connect_port 3306
            }
        }
    }
    

    经过上面的修改,重新测试httpd会发现负载均衡效果好了很多(这里可能需要等5s,因为Keep-Alive: timeout=5, max=100),而且不会出现请求死循环的问题了,理论上以及我自己测试过多次是没有问题,具体稳定性以及有没有其他未发现的bug暂时不知道。

    关于Keep-Alive特性from《图解HTTP》
    五:配置mysql双主(互为主从)

    上面我们搭建好了keepalived+LVS环境,也添加了3306mysql端口的配置,且验证过80端口是可行的,然后我们只需要添加mysql并配置主从就可以完成搭建。

    1.安装mysql

    直接到mysql官网获取下载方式https://dev.mysql.com/downloads/repo/yum/
    这里我使用的是centos7对应mysql80-community-release-el7-1.noarch.rpm

    noarch:没有限制,一般不包含二进制程序,常为shell script软件

    ①查询是否已安装旧版本:rpm -qa | grep mysql 或 yum list installed | grep mysql
    ②下载对应rpm安装包:wget dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
    ③安装rpm包:rpm -Uvh mysql80-community-release-el7-1.noarch.rpm 或者 yum install -y mysql80-community-release-el7-1.noarch.rpm
    ④安装完成后/etc/yum.repos.d/下会多出几个mysql的yum源的配置,安装mysql:yum install -y mysql-community-server
    ⑤启动mysql:service mysqld start
    ⑥获取临时密码grep 'temporary password' /var/log/mysqld.log
    ⑦登陆mysql:mysql -uroot -p 然后粘贴临时密码登陆
    ⑧修改密码:alter user 'root'@'localhost' identified by 'your-password';
    ⑨如果密码简单报错,则修改密码级别:set global validate_password.policy=0;
    ⑩navicat连接MYSQL报错:提示Host is not allowed to connect to this MySQL server
    原因:root帐号不允许从远程登陆,只能在localhost,修改localhost为%
    use mysql; 然后执行 update user set host = '%' where user = 'root';
    *报错:Client does not support authentication protocol requested by server:
    ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password BY '复杂点的密码';

    2.mysql配置主从

    mysql主从复制和二进制日志文件系统可以看这两篇文章:
    MySQL Replication 主从复制全方位解决方案
    MySQL的存储引擎与日志说明
    ①修改配置文件vi /etc/my.cnf,主要添加下面两个配置

    #server id 不能相同
    server-id = 1         
    # 跳过域名解析参数
    skip_name_resolve = 0
    

    ②创建一个用户给予复制权限用于主从复制

    #先创建一个用户repl
    create user 'repl'@'192.168.1.%' identified by 'your-password';
    #再授权
    grant replication slave on *.* to 'repl'@'192.168.1.%' with grant option;
    

    ③登陆mysql-master,show master status;获取FilePosition

    ishow master status获取binlog信息
    ④登陆mysql-slave,并执行change master,如果两个都是yes则为成功,如果还是connecting则需要检查网络是否连通,权限是否配置之类的。
    change master to master_host='192.168.1.110',master_user='repl',master_password='your-password',master_log_file='binlog.000014',master_log_pos=155;
    
    同步成功

    ⑤反向操作一次主从则配置双主(互为主从)成功
    ⑥为了增强一致性,配置半同步复制:
    MySQL复制默认是异步复制,半同步复制则是当master在将自己binlog发给slave的时候,要确保slave已经接受到了这个二进制日志以后,才会返回数据给客户端。

    //两个库都安装插件
    INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
    INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
    //查看是否成功
    show plugins;
    //两个库都执行两条语句开启semisync master和slave
    SET GLOBAL rpl_semi_sync_master_enabled = 1;
    SET GLOBAL rpl_semi_sync_slave_enabled = 1;
    //重启SLAVE IO线程
    STOP SLAVE IO_THREAD;
    START SLAVE IO_THREAD;
    //semi_sync_slave_status和semi_sync_master_status都是on则配置成功
    show status like '%semi%';
    

    直接在之前已经搭建好的keepalived+LVS的lvs-master和lvs-slave两台机器上安装mysql并通过mysql二进制文件复制的方式配置了双主模式就可以实现mysql双主负载均衡高可用

    相关文章

      网友评论

        本文标题:keepalived+LVS使用两台机器实现mysql双主负载均

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