nginx

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > nginx > Nginx高可用

Nginx高可用(主从、主主模式)的项目实践

作者:为什么要做囚徒

本文介绍了Nginx高可用性的两种主要解决方案,主从架构和主主架构,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. 引言

在单机部署的Nginx环境中,一旦Nginx服务器出现故障,整个系统服务将受到影响,导致服务中断。为了解决这个问题,我们需要引入Nginx的高可用性(HA)架构。本文将详细探讨Nginx高可用性的两种主要解决方案:主从架构和主主架构。

2. 高可用架构设计

KeepAlived是一款基于VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)的开源软件,主要用于解决网络服务的单点故障问题,特别是在集群环境中提供VIP(Virtual IP,虚拟IP地址)共享和故障切换功能

即前端使用两台服务器,一台主服务器和一台热备服务器,正常情况下,主服务器绑定一个虚拟IP,提供负载均衡服务,热备服务器处于空闲状态;当主服务器发生故障时,热备服务器接管主服务器的虚拟IP,提供负载均衡服务;但是热备服务器在主机器不出现故障的时候,永远处于浪费状态,对于服务器不多的网站,该方案不经济实惠。

即前端使用两台负载均衡服务器,互为主备,且都处于活动状态,同时各自绑定一个虚拟IP,提供负载均衡服务;当其中一台发生故障时,另一台接管发生故障服务器的虚拟IP(这时由非故障机器一台负担所有的请求)

3. 基础环境准备

本片采用 nginx容器部署+keepalived宿主机部署、nginx容器部署+keepalived容器部署两种方案

4. Nginx安装

mkdir -p /home/xmc/nginx1/conf.d /home/xmc/nginx1/html /home/xmc/nginx1/logs
docker run -d --name=nginx1 nginx:latest
docker cp nginx1:/etc/nginx/nginx.conf /home/xmc/nginx1
docker cp nginx1:/etc/nginx/conf.d /home/xmc/nginx1
docker cp nginx1:/usr/share/nginx/html /home/xmc/nginx1
docker stop nginx1
docker rm nginx1
docker run \
-d -p 8081:80 \
--name nginx1 \
--privileged=true \
--restart=always \
-v /home/xmc/nginx1/nginx.conf:/etc/nginx/nginx.conf \
-v /home/xmc/nginx1/logs:/var/log/nginx \
-v /home/xmc/nginx1/conf.d:/etc/nginx/conf.d \
-v /home/xmc/nginx1/html:/usr/share/nginx/html \
nginx:latest

5. keepalived安装

keepalived安装包下载地址

# 进入一下目录,解压的时候会自动创建keepalived文件夹
cd /opt/module
tar -zxvf keepalived-2.2.7.tar.gz
./configure --prefix=/usr/local/keepalived make && make install
# 启动
systemctl start keepalived
# 状态
systemctl status keepalived
# 停止
systemctl stop keepalived
sudo systemctl enable keepalived
Keepalived默认所有的日志都是写入到/var/log/message,
你可以使用命令 tail -f /var/log/messages|grep Keepalived 进行查看

4. 配置主备模式

global_defs {
    notification_email {
        acassen@firewall.loc
        failover@firewall.loc
        sysadmin@firewall.loc
    }
    notification_email_from Alexandre.Cassen@firewall.loc
    smtp_server 192.168.10.200
    smtp_connect_timeout 30
    router_id LVS_DEVEL
}
vrrp_script chk_http_port {
    script "/etc/keepalived/nginx_check.sh" # 脚本路径
    interval 2 #(检测脚本执行的间隔)
    weight 2
}
vrrp_instance VI_1 {
    state MASTER    # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
    priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.50 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
     track_script {  # 调用上边的脚本
        chk_http_port
     }
}
global_defs {
    notification_email {
        acassen@firewall.loc
        failover@firewall.loc
        sysadmin@firewall.loc
    }
    notification_email_from Alexandre.Cassen@firewall.loc
    smtp_server 192.168.10.200
    smtp_connect_timeout 30
    router_id LVS_DEVEL
}
vrrp_script chk_http_port {
    script "/etc/keepalived/nginx_check.sh" # 脚本路径
    interval 2 #(检测脚本执行的间隔)
    weight 2
}
vrrp_instance VI_1 {
    state BACKUP    # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
    priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.50 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
     track_script {  # 调用上边的脚本
        chk_http_port
     }
}
vim /etc/keepalived/nginx_check.sh
#!/bin/bash

# 容器名称
container_name="nginx1"

# 检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)

# 如果容器不存在
if [ -z "$container_status" ]; then
    echo "容器 $container_name 不存在! 关闭 keepalived..."
    systemctl stop keepalived
    echo "Keepalived 已关闭。"
    exit 1
