ProxySQL 安装与基本配置指南 —— 实现 MySQL 读写分离

avatar 2026年7月17日18:37:40 评论 6 次浏览

一、为什么要用 ProxySQL?

在业务增长过程中,数据库往往是最先出现瓶颈的环节。读写分离是提升数据库性能最直接有效的手段之一。然而,直接在应用层硬编码读写分离逻辑,不仅代码侵入性强,后期维护成本也很高。

ProxySQL 是一个高性能、轻量级的 MySQL 代理中间件,用 C++ 开发,性能损耗极低。它能帮你:

  • 透明地实现读写分离:应用只需连接 ProxySQL,无需关心后端主从结构

  • 自动故障切换:后端节点宕机时自动摘除,对应用无感知

  • 灵活的路由规则:可按 SQL 类型、正则表达式、事务状态等精细控制路由

与 MyCAT、ShardingSphere 等竞品相比,ProxySQL 的定位非常明确——专注于纯读写分离场景,部署简单,配置方式灵活(通过 SQL 即可完成),学习曲线平缓。如果你的需求只是读写分离,不需要分库分表,ProxySQL 是性价比最高的选择。


二、环境准备

项目 说明
ProxySQL 版本 3.0.9(最新稳定版)
操作系统 CentOS 7/8/9、Ubuntu 20.04/22.04/24.04 等
后端数据库 MySQL 5.7 或 8.0,已完成主从复制配置
必备工具 MySQL 客户端(用于连接管理端口)

网络规划参考

角色 IP 地址 端口
ProxySQL 服务节点 192.168.0.10 6033(应用连接)/ 6032(管理端口)
MySQL 主库 192.168.0.11 3306
MySQL 从库 1 192.168.0.12 3306
MySQL 从库 2 192.168.0.13 3306

三、安装 ProxySQL

方式一:通过 YUM 仓库安装(推荐,CentOS/RHEL)

1. 配置官方 YUM 仓库

cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name=ProxySQL repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-3.0.x/centos/\$releasever
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/proxysql-3.0.x/repo_pub_key
EOF

2. 安装 ProxySQL

yum install proxysql -y

如果要安装特定版本,例如 3.0.9:

yum install proxysql-3.0.9 -y

方式二:通过 APT 仓库安装(Ubuntu/Debian)

# 添加仓库密钥和源
wget -nv -O /usr/share/keyrings/proxysql-3.0.x-keyring.gpg \
  'https://repo.proxysql.com/ProxySQL/proxysql-3.0.x/repo_pub_key.gpg'
echo "deb [signed-by=/usr/share/keyrings/proxysql-3.0.x-keyring.gpg] \
  https://repo.proxysql.com/ProxySQL/proxysql-3.0.x/$(lsb_release -sc)/ ./" \
  | tee /etc/apt/sources.list.d/proxysql.list

# 安装
apt update
apt install proxysql -y

方式三:下载 DEB/RPM 包直接安装

访问 GitHub Releases 下载对应系统的安装包:

# Ubuntu 示例
wget https://github.com/sysown/proxysql/releases/download/v3.0.9/proxysql_3.0.9-ubuntu22_amd64.deb
dpkg -i proxysql_3.0.9-ubuntu22_amd64.deb

四、启动与基本验证

安装完成后,使用 systemd 管理服务:

# 启动 ProxySQL
systemctl start proxysql

# 设置开机自启
systemctl enable proxysql

# 查看状态
systemctl status proxysql

检查端口监听:

netstat -tlnp | grep -E '6032|6033'
  • 6032:管理端口,用于配置 ProxySQL

  • 6033:应用连接端口,业务程序通过此端口访问数据库


五、核心概念:三层配置体系

在动手配置之前,必须先理解 ProxySQL 独特的配置架构,这是最容易踩坑的地方:

┌─────────────────────────────────────┐
│           RUNTIME                   │  ← 正在生效的配置(内存中)
├─────────────────────────────────────┤
│           MEMORY                    │  ← 你正在编辑的配置(修改后未生效)
├─────────────────────────────────────┤
│           DISK                      │  ← 持久化到 SQLite 的配置(重启不丢失)
└─────────────────────────────────────┘

操作逻辑

  1. 在管理界面中修改 MEMORY 层的表

  2. 执行 LOAD ... TO RUNTIME 使配置生效

  3. 执行 SAVE ... TO DISK 持久化到磁盘

⚠️ 常见错误:修改后忘了 SAVE TO DISK,重启 ProxySQL 后配置全部丢失。


