PolarDB-X 三种部署方式详解:从二进制到Docker与K8s的完整实践
2026/9/22 1:56:02 网站建设 项目流程

开头先交代一下背景。之前一直在用单机MySQL做业务,后来数据量上来,分库分表的诉求越来越强烈,就盯上了PolarDB-X。真正上手才发现,这套分布式数据库的部署路径比想象中多,docker、k8s、二进制部署这三种方式我前后都折腾了一遍,踩了不少坑,但也因此把它内部那几个核心角色之间的关系彻底搞明白了。这篇文章就把我完整的实操过程、关键原理和踩坑记录整理出来,给准备部署PolarDB-X的DBA、后端开发和SRE做个参考。

1. 部署PolarDB-X前,先搞懂它由哪些角色组成

1.1 GMS、CN、DN、CDC各自在集群里干什么

很多人拿到PolarDB-X第一反应是:这不就是 MySQL 换个壳吗?装一个实例然后用 MySQL 客户端连上去不就行了。这个想法对了一半,PolarDB-X 的通信协议确实兼容 MySQL,但它的底层架构完全不是单实例,而是由多个分布式角色协作组成的。

一个最小的 PolarDB-X 集群通常包含这几个角色:

  • GMS(Global Meta Service):全局元数据服务,负责管理整个集群的拓扑结构、库表元数据、权限信息、全局事务状态。它相当于整个集群的大脑,所有关于"这个表在哪些 DN 上有分片"的信息都存在这里。
  • CN(Compute Node):计算节点,用户接入的入口,负责接收 SQL、做语法解析、生成执行计划、把请求分发到对应的 DN 上,最后汇总结果返回给客户端。
  • DN(Data Node):数据节点,真正存储数据的组件,底层是一个兼容 MySQL 协议的存储引擎,支持多副本,数据按分片规则散落在多个 DN 上。
  • CDC(Change Data Capture):变更数据捕获服务,负责把事务日志解析成标准的 Binlog 流,供下游做数据同步或者增量订阅。

如果把 PolarDB-X 比作一个公司,GMS 是行政中枢,CN 是前台接待,DN 是各个业务部门,CDC 是给外部合作伙伴定期同步工作简报的接口人。任何一个角色挂了,集群的健康状态都会受影响,只不过影响面有大有小。

1.2 三种部署路径的本质区别:谁在管理这些角色

docker、k8s、二进制部署,说到底解决的是同一个问题:怎么把这个几个角色跑起来,并让它们互相发现、协同工作。区别在于"管理的尺度"和"出问题之后由谁来自动处理"。

二进制部署是进程级的,所有步骤都要自己来。下载压缩包、解压、改配置、启动等,连组件之间怎么注册、怎么发现,都得按顺序手动搞定。好处是你能看到每个进程的真实行为,对理解 PolarDB-X 内部机制帮助很大。

Docker 部署是容器级的,镜像里已经把所有角色的可执行文件、依赖库、运行环境都打包好了。用 docker-compose 定义好服务拓扑,一条命令就能拉起来。它对宿主机的依赖只剩下一个 Docker 引擎,隔离性和可移植性都更好。

K8s 部署是声明式资源级的,你只需要告诉 Kubernetes"我想要一个什么样的 PolarDB-X 集群",剩下的副本管理、故障转移、存储分配、网络暴露都由 Operator 自动完成。这是生产环境最推荐的方式,因为它把分布式数据库的运维复杂度压缩到了一次 apply。

1.3 为什么 etcd 在这套体系里这么重要

PolarDB-X 的组件之间不是靠静态 IP 配置文件互相连接的,而是通过 etcd 做服务发现。GMS、CN、DN 启动之后都会向 etcd 注册自己的地址和状态,CN 在处理用户请求时,需要实时从 etcd 查询当前集群里有哪几个 DN、路由信息是什么。这也是为什么无论用哪种方式部署,etcd 都是绕不开的前置组件。理解这一点,后面排查各种"连不上""找不到节点"的问题会轻松很多。

2. 二进制部署:手动拉起每个进程的实操记录

