Skip to content

MySQL ProxySQL + Keepalived 自动切换方案

架构设计

基本架构

  • ProxySQL 层:2个ProxySQL节点,实现读写分离和负载均衡
  • Keepalived 层:在ProxySQL节点上部署,提供VIP(虚拟IP)管理
  • MySQL 层:1主多从架构,使用MHA或其他方案实现主从切换

组件说明

  • ProxySQL:开源的MySQL代理,支持读写分离、连接池、查询路由等功能
  • Keepalived:基于VRRP协议的高可用解决方案,实现VIP的故障转移
  • MySQL:主从复制架构,提供数据存储服务

数据流

  1. 应用程序连接到VIP
  2. Keepalived将请求转发到活动的ProxySQL节点
  3. ProxySQL根据规则将请求路由到MySQL主库(写操作)或从库(读操作)
  4. 当活动ProxySQL节点故障时,Keepalived自动将VIP切换到备用ProxySQL节点

部署准备

系统要求

硬件要求

  • ProxySQL 节点

    • CPU:至少2核
    • 内存:至少4GB
    • 磁盘:至少50GB
    • 网络:与MySQL节点网络互通
  • MySQL 节点

    • 按照MySQL生产环境要求配置

软件要求

  • 操作系统:Linux(推荐CentOS 7+ 或 Ubuntu 16.04+)
  • ProxySQL:2.0.0+ 版本
  • Keepalived:1.3.5+ 版本
  • MySQL:5.7+ 版本
  • 依赖包
    • gcc
    • gcc-c++
    • make
    • openssl-devel
    • libnl3-devel
    • net-snmp-devel

网络规划

节点类型主机名IP地址VIP
ProxySQL 1proxysql1192.168.1.101192.168.1.100
ProxySQL 2proxysql2192.168.1.102192.168.1.100
MySQL 主库mysql-master192.168.1.201-
MySQL 从库1mysql-slave1192.168.1.202-
MySQL 从库2mysql-slave2192.168.1.203-

安装与配置

安装 ProxySQL

在所有 ProxySQL 节点上执行

bash
# 下载并安装 ProxySQL
wget https://github.com/sysown/proxysql/releases/download/v2.4.4/proxysql-2.4.4-1-centos7.x86_64.rpm
yum localinstall proxysql-2.4.4-1-centos7.x86_64.rpm

# 启动 ProxySQL
systemctl start proxysql
systemctl enable proxysql

# 检查状态
systemctl status proxysql

安装 Keepalived

在所有 ProxySQL 节点上执行

bash
# 安装 Keepalived
yum install keepalived -y

# 启动 Keepalived
systemctl start keepalived
systemctl enable keepalived

# 检查状态
systemctl status keepalived

配置 ProxySQL

连接到 ProxySQL 管理接口

bash
mysql -u admin -padmin -h 127.0.0.1 -P 6032

添加 MySQL 服务器

sql
-- 添加主库
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight, max_connections, max_replication_lag) VALUES (10, '192.168.1.201', 3306, 1, 1000, 10);

-- 添加从库
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight, max_connections, max_replication_lag) VALUES (20, '192.168.1.202', 3306, 1, 1000, 10);
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight, max_connections, max_replication_lag) VALUES (20, '192.168.1.203', 3306, 1, 1000, 10);

-- 加载配置
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

配置读写分离规则

sql
-- 添加查询规则
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply) VALUES (1, 1, '^SELECT.*FOR UPDATE', 10, 1);
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply) VALUES (2, 1, '^SELECT', 20, 1);

-- 加载配置
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

添加监控用户

sql
-- 添加监控用户
INSERT INTO mysql_users (username, password, default_hostgroup, active, max_connections) VALUES ('monitor', 'monitor_pass', 10, 1, 100);

-- 加载配置
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

配置监控脚本

创建监控脚本 /usr/local/bin/proxysql_monitor.sh

bash
#!/bin/bash

# 检查 ProxySQL 状态
PROXYSQL_STATUS=$(systemctl status proxysql | grep Active | grep running | wc -l)

