java面试宝典 nginx和mysql的高可用

Keepalvied

Keepalived是一个基于VRRP协议来实现的服务高可用方案,可以利用其来避免IP单点故障。

原理:每一台机器都有一个Keepalived,每个Keepalived都有一个自己的 ip,那就是一共有n个ip,但是所有的Keepalived只有一个共同的虚拟ip,n个ip都去抢这个虚拟ip,前端发起的请求将会落在抢到虚拟ip的那台机器上。同理,每一台机器上都有nginx和keepalived,配置nginx主从模式,一般主的优先级大于从的,所以主是好的话,主能抢到虚拟ip,一般的请求会访问这个虚拟ip,进而请求就会落在主这台机器上;但是如果主宕了的话,keepalived会检测到主已经挂了,就让从去抢到这个虚拟ip,所以来访问的时候,请求就会落在从机器上,达到高可用效果。

keepalived脑裂: 当联系2个节点的“心跳线”断开时,本来为一整体就分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障,两个节点上就会争抢“共享资源”、争起“应用服务”,就会发生严重后果,两边“服务”都起不来了;或者两边“服务”都起来了,但同时读写“共享存储”,导致数据损坏(常见如数据库轮询着的联机日志出错)

nginx 高可用

每一台机器都有一个Keepalived和一个nginx,配置主从关系,多个nginx用同一个配置文件

MASTER 服务的keepalived.conf

global_defs {
 
}
 
