一、基础概念与方案选型

1. 什么是MySQL负载均衡

MySQL负载均衡核心目标:

  1. 读请求分摊:多从库分担查询压力,横向扩容读能力
  2. 读写分离:写统一走主库,读分发到从库
  3. 故障自动摘除:节点宕机不再转发流量
  4. 连接池复用:减少应用直连MySQL的连接数消耗

2. 主流方案对比(生产首选ProxySQL/HAProxy)

方案层级核心能力适用场景
HAProxy四层TCP代理连接轮询、权重、健康检查,不解析SQL仅做读负载均衡、简单集群、低并发
ProxySQLSQL七层代理自动读写分离、SQL规则路由、连接池、缓存绝大多数业务(读多写少、无需改代码)
MySQL Router官方轻量代理配合InnoDB Cluster/MGR,简单读写端口MySQL官方集群、小型业务
LVS+Keepalived四层内核负载性能最高,无流量损耗超大流量、千级并发数据库集群
应用层分库代码层面区分读写零中间件,维护成本高架构统一、研发可控团队

推荐新手/中小企业:ProxySQL,开箱即用读写分离,不用改业务代码。

二、前置环境准备(通用,所有方案共用)

环境拓扑示例

  • Master主库:192.168.10.10:3306(写)
  • Slave1从库:192.168.10.11:3306(读)
  • Slave2从库:192.168.10.12:3306(读)
  • ProxySQL代理:192.168.10.20(对外端口6033)

步骤1:搭建MySQL主从复制(必须先做)

1.1 主库my.cnf配置
[mysqld]
server-id=1
log_bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON

重启MySQL,创建复制账号:

CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl@123';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS; -- 记录File、Position
1.2 从库my.cnf(两台从库server-id分别2、3)
[mysqld]
server-id=2
relay_log=relay-bin
read_only=ON
super_read_only=ON
gtid_mode=ON
enforce_gtid_consistency=ON

重启从库,配置同步:

CHANGE MASTER TO
MASTER_HOST='192.168.10.10',
MASTER_USER='repl',
MASTER_PASSWORD='Repl@123',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=156;

START SLAVE;
SHOW SLAVE STATUS\G
# 校验:Slave_IO_Running=Yes,Slave_SQL_Running=Yes
1.3 创建ProxySQL监控/业务账号(所有MySQL节点执行)
-- 监控账号(代理探测节点存活)
CREATE USER 'proxy_monitor'@'%' IDENTIFIED BY 'Monitor@123';
GRANT SELECT, REPLICATION CLIENT ON *.* TO 'proxy_monitor'@'%';

-- 业务访问账号(应用连接代理)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'App@123';
GRANT ALL ON business.* TO 'app_user'@'%';
FLUSH PRIVILEGES;

三、方案一:ProxySQL 读写分离+负载均衡(生产主流完整教程)

1. 安装ProxySQL(CentOS7/8)

yum install -y proxysql
systemctl start proxysql
systemctl enable proxysql

管理端口:6032(admin后台),业务端口默认6033(应用连接)
登录管理后台:

mysql -uadmin -padmin -h127.0.0.1 -P6032

2. 注册后端MySQL节点(分写组、读组)

hostgroup规范:

  • hostgroup_id=10:写组(仅主库)
  • hostgroup_id=20:读组(所有从库,自动负载均衡)
-- 清空原有配置
DELETE FROM mysql_servers;

-- 添加主库(写组)
INSERT INTO mysql_servers(hostgroup_id,hostname,port,weight,max_connections)
VALUES (10,'192.168.10.10',3306,1000,2000);

-- 添加两台从库(读组,权重相同轮询)
INSERT INTO mysql_servers(hostgroup_id,hostname,port,weight,max_connections)
VALUES
(20,'192.168.10.11',3306,100,2000),
(20,'192.168.10.12',3306,100,2000);

-- 加载到运行时、持久化磁盘
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

-- 查看节点
SELECT hostgroup_id,hostname,status,weight FROM mysql_servers;

3. 配置监控账号(自动健康检查)

SET mysql_monitor_username='proxy_monitor';
SET mysql_monitor_password='Monitor@123';
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

ProxySQL会每秒执行SELECT 1探测节点,宕机自动OFFLINE摘除。

4. 配置自动读写分离路由规则(核心)

