外观
MySQL ProxySQL + Keepalived 自动切换方案
架构设计
基本架构
- ProxySQL 层:2个ProxySQL节点,实现读写分离和负载均衡
- Keepalived 层:在ProxySQL节点上部署,提供VIP(虚拟IP)管理
- MySQL 层:1主多从架构,使用MHA或其他方案实现主从切换
组件说明
- ProxySQL:开源的MySQL代理,支持读写分离、连接池、查询路由等功能
- Keepalived:基于VRRP协议的高可用解决方案,实现VIP的故障转移
- MySQL:主从复制架构,提供数据存储服务
数据流
- 应用程序连接到VIP
- Keepalived将请求转发到活动的ProxySQL节点
- ProxySQL根据规则将请求路由到MySQL主库(写操作)或从库(读操作)
- 当活动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 1 | proxysql1 | 192.168.1.101 | 192.168.1.100 |
| ProxySQL 2 | proxysql2 | 192.168.1.102 | 192.168.1.100 |
| MySQL 主库 | mysql-master | 192.168.1.201 | - |
| MySQL 从库1 | mysql-slave1 | 192.168.1.202 | - |
| MySQL 从库2 | mysql-slave2 | 192.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 故障转移
查看当前 VIP 状态:
baship addr show eth0停止 ProxySQL 1 上的 ProxySQL 服务:
bashsystemctl stop proxysql检查 VIP 是否转移到 ProxySQL 2:
baship addr show eth0启动 ProxySQL 1 上的 ProxySQL 服务:
bashsystemctl start proxysql检查 VIP 是否转移回 ProxySQL 1:
baship addr show eth0
测试 MySQL 主库故障转移
模拟主库故障:
bashsystemctl stop mysqld检查 MHA 是否将从库提升为主库(如果使用 MHA)
检查 ProxySQL 是否检测到主库变化:
sqlSELECT * FROM mysql_servers;验证应用程序是否仍能正常连接:
bashmysql -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 服务状态
- 检查网络连接
- 验证用户名和密码
- 检查防火墙配置
查询路由错误
- 症状:读操作被路由到主库,或写操作被路由到从库
- 原因:
- 查询规则配置错误
- 正则表达式匹配问题
- 解决方案:
- 检查查询规则配置
- 测试正则表达式匹配
- 调整查询规则顺序
排查步骤
检查系统状态:
bashsystemctl status proxysql keepalived mysqld检查网络连接:
bashping 192.168.1.100 ping 192.168.1.201检查 ProxySQL 状态:
sqlSELECT * FROM mysql_servers; SELECT * FROM mysql_query_rules;检查 Keepalived 状态:
bashsystemctl status keepalived tail -f /var/log/messages检查 MySQL 复制状态:
sqlSHOW 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: 系统容量规划应考虑以下因素:
- 业务增长预期
- 峰值流量
- 数据量增长
- 响应时间要求
- 可用性要求
应根据这些因素选择合适的硬件配置和软件参数,并定期进行容量评估和调整。