六、配置读写分离

6.1 连接管理界面

mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='ProxySQL> '

注意:必须用 127.0.0.1,不能用 localhost,否则客户端会用 Unix Socket 连接,无法到达 TCP 端口。

默认管理员账号密码为 admin/admin。如果 MySQL 客户端版本为 8.04 或更高,可能需要添加 --default-auth=mysql_native_password

6.2 在后端 MySQL 创建监控账号

ProxySQL 需要通过监控账号检测后端节点的健康状况和复制延迟:

-- 在主库上执行
CREATE USER 'monitor'@'%' IDENTIFIED BY 'monitor';
GRANT SUPER, REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'monitor'@'%';
FLUSH PRIVILEGES;

6.3 配置后端 MySQL 实例

在管理界面中执行:

-- 清空已有配置(首次配置或重置时使用)
DELETE FROM mysql_servers;

-- 添加主库(写组,hostgroup_id = 10)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) 
VALUES (10, '192.168.0.11', 3306, 100);

-- 添加从库(读组,hostgroup_id = 20)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) 
VALUES (20, '192.168.0.12', 3306, 100);
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) 
VALUES (20, '192.168.0.13', 3306, 100);

-- 加载到 RUNTIME 并持久化
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

参数说明

  • hostgroup_id:分组编号,10 为写组,20 为读组

  • weight:权重,值越大分配流量越多

  • max_replication_lag:可单独为从库设置延迟阈值,超过则自动摘除

6.4 配置应用连接账号

-- 添加应用使用的账号
INSERT INTO mysql_users (username, password, default_hostgroup, transaction_persistent) 
VALUES ('appuser', 'your_password', 10, 1);

-- 加载并持久化
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

参数说明

  • default_hostgroup=10:默认路由到写组

  • transaction_persistent=1:事务内的所有 SQL 保持在同一 hostgroup,避免读写不一致

注意:appuser 需要提前在后端 MySQL 主库上创建并授权。

6.5 配置读写分离规则——最关键的一步

规则按 rule_id 从小到大顺序匹配,匹配到 apply=1 的规则后停止匹配,顺序很重要。

-- 删除旧规则(重置用)
DELETE FROM mysql_query_rules;

-- 规则1:SELECT ... FOR UPDATE(需要加锁的读)→ 走写组
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) 
VALUES (1, 1, '^SELECT.*FOR UPDATE$', 10, 1);

-- 规则2:普通 SELECT → 走读组
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) 
VALUES (2, 1, '^SELECT', 20, 1);

-- 规则3:写操作(INSERT/UPDATE/DELETE/REPLACE)→ 走写组
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) 
VALUES (3, 1, '^(INSERT|UPDATE|DELETE|REPLACE)', 10, 1);

-- 规则4:兜底规则,所有其他 SQL → 走写组
INSERT INTO mysql_query_rules (rule_id, active, match_digest, destination_hostgroup, apply) 
VALUES (4, 1, '.*', 10, 1);

-- 加载并持久化
LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

规则匹配逻辑

rule_id 匹配条件 路由目标 说明
1 ^SELECT.*FOR UPDATE$ 写组(10) 带锁的查询必须走主库
2 ^SELECT 读组(20) 普通查询走从库
3 ^(INSERT|UPDATE|DELETE|REPLACE) 写组(10) 所有写操作走主库
4 .* 写组(10) 未被匹配的请求兜底到主库

6.6 配置主从复制组(自动故障切换)

配置 mysql_replication_hostgroups 后,ProxySQL 会自动检测后端节点的 read_only 状态,当主库宕机、从库提升为新主库时,自动调整路由。

INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup, comment) 
VALUES (10, 20, '读写分离组');

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

6.7 启用监控和复制延迟检查

-- 启用监控
UPDATE global_variables SET variable_value='true' WHERE variable_name='mysql-monitor_enabled';

-- 设置监控间隔(单位:毫秒)
UPDATE global_variables SET variable_value='2000' 
WHERE variable_name IN (
  'mysql-monitor_connect_interval',
  'mysql-monitor_ping_interval',
  'mysql-monitor_read_only_interval'
);

-- 设置从库最大复制延迟(单位:秒),超过则自动摘除
UPDATE mysql_servers SET max_replication_lag = 10 WHERE hostgroup_id = 20;

-- 加载全局变量
LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

6.8 利用配置文件配置

根据官方文档,配置文件主要用于提供初始/基础配置,复杂的配置推荐通过管理界面进行动态修改。

# ProxySQL 配置文件示例
# 用于 MySQL 读写分离场景