2.1 下载二进制包与前置依赖准备

二进制部署花的时间最长,但也是我收获最大的部分。先说环境,我用的是一台 4C8G 的 Linux 虚拟机,操作系统是 CentOS 7.9。这个配置跑一个最小集群刚刚好,如果内存只有 4G 会比较紧张,因为 GMS 和 CN 都是 Java 服务,光 JVM 堆就可能吃掉 4G 以上。

前置依赖有三个:JDK 8、etcd、MySQL 客户端。

# 安装 JDK 8 yum install -y java-1.8.0-openjdk # 下载 etcd 单节点版本用于测试 wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz tar zxvf etcd-v3.5.0-linux-amd64.tar.gz mv etcd-v3.5.0-linux-amd64 /opt/etcd

PolarDB-X 的二进制发布包主要分两部分。一部分是 polardbx-engine,也就是 DN 存储引擎,本质上是 MySQL 的一个分布式分支;另一部分是 polardbx-sql,里面同时包含 GMS 和 CN 这两个 Java 服务的启动脚本。到 GitHub Releases 页面下载对应版本即可,需要注意 release note 里会标明这个版本对应的 polardbx-engine 和 polardbx-sql 版本要配套使用,不要混搭。

2.2 启动 etcd 并验证服务发现

先启动 etcd,因为后面所有组件都要往这里注册。测试环境用单节点就行,生产环境至少三个节点起步。

/opt/etcd/etcd \ --name pxc-etcd-1 \ --listen-client-urls http://0.0.0.0:2379 \ --advertise-client-urls http://192.168.1.10:2379 \ --listen-peer-urls http://0.0.0.0:2380 \ --initial-advertise-peer-urls http://192.168.1.10:2380 \ --initial-cluster pxc-etcd-1=http://192.168.1.10:2380 \ --initial-cluster-state new

这里有一个非常关键的细节:advertise-client-urls 不能写 127.0.0.1。如果写了回环地址,etcd 自己在本机注册没问题,但其他机器上的 GMS、DN、CN 来查询时会拿到一个谁也访问不到的地址,导致集群之间互相发现不了。我第一次踩坑就栽在这里,CN 一直报"unable to fetch topology from meta storage",排查了很久才发现是 etcd 的 advertise 地址写错了。

启动后可以用 etcdctl 验证一下:

/opt/etcd/etcdctl --endpoints=http://192.168.1.10:2379 endpoint health

返回 healthy 就说明服务发现的基础设施已经就绪。

2.3 按顺序启动 GMS、DN、CN

启动顺序是有讲究的,大致是 etcd -> GMS -> DN -> CN。GMS 要先起来,因为 DN 注册时需要向 GMS 获取一些元数据信息;CN 最后启动,因为它启动时会去发现集群中已有的 GMS 和 DN。

GMS 启动命令大致如下:

cd /opt/polardbx-sql bin/start_gms.sh --port 3306 --etcd http://192.168.1.10:2379

DN 启动命令:

cd /opt/polardbx-engine bin/start_dn.sh --port 3307 --etcd http://192.168.1.10:2379

CN 启动命令:

cd /opt/polardbx-sql bin/start_cn.sh --port 8522 --etcd http://192.168.1.10:2379

每个组件启动后都会向 etcd 注册。等三个角色都起来后,用 MySQL 客户端连 CN 的 8522 端口验证:

mysql -h127.0.0.1 -P8522 -upolardbx_root -p123456

能连上之后,可以先建一个带分片键的测试表,验证分布式能力是否真的生效:

create database test_db; create table test_order ( id bigint not null auto_increment, user_id bigint not null, amount decimal(10,2), primary key(id), key idx_user(user_id) ) partition by hash(user_id) partitions 4;

如果这条建表语句能成功执行,说明 CN 已经把分片规则同步给各个 DN 了,分布式表是真的建出来了,不是单机模拟。

2.4 二进制部署常见的三个坑

