导读:经常会有开发者咨询开源PolarDB-X部署相关问题。我们让AI全自动部署了一遍,看看在部署过程中有哪些容易被忽略的问题。如果你正准备部署PolarDB-X,这篇文章至少能帮你省下2小时排障时间。
PolarDB-X简介
PolarDB分布式版(简称PolarDB-X)是阿里云自主研发的云原生集中式和分布式一体化数据库产品,整体采用了基于存储计算分离的Shared-Nothing系统架构,支持水平扩展、分布式事务、混合负载等能力,具备金融级高可用、高吞吐、大存储、低延时、易扩展、高度兼容 MySQL 系统及生态等特点。
而PolarDB-X标准版,基于集中分布式一体化的架构,将分布式中的存储节点(DN)多副本单独提供服务,提供100%兼容MySQL的语法和功能,兼容MySQL5.7、8.0等多个版本。同时,标准版相对于原生MySQL进行了多方位的功能和性能的增强,基于分布式的技术丰富了高可用、性能提升等。
PolarDB-X标准版,采用分层架构:
日志层:采用Paxos的多数派复制协议,基于Paxos consensus协议日志完全兼容MySQL Binlog格式。相比于开源MySQL主备复制协议(基于Binlog的异步或半同步),PolarDB-X标准版可以金融级容灾能力,满足机房级故障时,不丢任何数据(RPO=0)。
存储层:自研Lizard事务系统,对接日志层,可以替换传统MySQL InnoDB的单机事务系统,分别设计了SCN单机事务系统和GCN分布式事务系统来解决这些弊端,可以满足集中式和分布式一体化的事务优化,同时PolarDB-X标准版基于SCN单机事务系统可以提供完全兼容MySQL的事务隔离级别。
执行层:类似于MySQL的Server层,自研xRPC Server可以对接PolarDB-X企业版的分布式查询。同时为完全兼容MySQL,也提供兼容MySQL Server的SQL执行能力,对接存储层的事务系统来提供数据操作。
本文目标:在3台阿里云ECS上,通过 RPM 包快速部署三节点HA集群,并记录AI在全自动部署过程中踩过的每一个坑。
环境配置
节点 |
公网IP(管理) |
内网IP(集群通信) |
角色 |
规格 |
Node1 |
120.xx.xx.211 |
192.168.0.20 |
Leader |
4C8G,40G SSD |
Node2 |
121.xx.xx.241 |
192.168.0.19 |
Follower |
4C8G,40G SSD |
Node3 |
121.xx.xx.171 |
192.168.0.21 |
Follower |
4C8G,40G SSD |
- 操作系统:Alibaba Cloud Linux(兼容 CentOS 7/RHEL 7)
- 部署方式:RPM 一键安装
部署流程(标准路径)
理想的部署流程应该是这样的:
# Step 1: 访问polardb开源官网(openpolardb.com/download)下载RPM包到每台机器 wget -O /tmp/polardbx-engine.rpm \ "https://polar-db-prod.oss-cn-hangzhou.aliyuncs.com/...rpm" # Step 2: 安装RPM yum install -y /tmp/polardbx-engine.rpm # Step 3: 创建运行用户和数据目录 useradd -s /sbin/nologin -M polarx mkdir -p /data/polardbx/data /data/polardbx/tmp chown -R polarx:polarx /data/polardbx # Step 4: 生成 my.cnf(每台机器不同) # 见下文"细节四" # Step 5: 初始化数据目录(一次性) mysqld --defaults-file=/data/polardbx/my.cnf \ --initialize-insecure \ --cluster-info="192.168.0.20:3201;192.168.0.19:3201;192.168.0.21:3201@1" # Step 6: 启动服务(持久运行) mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize # Step 7: 验证集群状态 mysql -uroot -h127.0.0.1 -P3306 -e "SELECT * FROM INFORMATION_SCHEMA.ALISQL_CLUSTER_GLOBAL;"
但实际上,AI在执行这个流程时,也忽略了多个细节。
容易被忽略的细节
细节一:公网IP互不通——安全组的隐形墙
错误场景:三台机器之间使用公网IP配置 cluster-info,启动后集群始终无法建立共识。查询 ALISQL_CLUSTER_GLOBAL 返回空集。
排查命令:
# Node1 上测试连通性 ping 121.xx.xx.241 # ❌ 100% packet loss nc -zv 121.xx.xx.241 3201 # ❌ Connection timed out ping 192.168.0.19 # ✅ 0.1ms nc -zv 192.168.0.19 3201 # ✅ Connected
根本原因:阿里云ECS的公网IP之间默认不互通(安全组限制),但同VPC的内网IP完全互通。
错误配置:
# ❌ 错误:使用公网IP --cluster-info="120.55.84.211:3201;121.43.233.241:3201;121.40.252.171:3201@1"
正确配置:
# ✅ 正确:使用内网IP --cluster-info="192.168.0.20:3201;192.168.0.19:3201;192.168.0.21:3201@1"
经验教训:云环境部署三节点时,节点间通信务必使用内网IP。 公网IP仅用于外部客户端访问和管理。建议在部署前先用 ping 和 nc 验证三节点之间的网络连通性。
细节二:mysqld拒绝root启动——用户切换的细节
错误场景:安装RPM后,直接用 root 用户执行启动命令:
/opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize
结果进程启动后立即退出,日志中没有任何有效错误信息。直接用 mysqld 测试时才暴露真相:
[ERROR] Fatal error: Please read "Security" section of the manual to find out how to run mysqld as root!
根本原因:MySQL/PolarDB-X 出于安全考虑,禁止以 root 用户直接运行 mysqld。
正确做法:
# Step 1: 创建专用运行用户(所有节点执行) useradd -s /sbin/nologin -M polarx # Step 2: 数据目录授权(所有节点执行) mkdir -p /data/polardbx/data /data/polardbx/tmp chown -R polarx:polarx /data/polardbx # Step 3: 以 polarx 用户启动(注意!坑3与此相关) su -s /bin/bash polarx -c \ "/opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize"
经验教训:务必创建专用运行用户(如 polarx),并将数据目录权限授予该用户。 这是MySQL部署的基础要求,但在自动化脚本中很容易被忽略。
细节三:工作目录权限——su 继承的隐形陷阱
错误场景:在解决了坑2(创建polarx用户)之后,再次执行启动命令:
# 当前目录是 /root su -s /bin/bash polarx -c \ "/opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize"
结果报错:
mysqld_safe: line 513: cd: /root: Permission denied
根本原因:su -s /bin/bash polarx -c "cmd" 会继承当前shell的工作目录。如果当前在 /root 目录下执行,mysqld_safe 内部会尝试 cd /root,而 polarx 用户没有 /root 的访问权限,导致启动失败。
正确做法:
# ✅ 先切换到 polarx 用户有权限的目录,再启动 su -s /bin/bash polarx -c \ "cd /data/polardbx && /opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize"
经验教训:使用 su 切换用户启动服务时,务必先 cd 到目标用户有权限访问的目录。 建议统一使用 /data/polardbx 作为工作目录。
细节四:--initialize-insecure 不是启动命令
错误场景:执行初始化命令后,返回码为0,但 ps aux 中看不到任何 mysqld 进程,端口也没有监听。
/opt/polardbx_engine/bin/mysqld --defaults-file=/data/polardbx/my.cnf --initialize-insecure # 命令立即退出,echo $? = 0
排查过程:反复检查 my.cnf 配置、数据目录权限,都没有发现问题。最后才意识到——这个命令本来就是应该退出的。
根本原因:--initialize-insecure 是一个一次性数据目录初始化命令,它的作用是:
- 创建系统表(mysql、information_schema 等)
- 生成 root@localhost 用户(空密码)
- 初始化 InnoDB 数据文件
完成后,进程自动退出。它不是守护进程启动命令。
正确流程:
# Step 1: 初始化(一次性,执行完自动退出) su -s /bin/bash polarx -c \ "/opt/polardbx_engine/bin/mysqld --defaults-file=/data/polardbx/my.cnf --initialize-insecure --cluster-info='...'" # Step 2: 验证初始化成功 ls -la /data/polardbx/data/ # 应该看到 ibdata1、mysql 目录等29+个文件 # Step 3: 启动持久服务(mysqld_safe才是守护进程) su -s /bin/bash polarx -c \ "cd /data/polardbx && /opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize" # Step 4: 验证进程 ps aux | grep mysqld # 应该看到 mysqld 进程 ss -tlnp | grep 3306 # 应该看到 3306 端口监听
经验教训:--initialize-insecure 和 mysqld_safe --daemonize 是两个独立的步骤。 初始化完成后,必须单独执行启动命令才能建立持久服务。很多开发者误以为初始化命令会同时启动服务。
细节五:缺失 libncurses.so.5——RPM安装的隐形依赖
错误场景:集群启动成功,进程和端口都正常。但尝试用 mysql 客户端连接时:
/opt/polardbx_engine/bin/mysql -uroot -h127.0.0.1 -P3306 # 报错:error while loading shared libraries: libncurses.so.5: cannot open shared object file
根本原因:RPM包是在 CentOS 7 / Alibaba Cloud Linux 环境下编译的,依赖 libncurses.so.5。但现代系统默认安装的是 ncurses 6.x,只提供 libncurses.so.6,缺少兼容版本的 .so.5。
解决方案:
# CentOS / RHEL / Alibaba Cloud Linux yum install -y ncurses-compat-libs # 验证 ls -la /lib64/libncurses.so.5 # 应该存在
经验教训:RPM安装后,务必检查动态库依赖。 可以通过 ldd /opt/polardbx_engine/bin/mysql | grep "not found" 快速检查缺失的库。
细节六:cluster-info 中的分号截断远程命令
错误场景:通过SSH远程执行初始化命令时,因为 cluster-info 包含分号 ;,导致命令被shell截断:
# 预期执行的命令: mysqld --initialize-insecure --cluster-info='ip1:3201;ip2:3201;ip3:3201@1' # 实际执行结果(分号被当作命令分隔符): mysqld --initialize-insecure --cluster-info='ip1:3201 # ip2:3201 被当作新命令执行,报错:command not found
根本原因:在通过SSH或脚本传递包含特殊字符(分号、引号、美元符号等)的命令时,多层shell的引号解析会导致命令被意外截断或变形。
解决方案——base64编码传递:
# 本地生成初始化脚本 cat > init.sh << 'EOF' #!/bin/bash /opt/polardbx_engine/bin/mysqld \ --defaults-file=/data/polardbx/my.cnf \ --initialize-insecure \ --cluster-info="192.168.0.20:3201;192.168.0.19:3201;192.168.0.21:3201@1" EOF # base64编码后通过SSH传递(避免引号解析问题) base64_script=$(base64 -w 0 init.sh) ssh root@192.168.0.20 \ "echo '$base64_script' | base64 -d > /tmp/init.sh && bash /tmp/init.sh"
经验教训:远程执行包含特殊字符的命令时,使用 base64 编码传递脚本是最可靠的方案。 这完全避免了多层shell引号解析的问题。
细节七:卸载不彻底——进程残留的"幽灵文件"
错误场景:第一次部署失败后执行了标准卸载流程:
mysqladmin shutdown rm -rf /data/polardbx rpm -e t-polardbx-engine
看起来干净利落?重新部署时发现磁盘空间不足,但 du -sh / 只统计到18GB,而 df -h 显示已用38GB。消失的20GB去哪了?
排查命令:
# 查看被删除但仍被进程占用的文件 lsof +L1 | grep polarx # 输出示例: # mysqld 39258 polarx 3u REG 253,3 12582912 /data/polardbx/data/ibdata1 (deleted) # mysqld 39258 polarx 4u REG 253,3 50331648 /data/polardbx/data/undo_001 (deleted) # ... 共约20GB
根本原因:mysqld 进程被 polarx 用户启动,即使数据文件被 rm -rf 删除,只要进程还在运行,文件描述符就继续占用磁盘空间。Linux 中这叫"已删除但仍被打开的文件(deleted-but-open files)"。
正确卸载流程:
# Step 1: 优雅停止服务 mysqladmin -uroot -h127.0.0.1 -P3306 shutdown # Step 2: 强制终止运行用户的所有残留进程 pkill -9 -u polarx # Step 3: 验证没有残留占用 lsof +L1 | grep -E 'polardbx|mysqld' # 如果输出为空,说明空间已释放 # Step 4: 删除数据目录和RPM rm -rf /data/polardbx rpm -e t-polardbx-engine # Step 5: 删除用户(可选) userdel polarx # Step 6: 验证磁盘空间释放 df -h
经验教训:卸载时务必终止运行用户(polarx)的所有进程,否则 rm -rf 删掉的只是文件入口,真正的磁盘块仍被进程持有。 建议在卸载脚本中加入 lsof +L1 检查,确认没有残留的已删除文件。
完整部署命令速查表
每台机器都需要执行的命令
# ========== Step 1: 下载并安装RPM ========== wget -O /tmp/polardbx-engine.rpm "<你的RPM下载链接>" yum install -y /tmp/polardbx-engine.rpm # ========== Step 2: 安装客户端依赖 ========== yum install -y ncurses-compat-libs # ========== Step 3: 创建用户和数据目录 ========== useradd -s /sbin/nologin -M polarx mkdir -p /data/polardbx/data /data/polardbx/tmp chown -R polarx:polarx /data/polardbx # ========== Step 4: 生成 my.cnf ========== # 注意:每台机器的 server_id 不同(1、2、3),其他配置相同 cat > /data/polardbx/my.cnf << 'EOF' [mysqld] server_id = 1 # Node2改为2,Node3改为3 datadir = /data/polardbx/data tmpdir = /data/polardbx/tmp socket = /data/polardbx/tmp/mysql.sock log_error = /data/polardbx/data/error.log port = 3306 # X-Paxos 配置 cluster_id = 1 cluster_info = '192.168.0.20:3201;192.168.0.19:3201;192.168.0.21:3201@1' # 性能配置(根据内存调整) innodb_buffer_pool_size = 2G max_connections = 500 # 日志配置 log_bin = /data/polardbx/data/mysql-bin binlog_format = ROW EOF # ========== Step 5: 初始化数据目录(一次性) ========== su -s /bin/bash polarx -c \ "/opt/polardbx_engine/bin/mysqld --defaults-file=/data/polardbx/my.cnf --initialize-insecure" # 验证初始化成功(应该有29+个文件) ls -la /data/polardbx/data/ # ========== Step 6: 启动服务 ========== su -s /bin/bash polarx -c \ "cd /data/polardbx && /opt/polardbx_engine/bin/mysqld_safe --defaults-file=/data/polardbx/my.cnf --daemonize" # 验证进程和端口 ps aux | grep mysqld ss -tlnp | grep -E '3306|3201'
部署验证:集群状态检查
在所有节点启动后,在 Leader 节点上执行验证:
-- 1. 查看版本 SELECT VERSION(); -- 结果:8.0.32-X-Cluster-8.4.19-20250825 -- 2. 查看本地角色(Leader上执行) SELECT * FROM INFORMATION_SCHEMA.ALISQL_CLUSTER_LOCAL; -- 结果:ROLE=Leader, CURRENT_LEADER=192.168.0.20:3201, SERVER_READY_FOR_RW=Yes -- 3. 查看全局拓扑(Leader上执行) SELECT * FROM INFORMATION_SCHEMA.ALISQL_CLUSTER_GLOBAL; -- 结果:3 rows,显示所有节点角色和匹配索引 -- 4. 查看复制健康状态 SELECT * FROM INFORMATION_SCHEMA.ALISQL_CLUSTER_HEALTH; -- 结果:LOG_DELAY_NUM=0, APPLY_DELAY_NUM=0, APPLY_DELAY_SECONDS=0 -- 5. 写入测试 CREATE DATABASE deploy_test; USE deploy_test; CREATE TABLE t1 (id INT PRIMARY KEY, msg VARCHAR(100)); INSERT INTO t1 VALUES (1, 'hello from leader'); -- 6. 在 Follower 节点上验证数据同步 -- 连接到 Node2 或 Node3 SELECT * FROM deploy_test.t1; -- 结果:(1, hello from leader) ✅
故障切换测试:关闭 Leader(Node1)的 mysqld 进程
- 观察 Node2/Node3 的
ALISQL_CLUSTER_LOCAL,约3秒内新 Leader 产生 - 新 Leader 可正常读写
- 原 Leader 重启后自动作为 Follower 重新加入集群
开发者部署检查清单
在部署前对照检查,避免踩坑:
检查项 |
命令/方法 |
预期结果 |
节点间网络连通性 |
|
全部通 |
共识端口开放 |
|
全部通 |
磁盘空间 |
|
剩余 ≥ 10GB |
内存 |
|
可用 ≥ 4GB |
运行用户 |
|
用户存在 |
数据目录权限 |
|
polarx:polarx |
RPM依赖 |
|
无输出 |
客户端依赖 |
|
文件存在 |