# ==========================================
# 1. 基础路径设置 (始终从配置文件读取)
# ==========================================
datadir="/var/lib/proxysql"                 # 数据目录,存放 proxysql.db 等文件
errorlog="/var/lib/proxysql/proxysql.log"   # 错误日志路径

# ==========================================
# 2. 管理模块 (admin_variables)
# ==========================================
admin_variables = {
    # 管理员账号密码(强烈建议生产环境修改)
    # 格式: 用户名:密码,多个用分号隔开
    admin_credentials="admin:admin;radmin:radmin"

    # 管理接口监听地址和端口(默认 6032)
    mysql_ifaces="0.0.0.0:6032"

    # 是否启用 REST API(可选)
    restapi_enabled="true"
    restapi_port=6070

    # 管理界面刷新间隔(毫秒)
    refresh_interval=2000
}

# ==========================================
# 3. MySQL 代理模块 (mysql_variables)
# ==========================================
mysql_variables = {
    # 业务端口,应用程序连接此端口(默认 6033)
    interfaces="0.0.0.0:6033"

    # 后端 MySQL 版本,ProxySQL 会向客户端报告此版本
    server_version="5.7.39"

    # 线程数与连接数
    threads=4
    max_connections=2048

    # 查询超时(毫秒),默认 36,000,000 ms = 10 小时
    default_query_timeout=36000000

    # 监控账号(需提前在后端 MySQL 创建)
    monitor_username="monitor"
    monitor_password="monitor"

    # 监控间隔(毫秒)
    monitor_connect_interval=2000
    monitor_ping_interval=2000
    monitor_read_only_interval=1500

    # 启用压缩
    have_compress=true
}

# ==========================================
# 4. 后端服务器列表 (mysql_servers)
# 注:官方推荐通过管理界面动态配置,此处仅作初始化示例
# ==========================================
mysql_servers = (
    # 主库(写组 hostgroup_id = 10)
    {
        address="192.168.0.11"
        port=3306
        hostgroup=10
        weight=100
        max_replication_lag=0
    },
    # 从库1(读组 hostgroup_id = 20)
    {
        address="192.168.0.12"
        port=3306
        hostgroup=20
        weight=100
        max_replication_lag=10
    },
    # 从库2(读组 hostgroup_id = 20)
    {
        address="192.168.0.13"
        port=3306
        hostgroup=20
        weight=100
        max_replication_lag=10
    }
)

# ==========================================
# 5. 应用用户 (mysql_users)
# ==========================================
mysql_users = (
    {
        username="appuser"
        password="your_password"
        default_hostgroup=10           # 默认路由到写组
        transaction_persistent=1       # 事务内保持同一 hostgroup
        active=1
        max_connections=100
    }
)

# ==========================================
# 6. 读写分离路由规则 (mysql_query_rules)
# 匹配顺序:按 rule_id 从小到大
# ==========================================
mysql_query_rules = (
    # 规则1:SELECT ... FOR UPDATE(加锁读)→ 写组
    {
        rule_id=1
        active=1
        match_digest="^SELECT.*FOR UPDATE$"
        destination_hostgroup=10
        apply=1
    },
    # 规则2:普通 SELECT → 读组
    {
        rule_id=2
        active=1
        match_digest="^SELECT"
        destination_hostgroup=20
        apply=1
    },
    # 规则3:写操作(INSERT/UPDATE/DELETE/REPLACE)→ 写组
    {
        rule_id=3
        active=1
        match_digest="^(INSERT|UPDATE|DELETE|REPLACE)"
        destination_hostgroup=10
        apply=1
    },
    # 规则4:兜底规则,其他所有 SQL → 写组
    {
        rule_id=4
        active=1
        match_digest=".*"
        destination_hostgroup=10
        apply=1
    }
)

# ==========================================
# 7. 复制组自动管理(可选)
# 根据后端 read_only 状态自动分配 hostgroup
# ==========================================
mysql_replication_hostgroups = (
    {
        writer_hostgroup=10
        reader_hostgroup=20
        comment="读写分离组"
    }
)

配置要点说明

1. 配置文件 vs 动态命令:配置文件仅在 ProxySQL 首次启动或使用 --initial 参数时被读取,主要用于初始化 proxysql.db。日常运维推荐通过管理端口(6032)使用 INSERT/UPDATE + LOAD/SAVE 命令动态修改配置。

2. 管理员账号admin_credentials 的默认账号是 admin:admin生产环境务必修改,否则存在严重安全风险。示例中添加了 radmin 作为只读管理账号。