第一个坑是 JVM 内存参数。GMS 和 CN 默认的 -Xmx 可能设得比较大,在 8G 内存的机器上同时跑三个角色,很容易因为内存不足导致进程被操作系统 OOM Kill。建议在启动脚本里显式指定 -Xmx2g 之类的小堆配置。

第二个坑是端口冲突。8522 是 CN 对外服务的默认端口,3306 是 GMS 的默认端口,3307 是 DN 的默认端口。如果你的机器上装了 MySQL 或者别的服务占了这些端口,启动会直接失败。部署前先用 ss -lntp 检查一下端口占用情况。

第三个坑是日志不落盘。很多启动脚本默认把日志输出到 nohup.out 或者某个固定的 logs 目录,但如果目录权限不对,进程可能启动了但日志写不进去,看起来像卡住了一样。遇到这种情况,先确认运行用户对 logs 目录有写权限,然后去看实际日志文件,而不是看终端输出。

3. Docker Compose 部署:一台机器快速跑起完整集群

3.1 all-in-one 镜像与 compose 编排

二进制部署太折腾,每次想快速验证一个功能都得先花半小时把环境搭起来。后来我发现官方提供了 all-in-one 的 Docker 镜像polardb/polardb-x,它把 GMS、CN、DN、CDC 全部封装在了同一个容器里,容器启动时会自动拉起这几个内部进程。这对本地开发来说非常友好。

我用的 docker-compose.yml 是这样的:

version: "3" services: polardb-x: image: polardb/polardb-x:latest container_name: polardb-x ports: - "8522:8522" - "8080:8080" environment: - MODE=dev volumes: - pxc-data:/data restart: unless-stopped volumes: pxc-data:

启动命令就一行:

docker compose up -d

然后看日志:

docker compose logs -f polardb-x

看到类似 "PolarDB-X is ready" 的日志输出,就可以连接了。

3.2 初始化与连接验证

连接方式跟二进制部署完全一样,还是通过 8522 端口:

mysql -h127.0.0.1 -P8522 -upolardbx_root -p123456

all-in-one 镜像的默认账号密码一般是polardbx_root/123456,具体以镜像文档的说明为准。

这个方案最方便的地方在于,Docker 镜像把二进制部署过程中所有容易出错的环节都屏蔽掉了。etcd 不需要自己装,JVM 参数不需要自己调,角色之间的启动顺序也不需要关心。对只是想体验 PolarDB-X 功能、验证业务代码兼容性的人来说,这是性价比最高的选择。

3.3 镜像下载慢和 Docker Desktop 虚拟化问题的处理

用 Docker 部署绕不开两个问题。第一个是镜像下载慢。polardb/polardb-x这个镜像体积不算小,如果是首次在本地拉取,可能会等很久。解决办法是配置镜像加速器,Docker Desktop、国内各大云厂商都提供加速地址,在 Docker 引擎配置里加上 registry-mirrors 就行。另外一个土办法是先在一台网络好的服务器上 docker pull 完,再 save 成 tar 包导到目标机器上。

第二个问题在 Windows 上比较常见。很多人在 Windows 用 Docker Desktop 启动时报错,提示 "virtualization support not detected" 或者 "Docker Desktop failed to start because virtualisation support wasn't detected"。这个问题的根源是 Hyper-V 或者 WSL2 没开启,进 BIOS 把 CPU 虚拟化打开,然后在 Windows 功能里启用"适用于 Linux 的 Windows 子系统"和"虚拟机平台",重启之后再启动 Docker Desktop 就正常了。

3.4 挂载与数据持久化建议

我特别想强调数据持久化这一点。docker-compose 里如果在 volumes 中只写了命名卷但容器内数据库目录没挂准,容器一重建数据就没了。我在测试时就干过这种事,辛辛苦苦建的表和数据,一条 docker compose down 再 up 全部清空,只能从头再来。

建议是把容器内的数据目录显式挂载到宿主机的一个固定目录,比如:

volumes: - /data/polardb-x:/data

这样即使容器被删了,宿主机上/data/polardb-x目录里的数据还在。实际操作时,先启动一次容器,用docker exec进去看看数据实际写在哪个路径,再修改挂载关系,这样最稳妥。

4. K8s 部署:用 Operator 管理有状态集群

4.1 为什么原生 Deployment 不适合 PolarDB-X 这类有状态应用

Docker 方式虽然省心,但它是单体容器,所有角色堆在一个容器里,没法独立扩缩容。比如业务增长需要把 CN 从 1 个扩到 3 个,Docker 方式没法优雅地做到。K8s 部署就能解决这个问题。

但直接用原生 Deployment 去跑 PolarDB-X 也不太合适。关键原因在于 PolarDB-X 的每个角色都有状态:DN 的数据要持久化到 PV 上,多副本之间要保证顺序启动,故障后要重新调度到可用节点。这些逻辑如果都自己写 K8s yaml,工作量巨大且维护成本极高。

官方提供的方案是 PolardbX Operator。它本质上是一个运行在 K8s 里的控制器,监听用户提交的PolarDBXCluster自定义资源,然后自动创建和管理对应的 StatefulSet、Service、PVC 等底层资源。

4.2 Helm 安装 Operator

前提是你已经有一套可用的 K8s 集群,并且安装了 Helm。用 Helm 安装 Operator 比较干净:

helm repo add polardbx https://polardb.github.io/polardb-operator helm repo update helm install polardbx-operator polardbx/polardb-operator -n polardbx-system --create-namespace

安装完成后确认一下:

kubectl get pods -n polardbx-system

看到 polardbx-operator-controller-manager 处于 Running 状态,说明 Operator 已经就绪。这里提醒一下,K8s 版本不要太老,我测试时用的是 1.24 版本,Operator 对太老的 K8s 版本兼容性不太好,有可能出现 CRD 注册失败的情况。

4.3 编写 PolarDBXCluster YAML

Operator 装好之后,创建一个 PolarDB-X 集群实例。下面是我测试用的最小 YAML:

apiVersion: polardbx.aliyun.com/v1 kind: PolarDBXCluster metadata: name: pxc-demo namespace: polardbx spec: topology: cn: replicas: 2 resources: limits: cpu: "2" memory: 4Gi dn: replicas: 2 resources: limits: cpu: "2" memory: 4Gi storage: class: local-path

注意spec.storage.class这个字段,它指定的是 K8s 集群里的 StorageClass。如果集群里没有可用的默认 StorageClass,PVC 会一直卡在 Pending 状态,Pod 也起不来。我自己就踩过这个坑,后来在 Kind 集群里装了一个 local-path-provisioner,并在 YAML 里显式指定,Pod 才正常调度。

应用 YAML:

kubectl apply -f pxc-demo.yaml

然后观察状态:

kubectl get polardbxcluster -n polardbx kubectl get pods -n polardbx

等 Pod 全部 Running,集群就创建成功了。整个过程中 Operator 会自动完成 GMS、CN、DN 的创建和初始化,不需要人工介入。

4.4 访问集群与常见故障排查

K8s 集群内部的 Pod 不是直接暴露给外部的,需要把 CN 的服务端口转发出来:

kubectl port-forward svc/pxc-demo-cn -n polardbx 8522:8522

然后在本机执行:

mysql -h127.0.0.1 -P8522 -upolardbx_root -p123456

排查问题最常用的三个命令:

# 看集群自定义资源状态 kubectl describe polardbxcluster pxc-demo -n polardbx # 看具体 Pod 日志 kubectl logs -f pxc-demo-cn-0 -n polardbx # 看 PVC 状态 kubectl get pvc -n polardbx

我遇到最多的故障场景是镜像拉取超时,也就是 Pod 状态显示 ImagePullBackOff。这种情况一般不是因为镜像不存在,而是 K8s 集群无法访问外网镜像仓库,或者没有配置 imagePullSecret。在离线环境部署时,需要先把镜像推到内网仓库,然后在 YAML 里把 image 字段改成内网地址,或者给 namespace 配置 imagePullSecret。

4.5 生产环境要额外关注的资源与调度设置