规则优先级从上到下:

  1. SELECT ... FOR UPDATE 加锁查询强制走主库
  2. 普通SELECT走读组20(负载均衡分发)
  3. INSERT/UPDATE/DELETE/DDL全部走写组10
DELETE FROM mysql_query_rules;

-- 1. 行锁查询走主库
INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply)
VALUES (1,1,'^SELECT .*FOR UPDATE$',10,0);

-- 2. 普通SELECT走从库读组
INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply)
VALUES (2,1,'^SELECT',20,1);

-- 3. 其余所有SQL(增删改、建表)走主库
INSERT INTO mysql_query_rules(rule_id,active,match_pattern,destination_hostgroup,apply)
VALUES (3,1,'.',10,1);

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

5. 配置业务访问账号

DELETE FROM mysql_users;
INSERT INTO mysql_users(username,password,default_hostgroup,transaction_persistent)
VALUES ('app_user','App@123',10,1);

LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

default_hostgroup=10:无匹配规则默认走主库,保障事务一致性。

6. 验证负载均衡与读写分离

6.1 应用连接代理
mysql -uapp_user -pApp@123 -h192.168.10.20 -P6033
6.2 验证读负载均衡(多次执行,交替返回两台从库hostname)
SELECT @@hostname;
6.3 验证写路由(INSERT只会走到主库)
INSERT INTO test(name) VALUES('test');
6.4 查看路由统计(ProxySQL后台6032端口)
SELECT hostgroup,sum_count,username FROM stats_mysql_query_digest;

7. 高可用补充:双ProxySQL+Keepalived VIP

两台ProxySQL部署Keepalived,对外统一虚拟IP,避免代理单点故障。

四、方案二:HAProxy 纯TCP读负载均衡(仅分发读流量)

适用场景:仅需要分摊读请求,不需要自动SQL读写分离,业务代码手动区分读写地址。

1. 安装HAProxy

yum install haproxy -y

2. 配置 /etc/haproxy/haproxy.cfg

global
    log /dev/log local0
    daemon
defaults
    mode tcp
    timeout connect 5s
    timeout client 30s
    timeout server 30s
# 前端监听3307,对外读端口
frontend mysql-read
    bind 0.0.0.0:3307
    default_backend slave_pool
# 后端从库集群,轮询负载均衡
backend slave_pool
    mode tcp
    balance roundrobin
    server slave1 192.168.10.11:3306 check inter 2000 rise 2 fall 3
    server slave2 192.168.10.12:3306 check inter 2000 rise 2 fall 3
# 监控页面
listen stats
    bind 0.0.0.0:8080
    stats enable
    stats auth admin:123456

3. 启动&验证

systemctl start haproxy
# 连接读均衡端口
mysql -uapp_user -pApp@123 -h192.168.10.20 -P3307

浏览器访问 http://代理IP:8080 查看节点在线状态。

五、方案三:MySQL Router(官方轻量,配套MGR/InnoDB Cluster)

  1. 安装mysql-router
  2. bootstrap自动发现集群
mysqlrouter --bootstrap root@192.168.10.10:3306 --user=mysqlrouter
  1. 自动生成两个端口:
  • 6446:读写端口(主库)
  • 6447:只读端口(从库负载均衡)
    业务区分端口连接即可,无需SQL解析。

六、负载均衡核心运维要点

1. 负载均衡调度算法

  • roundrobin:轮询,服务器性能均等
  • weight:权重,高配机器分配更多请求
  • leastconn:最少连接,适合长查询业务
  • runtime weight:ProxySQL支持动态调整从库权重

2. 避坑关键点

  1. 主从延迟:实时报表、强一致性查询必须走主库,不要分配到从库
  2. SELECT … FOR UPDATE:行锁查询禁止分发从库,否则数据不一致
  3. 事务边界:事务内所有SQL必须统一路由同一节点
  4. 健康检查间隔:ProxySQL默认1000ms,HAProxy推荐2000ms
  5. 连接数限制:proxy层控制max_connections,防止打满MySQL连接

3. 故障排查命令

ProxySQL
-- 查看节点状态
SELECT hostname,status FROM mysql_servers;
-- 查看失败探测
SELECT * FROM monitor_mysql_servers;
-- SQL路由统计
SELECT digest_text,hostgroup,sum_count FROM stats_mysql_query_digest ORDER BY sum_count DESC;
HAProxy
# 查看后端状态
echo "show servers state" | socat stdio /var/lib/haproxy/stats

更多推荐