3. 监控账号monitor_usernamemonitor_password 需要提前在后端 MySQL 主库上创建并授予 SUPER, REPLICATION CLIENT, REPLICATION SLAVE 权限,否则 ProxySQL 无法检测后端节点健康状态。

4. 路由规则匹配顺序:规则按 rule_id 从小到大依次匹配,apply=1 表示匹配成功后停止继续匹配后续规则。因此要先匹配特殊规则(如 FOR UPDATE),再匹配通用规则。

5. 命令速查

-- 连接管理界面
mysql -u admin -padmin -h 127.0.0.1 -P6032

-- 修改配置后必须执行:
LOAD MYSQL SERVERS TO RUNTIME;   -- 使配置生效
SAVE MYSQL SERVERS TO DISK;      -- 持久化到磁盘(防止重启丢失)

这份配置文件可以作为搭建读写分离的起点,实际部署时请根据你的主从 IP、端口、账号密码等信息替换对应值。


七、验证读写分离效果

7.1 应用连接测试

使用配置的应用账号连接 ProxySQL 的服务端口(6033):

mysql -u appuser -p'your_password' -h 192.168.0.10 -P6033

7.2 查看路由状态

在管理界面(6032 端口)查看连接池状态:

SELECT hostgroup, srv_host, srv_port, status, ConnUsed 
FROM stats_mysql_connection_pool;

如果从库连接显示 hostgroup = 20,主库连接显示 hostgroup = 10,且状态均为 ONLINE,说明注册成功。

7.3 查看查询路由统计

SELECT digest_text, count_star, sum_time, hostgroup
FROM stats_mysql_query_digest
ORDER BY count_star DESC
LIMIT 10;

如果 SELECT 查询的 hostgroup 是 20,INSERT/UPDATEhostgroup 是 10,说明读写分离已生效。

7.4 强制路由调试

如需临时强制查询走主库,可使用注释 Hint:

/* hostgroup=10 */ SELECT * FROM your_table;

八、常见踩坑与解决方案

💣 坑 1:事务中的读操作被路由到从库

现象:事务中先插入了一条数据,紧接着查询时查不到。

原因:SELECT 被匹配到读组,从库复制有延迟,数据还未同步。

解决

  • 确保应用使用事务包裹“写后立即读”的操作

  • 或使用 Hint 强制走主库:/* hostgroup=10 */ SELECT ...

💣 坑 2:修改配置后重启丢失

现象:重启 ProxySQL 后所有配置消失。

原因:只执行了 LOAD ... TO RUNTIME,未执行 SAVE ... TO DISK

解决:养成习惯,每次改完都执行 SAVE MYSQL ... TO DISK

💣 坑 3:忘记配置监控账号

现象:后端节点状态一直是 OFFLINE 或连接报错。

原因:未在 MySQL 创建 monitor 账号,或密码与配置不匹配。

解决:检查 mysql-monitor_usernamemysql-monitor_password 配置,确保与 MySQL 实际账号一致。

💣 坑 4:从库宕机后流量未自动切换

现象:从库宕机后,部分查询仍然报错。

原因:未配置 mysql_replication_hostgroups 或监控间隔过长。

解决:配置 mysql_replication_hostgroups,并适当缩短监控间隔。


九、常用管理命令速查

操作 命令
连接管理界面 mysql -u admin -padmin -h 127.0.0.1 -P6032
查看后端节点状态 SELECT * FROM runtime_mysql_servers;
查看连接池状态 SELECT * FROM stats_mysql_connection_pool;
查看查询路由统计 SELECT * FROM stats_mysql_query_digest ORDER BY sum_time DESC LIMIT 10;
查看当前生效的规则 SELECT * FROM runtime_mysql_query_rules;
重启 ProxySQL systemctl restart proxysql
查看版本 proxysql --version

十、总结

ProxySQL 是一款非常适合 MySQL 读写分离场景的轻量级中间件。通过这篇文章,你已经掌握了从安装到配置读写分离的完整流程。

配置要点回顾

  1. 三层配置体系:记住 LOADSAVE 缺一不可

  2. 规则顺序:按 rule_id 从小到大匹配,先特殊后通用

  3. 事务一致性:开启 transaction_persistent=1,避免读写不一致

  4. 监控先行:配置监控账号,启用健康检查和复制延迟检查

希望这份指南能帮助你顺利落地 ProxySQL 读写分离方案。如果在配置过程中遇到其他问题,欢迎交流讨论。

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: