
開頭先交代一下背景。之前一直在用單機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 集群通常包含這幾個角色GMSGlobal Meta Service全局元數據服務負責管理整個集群的拓撲結構、庫表元數據、權限信息、全局事務狀態。它相當于整個集群的大腦所有關于這個表在哪些 DN 上有分片的信息都存在這里。CNCompute Node計算節點用戶接入的入口負責接收 SQL、做語法解析、生成執行計劃、把請求分發到對應的 DN 上最后匯總結果返回給客戶端。DNData Node數據節點真正存儲數據的組件底層是一個兼容 MySQL 協議的存儲引擎支持多副本數據按分片規則散落在多個 DN 上。CDCChange 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/etcdPolarDB-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-1http://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 --endpointshttp://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:2379DN 啟動命令cd /opt/polardbx-engine bin/start_dn.sh --port 3307 --etcd http://192.168.1.10:2379CN 啟動命令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: - MODEdev 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 -p123456all-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 wasnt 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 YAMLOperator 裝好之后創建一個 PolarDB-X 集群實例。下面是我測試用的最小 YAMLapiVersion: 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。如果集群里沒有可用的默認 StorageClassPVC 會一直卡在 Pending 狀態Pod 也起不來。我自己就踩過這個坑后來在 Kind 集群里裝了一個 local-path-provisioner并在 YAML 里顯式指定Pod 才正常調度。應用 YAMLkubectl 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 上遷移這樣每一步都有底。