如果只是测试,上面的配置完全够用。但生产环境部署时,有几个细节必须处理。

一个是资源请求和限制。不要把 request 和 limit 写成一样的值,否则节点资源稍微紧张时,Pod 不会被合理挤占,可能导致调度失败。建议 request 设成实际使用量的 80%,limit 设成峰值。

另一个是节点亲和性。DN 是有状态节点,扩容和故障迁移时尽量让副本分布在不同节点上,避免同一个物理机挂掉导致多个副本同时不可用。可以在 YAML 里通过 nodeAffinity 或者 podAntiAffinity 控制,让同一个集群的 DN 副本分散部署。

还有一个是备份。Operator 只管集群的生命周期,不管数据备份。生产环境一定要在 K8s 外面配置周期性的数据备份和恢复演练,不要以为集群跑在 K8s 上就万事大吉了。

5. 三种部署方式怎么选:对比与建议

5.1 从安装速度、运维成本、故障恢复能力看差异

把三种方式放到一起对比,差异非常明显:

对比项二进制部署Docker ComposeK8s Operator
前置依赖JDK、etcd、各类系统库Docker 引擎K8s 集群 + Helm
安装速度慢,手动操作多快,一条命令拉起中等,取决于集群是否就绪
故障恢复手动查看日志、手动重启手动重启容器Operator 自动调度恢复
扩缩容能力难,需要手动加节点不可行,单容器固定角色支持 CN/DN 独立扩缩容
数据持久化本地目录,自己管理挂载卷,自己管理PVC 自动分配
适合场景学习原理、二次开发本地开发、功能验证生产环境、长期运行

从表格能看出来,三者的定位其实是完全不同的。二进制部署适合钻研原理,Docker 适合快速起步,K8s 才是真正面向生产环境的方案。

5.2 我推荐的场景选择

如果是想弄懂"CN 启动时是怎么发现 DN 的""GMS 挂了对集群有什么影响"这类问题,用二进制部署过一遍是最值得的。虽然过程繁琐,但你会对每个角色的职责有非常具象的认知。这个认知在以后排查任何分布式数据库问题时都会帮到你。

如果是日常写代码联调,需要一整套 MySQL 兼容的分布式环境,直接选 Docker Compose。不要在生产环境用这个方案,不是因为性能差,而是它把所有角色塞进一个容器,失去了分布式部署的意义,出了问题也不好隔离。

如果是要给业务提供长期稳定的数据库服务,生产方式选 K8s Operator。它把副本管理、故障恢复、存储分配都标准化了,后续扩容缩容、版本升级都有现成的路径。前提是你的团队有基本的 K8s 运维能力。

5.3 部署前通用检查清单:几个容易被忽略的细节

最后分享几个在三种部署方式下都适用的小细节,都是我实际踩过的:

第一,NTP 时间同步。分布式数据库对节点间的时间偏差很敏感,尤其是涉及事务、日志时间戳的场景。时间不一致会导致一些看起来毫无规律的问题,比如事务提交报错、binlog 位点错乱。部署前确保所有节点都配置了 NTP 同步。

第二,文件句柄限制。PolarDB-X 的数据节点和计算节点在并发高的时候会打开大量文件,系统默认的 ulimit 1024 肯定不够。在启动前检查一下 ulimit -n,如果是 1024,改到 65535 以上再部署。

第三,swap 的问题。Java 服务最怕内存被 swap 换出,GC 停顿会明显变大。如果条件允许,在部署节点上关闭 swap 或者把 swappiness 调得很低。很多诡异的性能问题,排查到最后都是 swap 导致的。

部署这套东西,一开始会觉得步骤多、概念多,但当你真正把三种方式都走一遍,你会发现 PolarDB-X 的架构设计其实非常清晰。我自己的体会是,第一次部署时踩的那些坑——端口冲突、etcd 地址写错、PVC 卡 Pending——才是最宝贵的经验。如果你现在正准备部署,建议从二进制或者 Docker 开始跑通一台机器,再考虑往 K8s 上迁移,这样每一步都有底。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询