if [ $PROXYSQL_STATUS -eq 0 ]; then
    # ProxySQL 未运行,停止 Keepalived
    systemctl stop keepalived
    exit 1
else
    # ProxySQL 运行正常
    exit 0
fi

设置脚本权限:

bash
chmod +x /usr/local/bin/proxysql_monitor.sh

配置 Keepalived

在 ProxySQL 1 节点上配置

编辑 /etc/keepalived/keepalived.conf

txt
! Configuration File for keepalived

global_defs {
    notification_email {
        admin@example.com
    }
    notification_email_from keepalived@example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id LVS_DEVEL
    vrrp_skip_check_adv_addr
    vrrp_strict
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

vrrp_script check_proxysql {
    script "/usr/local/bin/proxysql_monitor.sh"
    interval 2
    weight -5
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100/24 dev eth0 label eth0:0
    }
    track_script {
        check_proxysql
    }
    notify_master "/usr/local/bin/proxysql_notify.sh master"
    notify_backup "/usr/local/bin/proxysql_notify.sh backup"
    notify_fault "/usr/local/bin/proxysql_notify.sh fault"
}

在 ProxySQL 2 节点上配置

编辑 /etc/keepalived/keepalived.conf

txt
! Configuration File for keepalived

global_defs {
    notification_email {
        admin@example.com
    }
    notification_email_from keepalived@example.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id LVS_DEVEL
    vrrp_skip_check_adv_addr
    vrrp_strict
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

vrrp_script check_proxysql {
    script "/usr/local/bin/proxysql_monitor.sh"
    interval 2
    weight -5
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100/24 dev eth0 label eth0:0
    }
    track_script {
        check_proxysql
    }
    notify_master "/usr/local/bin/proxysql_notify.sh master"
    notify_backup "/usr/local/bin/proxysql_notify.sh backup"
    notify_fault "/usr/local/bin/proxysql_notify.sh fault"
}

创建通知脚本

创建通知脚本 /usr/local/bin/proxysql_notify.sh

bash
#!/bin/bash

STATE=$1
LOG_FILE="/var/log/keepalived_notify.log"

echo "[$(date +'%Y-%m-%d %H:%M:%S')] State changed to $STATE" >> $LOG_FILE

case $STATE in
    master)
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] This node is now the master" >> $LOG_FILE
        # 可以在这里添加其他操作,如发送邮件通知
        ;;
    backup)
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] This node is now a backup" >> $LOG_FILE
        ;;
    fault)
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] This node is in fault state" >> $LOG_FILE
        # 可以在这里添加其他操作,如发送邮件通知
        ;;
    *)
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] Unknown state: $STATE" >> $LOG_FILE
        ;;
esac

设置脚本权限:

bash
chmod +x /usr/local/bin/proxysql_notify.sh

故障转移测试

测试 ProxySQL 故障转移

  1. 查看当前 VIP 状态

    bash
    ip addr show eth0
  2. 停止 ProxySQL 1 上的 ProxySQL 服务

    bash
    systemctl stop proxysql
  3. 检查 VIP 是否转移到 ProxySQL 2

    bash
    ip addr show eth0
  4. 启动 ProxySQL 1 上的 ProxySQL 服务

    bash
    systemctl start proxysql
  5. 检查 VIP 是否转移回 ProxySQL 1

    bash
    ip addr show eth0

测试 MySQL 主库故障转移

  1. 模拟主库故障

    bash
    systemctl stop mysqld
  2. 检查 MHA 是否将从库提升为主库(如果使用 MHA)

  3. 检查 ProxySQL 是否检测到主库变化

    sql
    SELECT * FROM mysql_servers;
  4. 验证应用程序是否仍能正常连接

    bash
    mysql -u app_user -papp_pass -h 192.168.1.100 -P 6033 -e "SELECT 1;"

监控与告警

监控指标

  • ProxySQL 指标

    • 连接数
    • 查询吞吐量
    • 错误率
    • 缓存命中率
  • Keepalived 指标

    • VIP 状态
    • 节点状态
    • 故障转移次数
  • MySQL 指标

    • 复制状态
    • 主从延迟
    • 连接数
    • 查询性能