vrrp_instance VI_1 {
    state MASTER    #指定A节点为主节点 备用节点上设置为 BACKUP 即可
    interface eth0    #绑定虚拟IP的网络接口
    virtual_router_id 51    #VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP组
    priority 100        #主节点的优先级(1-254之间),备用节点必须比主节点优先级低
    advert_int 1       #组播信息发送间隔,两个节点设置必须一样
    authentication {  #设置验证信息,两个节点设置必须一样
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {    #指定虚拟IP,两个节点设置必须一样
 
        192.168.116.120/32    #如果两个nignx的ip分别是192.168.116.128,.......129,则此处的虚拟ip跟他俩同一个网段即可
 
       # 192.168.200.16
       # 192.168.200.17
       # 192.168.200.18
    }
 
}

BACKUP服务的keepalived.conf


global_defs {
 
}
 
vrrp_instance VI_1 {
    state BACKUP    #指定A节点为主节点 备用节点上设置为 BACKUP 即可
    interface eth0    #绑定虚拟IP的网络接口
    virtual_router_id 51    #VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP组
    priority 99        #主节点的优先级(1-254之间),备用节点必须比主节点优先级低
    advert_int 1       #组播信息发送间隔,两个节点设置必须一样
    authentication {  #设置验证信息,两个节点设置必须一样
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {    #指定虚拟IP,两个节点设置必须一样
 
        192.168.116.120/32    #如果两个nignx的ip分别是192.168.116.128,.......129,则此处的虚拟ip跟他俩同一个网段即可
 
       # 192.168.200.16
       # 192.168.200.17
       # 192.168.200.18
    }
 
}

这样当master主服务器的keepalived停止服务,slave从服务器会自动接管对外服务;一旦主服务器的keepalived恢复,会重新接管对外服务。但这并不是我们需要的,我们需要的是当NginX停止服务的时候能够自动切换。

原理:
keepalived支持配置监控脚本,我们可以通过脚本监控NginX的状态,如果状态不正常则进行一系列的操作,最终仍不能恢复NginX则杀掉keepalived,使得从服务器能够接管服务。

思路:
由于keepalived并不跟nginx耦合,他俩完全不是一家人,但是keepalived提供了一个机制:让用户自定义一个shell脚本去检测进程状态并在进程下线后尝试重启进程

MASTER 服务的keepalived.conf

global_defs {
 
}
 
#检测脚本
vrrp_script chk_http_port {
    script "/usr/local/src/check_nginx_pid.sh" #心跳执行的脚本,检测nginx是否启动
    interval 2                          #(检测脚本执行的间隔,单位是秒)
    weight 2                            #权重
}
 
#vrrp 实例定义部分
vrrp_instance VI_1 {
    state MASTER            # 指定keepalived的角色,MASTER为主,BACKUP为备
    interface eth0   # 当前进行vrrp通讯的网络接口卡(当前centos的网卡) 用ifconfig查看你具体的网卡
    virtual_router_id 51 # 虚拟路由编号,主从要一致
    priority 100            # 优先级,数值越大,获取处理请求的优先级越高
    advert_int 1            # 检查间隔,默认为1s(vrrp组播周期秒数)
    #授权访问
    authentication {
        auth_type PASS #设置验证类型和密码,MASTER和BACKUP必须使用相同的密码才能正常通信
        auth_pass 1111
    }
    track_script {
        chk_http_port            #(调用检测脚本)
    }
    virtual_ipaddress {
        192.168.116.120/32    #如果两个nignx的ip分别是192.168.116.128,.......129,则此处的虚拟ip跟他俩同一个网段即可
 
       # 192.168.200.16
       # 192.168.200.17
       # 192.168.200.18
    }
}

BACKUP服务的keepalived.conf

global_defs {
 
}

#检测脚本
vrrp_script chk_http_port {
    script "/usr/local/src/check_nginx_pid.sh" #心跳执行的脚本,检测nginx是否启动
    interval 2                          #(检测脚本执行的间隔,单位是秒)
    weight 2                            #权重
}
 
vrrp_instance VI_1 {
    state BACKUP    #指定A节点为主节点 备用节点上设置为 BACKUP 即可
    interface eth0    #绑定虚拟IP的网络接口
    virtual_router_id 51    #VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP组
    priority 99        #主节点的优先级(1-254之间),备用节点必须比主节点优先级低
    advert_int 1       #组播信息发送间隔,两个节点设置必须一样
    authentication {  #设置验证信息,两个节点设置必须一样
        auth_type PASS
        auth_pass 1111
    }
    track_script {
        chk_http_port            #(调用检测脚本)
    }
    virtual_ipaddress {    #指定虚拟IP,两个节点设置必须一样
 
        192.168.116.120/32    #如果两个nignx的ip分别是192.168.116.128,.......129,则此处的虚拟ip跟他俩同一个网段即可
 
       # 192.168.200.16
       # 192.168.200.17
       # 192.168.200.18
    }
 
}

检测脚本 check_nginx_pid.sh

#!/bin/bash
#检测nginx是否启动了
A=`ps -C nginx --no-header |wc -l`        
if [ $A -eq 0 ];then    #如果nginx没有启动就启动nginx                        
      systemctl start nginx                #重启nginx
      if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then    #nginx重启失败,则停掉keepalived服务,进行VIP转移
              killall keepalived                    
      fi
fi

mysql 高可用

双节点主从 + keepalived

image.png

两个节点可以采用简单的一主一从模式,或者双主模式,并且放置于同一个VLAN中,在master节点发生故障后,利用keepalived的高可用机制实现快速切换到slave节点, 和上面nginx的高可用一样,也是通过编写shell 脚本去检测进程状态。

主从模式

MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行。主从的切换需要手动或者借助第三方工具,比如mycat实现自动主从切换。

主从复制的原理
(1)master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;
(2)slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件
(3)同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。

主从模式的另一个作用:读写分离

在开发工作中,有时候会遇见某个sql 语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。

双主模式

双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。这样做可以在一定程度上保证主库的高可用,在一台主库down掉之后,可以在极短的时间内配合keepalived切换到另一台主库上(尽可能减少主库宕机对业务造成的影响),减少了主从同步给线上主库带来的压力;

思路是:
1.两台mysql都可读写,互为主备,默认只使用一台(masterA)负责数据的写入,另一台(masterB)备用;
2.masterA是masterB的主库,masterB又是masterA的主库,它们互为主从;
3.两台主库之间做高可用,可以采用keepalived等方案(使用VIP对外提供服务);
4.所有提供服务的从服务器与masterB进行主从同步(双主多从);
5.建议采用高可用策略的时候,masterA或masterB均不因宕机恢复后而抢占VIP(非抢占模式);

不足的地方:
1.masterB可能会一直处于空闲状态(可以用它当从库,负责部分查询);
2.主库后面提供服务的从库要等masterB先同步完了数据后才能去masterB上去同步数据,这样可能会造成一定程度的同步延时;

有几个需要注意的地方:

  1. 采用keepalived作为高可用方案时,两个节点最好都设置成BACKUP模式,这样不会导致MASTER重新上线后抢夺BACKUP,避免因为意外情况下(比如脑裂)相互抢占导致往两个节点写入相同数据而引发冲突;
  2. 把两个节点的auto_increment_increment(自增起始值)和auto_increment_offset(自增步长)设成不同值。其目的是为了避免master节点意外宕机时,可能会有部分binlog未能及时复制到slave上被应用,从而会导致slave新写入数据的自增值和原先master上冲突了,因此一开始就使其错开;当然了,如果有合适的容错机制能解决主从自增ID冲突的话,也可以不这么做;
  3. keepalived的检测机制需要适当完善,不能仅仅只是检查mysqld进程是否存活,或者MySQL服务端口是否可通,还应该进一步做数据写入或者运算的探测,判断响应时间,如果超过设定的阈值,就可以启动切换机制;
  4. keepalived最终确定进行切换时,还需要判断slave的延迟程度。需要事先定好规则,以便决定在延迟情况下,采取直接切换或等待何种策略。直接切换可能因为复制延迟有些数据无法查询到而重复写入;
  5. keepalived自身都无法解决脑裂的问题,因此在进行服务异常判断时,可以调整判断脚本,通过对第三方节点补充检测来决定是否进行切换,可降低脑裂问题产生的风险。

更多demo请关注

springboot demo实战项目
java 脑洞
java 面试宝典
开源工具

公众号(五分钟技术)

五分钟了解前沿技术,大数据,微服务,区域链,提供java前沿技术干货,独立游戏制作技术分享

如果这篇文章对你有帮助请给个star


image.png

你可能感兴趣的:(java面试宝典 nginx和mysql的高可用)