fi

echo "容器 $container_name 当前状态为: $container_status"

# 如果容器未运行,尝试重新启动
if [ "$container_status" != "running" ]; then
    echo "容器 $container_name 未运行,尝试重新启动..."
    docker start "$container_name"
    sleep 5  # 等待 5 秒,确保容器有足够时间启动

    # 再次检查容器状态
    container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)

    if [ "$container_status" != "running" ]; then
        echo "容器 $container_name 重启后仍未运行,将关闭 Keepalived。"
        systemctl stop keepalived
        echo "Keepalived 已关闭。"
        exit 1
    else
        echo "容器 $container_name 已成功启动。"
    fi
else
    echo "容器 $container_name 已处于运行状态,无需重启。"
fi

赋予执行权限

chmod +x /etc/keepalived/nginx_check.sh 

5. 配置主主(双主)模式

global_defs {
    notification_email {
        acassen@firewall.loc
        failover@firewall.loc
        sysadmin@firewall.loc
    }
    notification_email_from Alexandre.Cassen@firewall.loc
    smtp_server 192.168.10.200
    smtp_connect_timeout 30
    router_id LVS_DEVEL
}
vrrp_script chk_http_port {
    script "/etc/keepalived/nginx_check.sh" # 脚本路径
    interval 2 #(检测脚本执行的间隔)
    weight 2
}
vrrp_instance VI_1 {
    state MASTER    # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
    priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.50 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
    track_script {  # 调用上边的脚本
        chk_http_port
    }
}
vrrp_instance VI_2 {
    state BACKUP   # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 52 # 虚拟路由标识,主、备服务器ID必须一样
    priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.51 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
    track_script {  # 调用上边的脚本
        chk_http_port
    }
}
global_defs {
    notification_email {
        acassen@firewall.loc
        failover@firewall.loc
        sysadmin@firewall.loc
    }
    notification_email_from Alexandre.Cassen@firewall.loc
    smtp_server 192.168.10.200
    smtp_connect_timeout 30
    router_id LVS_DEVEL
}
vrrp_script chk_http_port {
    script "/etc/keepalived/nginx_check.sh" # 脚本路径
    interval 2 #(检测脚本执行的间隔)
    weight 2
}
vrrp_instance VI_1 {
    state BACKUP    # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
    priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.50 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
     track_script {  # 调用上边的脚本
        chk_http_port
     }
}

vrrp_instance VI_2 {
    state MASTER    # 主机使用: MASTER  备机使用: BACKUP
    interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
    virtual_router_id 52 # 虚拟路由标识,主、备服务器ID必须一样
    priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
    advert_int 1 # 主备之间同步检查的时间间隔单位秒
    authentication { # 验证类型和密码
        auth_type PASS # 验证类型有两种 PASS和HA
        auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
    }
    virtual_ipaddress {
        192.168.10.51 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
    }
     track_script {  # 调用上边的脚本
        chk_http_port
     }
}

检测脚本(主机和备机一致):

#!/bin/bash

# 容器名称
container_name="nginx1"

# 检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)

# 如果容器不存在
if [ -z "$container_status" ]; then
    echo "容器 $container_name 不存在! 关闭 keepalived..."
    systemctl stop keepalived
    echo "Keepalived 已关闭。"
    exit 1
fi

echo "容器 $container_name 当前状态为: $container_status"

# 如果容器未运行,尝试重新启动
if [ "$container_status" != "running" ]; then
    echo "容器 $container_name 未运行,尝试重新启动..."
    docker start "$container_name"
    sleep 5  # 等待 5 秒,确保容器有足够时间启动

    # 再次检查容器状态
    container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)

    if [ "$container_status" != "running" ]; then
        echo "容器 $container_name 重启后仍未运行,将关闭 Keepalived。"
        systemctl stop keepalived
        echo "Keepalived 已关闭。"
        exit 1
    else
        echo "容器 $container_name 已成功启动。"
    fi
else
    echo "容器 $container_name 已处于运行状态,无需重启。"
fi

6. 注意事项

没有出现虚拟ip,如果出现主备都抢用了虚拟ip的情况,那很可能是firewall的原因,keepalived 是基于vrrp做到虚拟ip漂移的,这里不开启的话,主备均会认为对方挂掉了,会造成主备都能获取到虚拟ip(vip)

防火墙开启vrrp

firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent

重新载入配置

firewall-cmd –reload

到此这篇关于Nginx高可用(主从、主主模式)的项目实践的文章就介绍到这了,更多相关Nginx高可用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:
阅读全文