监控工具

  • Prometheus + Grafana

    • 使用 proxysql_exporter 监控 ProxySQL
    • 使用 node_exporter 监控服务器状态
    • 使用 mysqld_exporter 监控 MySQL 状态
  • Zabbix

    • 配置 ProxySQL 监控模板
    • 配置 Keepalived 监控模板
    • 配置 MySQL 监控模板
  • Nagios

    • 使用插件监控 ProxySQL 状态
    • 使用插件监控 Keepalived 状态
    • 使用插件监控 MySQL 状态

告警策略

  • ProxySQL 告警

    • ProxySQL 服务停止
    • 连接数超过阈值
    • 查询错误率超过阈值
  • Keepalived 告警

    • VIP 状态变化
    • 节点状态异常
    • 故障转移发生
  • MySQL 告警

    • 复制中断
    • 主从延迟过大
    • 连接数超过阈值

最佳实践

配置最佳实践

  • 使用专用监控用户:创建专门的监控用户,权限最小化
  • 合理设置权重:根据服务器性能设置合适的权重
  • 启用连接池:提高连接效率,减少资源消耗
  • 配置查询缓存:对于频繁执行的查询启用缓存
  • 合理设置超时:根据业务需求设置合适的超时时间

部署最佳实践

  • 分布式部署:ProxySQL 节点和 MySQL 节点分布在不同的物理机器上
  • 网络优化:使用高速网络,减少网络延迟
  • 硬件冗余:确保所有组件都有冗余备份
  • 定期测试:定期进行故障转移演练
  • 文档化:记录所有配置和操作流程

运维最佳实践

  • 定期检查:每周检查系统状态和日志
  • 定期备份:备份所有配置文件和数据
  • 定期更新:及时更新软件版本和安全补丁
  • 监控日志:监控系统日志和应用日志
  • 容量规划:根据业务增长规划资源需求

故障排查

常见问题

VIP 无法转移

  • 症状:当活动节点故障时,VIP 未转移到备用节点
  • 原因
    • Keepalived 服务未运行
    • 监控脚本配置错误
    • VRRP 协议被防火墙阻止
  • 解决方案
    • 检查 Keepalived 服务状态
    • 检查监控脚本是否正确执行
    • 检查防火墙配置,确保 VRRP 协议通过

ProxySQL 无法连接到 MySQL

  • 症状:ProxySQL 无法连接到 MySQL 服务器
  • 原因
    • MySQL 服务未运行
    • 网络连接问题
    • 用户名或密码错误
    • 防火墙阻止连接
  • 解决方案
    • 检查 MySQL 服务状态
    • 检查网络连接
    • 验证用户名和密码
    • 检查防火墙配置

查询路由错误

  • 症状:读操作被路由到主库,或写操作被路由到从库
  • 原因
    • 查询规则配置错误
    • 正则表达式匹配问题
  • 解决方案
    • 检查查询规则配置
    • 测试正则表达式匹配
    • 调整查询规则顺序

排查步骤

  1. 检查系统状态

    bash
    systemctl status proxysql keepalived mysqld
  2. 检查网络连接

    bash
    ping 192.168.1.100
    ping 192.168.1.201
  3. 检查 ProxySQL 状态

    sql
    SELECT * FROM mysql_servers;
    SELECT * FROM mysql_query_rules;
  4. 检查 Keepalived 状态

    bash
    systemctl status keepalived
    tail -f /var/log/messages
  5. 检查 MySQL 复制状态

    sql
    SHOW SLAVE STATUS\G

案例分析

电商系统高可用方案

业务需求

  • 高可用性,99.99% 可用性
  • 读写分离,提高性能
  • 自动故障转移,减少人工干预
  • 负载均衡,提高系统吞吐量

部署方案

  • 2 个 ProxySQL 节点,配置 Keepalived 实现 VIP 管理
  • 1 主 2 从 MySQL 架构,使用 MHA 实现主从切换
  • Prometheus + Grafana 监控整个系统

优化效果

  • 系统可用性达到 99.99%
  • 读操作性能提升 300%
  • 故障转移时间小于 30 秒
  • 系统吞吐量提高 200%

金融系统高可用方案

业务需求

  • 极高可用性,99.999% 可用性
  • 数据一致性,零数据丢失
  • 安全可靠,符合合规要求
  • 性能稳定,低延迟

部署方案

  • 3 个 ProxySQL 节点,配置 Keepalived 实现 VIP 管理
  • 1 主 3 从 MySQL 架构,使用半同步复制和 MHA
  • 跨机房部署,实现地理冗余
  • 完善的监控和告警系统

优化效果

  • 系统可用性达到 99.999%
  • 数据一致性得到保障
  • 故障转移时间小于 10 秒
  • 系统性能稳定,延迟低于 10ms

常见问题(FAQ)

Q1: ProxySQL 和 Keepalived 的关系是什么?

A1: ProxySQL 负责 MySQL 的读写分离和负载均衡,Keepalived 负责 ProxySQL 节点的高可用性,通过 VIP 实现故障转移。两者结合使用,可以构建完整的 MySQL 高可用解决方案。

Q2: 如何选择 ProxySQL 的版本?

A2: 建议选择稳定版本,如 2.4.x 系列。在生产环境中,应选择经过充分测试的版本,避免使用最新的测试版本。同时,应定期更新版本,以获取最新的功能和安全补丁。

Q3: Keepalived 的优先级设置有什么要求?

A3: 主节点的优先级应高于备用节点,通常相差 10 或 20。优先级越高,成为主节点的可能性越大。当主节点故障时,备用节点会根据优先级选举新的主节点。

Q4: 如何配置 ProxySQL 的读写分离规则?

A4: 可以通过正则表达式配置查询规则,将写操作路由到主库,读操作路由到从库。例如,将 ^SELECT.*FOR UPDATE 路由到主库,将 ^SELECT 路由到从库。

Q5: 如何监控 ProxySQL 和 Keepalived 的状态?

A5: 可以使用 Prometheus + Grafana、Zabbix 或 Nagios 等监控工具。对于 ProxySQL,可以使用 proxysql_exporter 收集指标;对于 Keepalived,可以通过监控 VIP 状态和系统日志来实现。

Q6: 如何测试故障转移?

A6: 可以通过停止活动节点上的服务来测试故障转移。例如,停止主 ProxySQL 节点上的 ProxySQL 服务,检查 VIP 是否转移到备用节点;停止主 MySQL 节点上的 MySQL 服务,检查从库是否被提升为主库。

Q7: 如何优化 ProxySQL 的性能?

A7: 可以通过以下方法优化 ProxySQL 的性能:

  • 启用连接池
  • 配置查询缓存
  • 合理设置线程数
  • 优化网络配置
  • 使用高速存储

Q8: 如何处理 ProxySQL 的日志?

A8: ProxySQL 的日志包括错误日志、查询日志和管理日志。应定期清理日志,避免磁盘空间不足。同时,可以配置日志轮转,自动管理日志文件的大小和数量。

Q9: 如何实现跨机房部署?

A9: 跨机房部署需要考虑网络延迟和数据一致性。可以在每个机房部署 ProxySQL 和 MySQL 节点,使用 Keepalived 管理 VIP,使用半同步复制确保数据一致性。同时,应配置合理的路由规则,优先将请求路由到本地机房的服务器。

Q10: 如何确保系统的安全性?

A10: 可以通过以下方法确保系统的安全性:

  • 使用 SSL/TLS 加密所有连接
  • 配置防火墙,限制访问
  • 使用强密码和定期密码更换
  • 最小化用户权限
  • 定期进行安全审计
  • 及时更新安全补丁

Q11: 如何处理大量连接?

A11: 可以通过以下方法处理大量连接:

  • 启用连接池,复用连接
  • 合理设置最大连接数
  • 使用读写分离,分散负载
  • 优化应用程序,减少连接数
  • 考虑使用分片,分散数据和连接

Q12: 如何规划系统容量?

A12: 系统容量规划应考虑以下因素:

  • 业务增长预期
  • 峰值流量
  • 数据量增长
  • 响应时间要求
  • 可用性要求

应根据这些因素选择合适的硬件配置和软件参数,并定期进行容量评估和调整。