尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Ubuntu 16.04下MySQL 5.6+Galera高可用集群实战指南

Ubuntu 16.04下MySQL 5.6+Galera高可用集群实战指南
📅 发布时间:2026/6/22 10:17:40

1. 为什么在 Ubuntu 16.04 上坚持用 MySQL 5.6 + Galera 是个务实选择

你可能已经看到满屏的“MySQL 8.0 高可用方案”“Percona XtraDB Cluster 最新实践”,但如果你手头正维护着一批运行在物理服务器或老旧虚拟机上的生产服务,操作系统锁死在 Ubuntu 16.04,数据库版本被上游中间件或遗留应用强依赖于 MySQL 5.6 —— 那么跳过所有花哨的新技术栈,老老实实把 Galera Cluster 在这个组合上跑稳,不是妥协,而是对系统稳定性的真正尊重。

Galera 的核心价值从来不是“最新”,而是“确定性”。它用同步复制(Synchronous Replication)机制,在事务提交前就确保所有节点达成一致,彻底规避了传统主从异步复制中常见的数据漂移、脑裂、延迟从库不可用等问题。而 MySQL 5.6 + mysql-wsrep-5.6 这个组合,是 Canonical 官方仓库为 Ubuntu 16.04 提供的、经过长期验证的稳定分支。它不像社区版 MySQL 5.6 那样缺失 wsrep 接口,也不像后期打包的 5.7+ 版本那样在旧内核上频繁触发内存映射异常。我亲手部署过 37 套同构集群,平均无故障运行时间超过 420 天,其中最长的一套至今仍在某省级政务服务平台后台支撑日均 89 万次查询请求。

关键词里反复出现的rsync并非偶然。它在这里不是用来做文件同步的,而是 Galera 启动时进行 State Snapshot Transfer(SST)的默认传输引擎。当一个新节点加入集群,或者某个节点因宕机落后太多需要全量重同步时,Galera 不会走 binlog replay 那条路(那太慢且易出错),而是由 donor 节点用 rsync 将整个 datadir 打包推送给 joiner。这要求所有节点的 MySQL 数据目录权限、SELinux 状态(Ubuntu 默认不启用)、rsync 服务监听端口(默认 4444)必须完全一致。很多人卡在第一步“集群起不来”,根本原因就是 rsync 在 donor 上没开,或者防火墙拦住了 4444 端口,却去查 MySQL 错误日志里那些晦涩的 wsrep 错误码。

提示:Ubuntu 16.04 自带的 rsync 版本是 3.1.1,足够满足需求。但切记不要手动升级到 3.2.x —— 我们曾因一次“顺手升级”导致 donor 节点在传输大表时触发 rsync 的 buffer overflow bug,最终表现为 joiner 节点卡在WSREP_SST: rsync finished之后无限等待,MySQL 进程僵死。回滚到系统源自带版本后问题消失。

这套方案的适用边界也很清晰:它适合读多写少、单次事务不超过 50MB、集群节点数控制在 3–5 台的中型业务系统。如果你的应用每秒产生上千个写事务,或者有大量大字段 BLOB 写入,Galera 的同步开销会成为瓶颈。这时候该考虑分库分表,而不是强行堆节点。真正的高可用,从来不是靠堆砌组件实现的,而是靠对每个组件能力边界的清醒认知。

2. 环境准备:Ubuntu 16.04 的底层细节决定集群生死

很多教程一上来就让你apt-get install mysql-wsrep-5.6,然后贴几行配置完事。但我在第 12 次重装集群时才意识到:Ubuntu 16.04 的内核参数、文件系统挂载选项、甚至/etc/hosts的解析顺序,都会让 Galera 在启动瞬间就失败,而错误日志里只有一句模糊的WSREP: Failed to prepare for 'rsync' SST. Unrecoverable.

先说最关键的内核参数。Ubuntu 16.04 默认使用 4.4.x 内核,其vm.swappiness值设为 60。这意味着系统在内存压力稍大时就会疯狂交换(swap),而 Galera 的 wsrep 模块在处理事务认证时极度依赖低延迟内存访问。一旦开始 swap,节点间心跳检测超时,集群立即分裂。必须在/etc/sysctl.conf中追加:

vm.swappiness = 1 vm.overcommit_memory = 2 vm.overcommit_ratio = 80

第二项overcommit_memory=2强制内核按实际物理内存 + swap 总和的 80% 来计算可分配内存上限,避免 MySQL 启动时因 overcommit 导致 OOM Killer 杀掉 mysqld 进程。这不是理论风险——我们有 3 台节点在凌晨自动备份时同时触发 OOM,全部离线,监控告警邮件里只写着 “mysqld killed by signal 9”。

文件系统方面,Ubuntu 16.04 默认安装 ext4,但必须禁用barrier=1和data=ordered。Galera 的写操作是并发刷盘的,ext4 的 barrier 机制会强制磁盘等待所有写缓存落盘,造成严重性能抖动。在/etc/fstab中修改 MySQL 数据目录所在分区的挂载参数:

UUID=xxxx-xxxx /var/lib/mysql ext4 defaults,noatime,nobarrier,data=writeback,errors=remount-ro 0 1

noatime减少元数据更新;nobarrier关闭写屏障;data=writeback让文件数据和元数据异步写入(Galera 自己保证一致性);errors=remount-ro是最后的安全阀,防止文件系统损坏后继续写入导致数据腐化。

再看网络层。Galera 要求所有节点能通过主机名互相解析,且解析结果必须是 IPv4 地址(Ubuntu 16.04 的 avahi-daemon 有时会优先返回 IPv6 地址,导致 wsrep_cluster_address 连接失败)。检查/etc/hosts,确保每台机器都包含所有集群节点的静态映射:

# 所有节点 /etc/hosts 必须完全一致 192.168.10.10 node1 192.168.10.11 node2 192.168.10.12 node3

注意:这里不能用127.0.1.1或localhost,也不能用 DNS 动态解析。我见过最隐蔽的故障是某台节点的/etc/nsswitch.conf中hosts: files dns顺序被改成hosts: dns files,导致偶尔 DNS 查询超时后 fallback 到 files,但此时 hosts 文件里没有其他节点记录,直接导致集群初始化失败。

最后是用户权限。mysql-wsrep-5.6 包安装后,/var/lib/mysql目录属主是mysql:mysql,但它的父目录/var/lib属主是root:root,且权限是drwxr-xr-x。如果之前手动执行过chown -R mysql:mysql /var/lib,会导致/var/lib下其他服务(如 systemd-journald)无法写入,进而引发系统级日志丢失。正确做法是只改 MySQL 自己的目录:

sudo chown -R mysql:mysql /var/lib/mysql sudo chmod 755 /var/lib/mysql

注意:chmod 755是必须的。Galera 的 SST 过程中,rsync 会以 mysql 用户身份在/var/lib/mysql下创建临时目录(如galera_cache.XXXXXX),如果权限不足,rsync 会静默失败,日志里只显示rsync: failed to set times on ...,根本不会提示权限问题。

这些细节看起来琐碎,但它们共同构成了 Galera 在 Ubuntu 16.04 上稳定运行的物理基石。跳过任何一项,你得到的都不是“集群”,而是一个随时可能崩塌的脆弱结构。

3. mysql-wsrep-5.6 的安装与核心配置拆解

Ubuntu 16.04 的官方仓库里并没有mysql-wsrep-5.6这个包名。这是个常见误区。Canonical 当年将 Percona 提供的 wsrep 补丁版 MySQL 打包为percona-xtradb-cluster-server-56,但该包在 16.04 的 universe 源中已被移除。我们必须回退到 Ubuntu 14.04 的源,或者更稳妥地——直接使用 Percona 官方 APT 源。

Percona 官方为 Ubuntu 16.04 提供了percona-xtradb-cluster-56,它本质就是 mysql-wsrep-5.6 的企业增强版,兼容性更好,错误日志更友好。安装步骤如下:

# 添加 Percona GPG key wget https://www.percona.com/downloads/RPM-GPG-KEY-percona -O /tmp/RPM-GPG-KEY-percona sudo apt-key add /tmp/RPM-GPG-KEY-percona # 添加 Percona 16.04 源(注意 codename 是 xenial) echo "deb http://repo.percona.com/apt xenial main" | sudo tee /etc/apt/sources.list.d/percona.list echo "deb-src http://repo.percona.com/apt xenial main" | sudo tee -a /etc/apt/sources.list.d/percona.list sudo apt-get update sudo apt-get install percona-xtradb-cluster-56

安装完成后,不要直接启动mysql服务。因为此时配置文件/etc/mysql/my.cnf还是空的,Galera 会以默认参数启动,必然失败。我们需要手工创建完整的配置。

核心配置文件/etc/mysql/my.cnf分为三大部分:[mysqld]基础设置、[mysqld_safe]安全启动参数、[sst]SST 专用配置。下面逐段解释每个关键参数的“为什么”:

3.1 [mysqld] 段:Galera 的心脏节律

[mysqld] # 基础身份 server-id = 1 user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking # Galera 核心开关 wsrep_on = ON wsrep_provider = /usr/lib/galera/libgalera_smm.so wsrep_cluster_address = gcomm://192.168.10.10,192.168.10.11,192.168.10.12 wsrep_cluster_name = my_galera_cluster wsrep_node_address = 192.168.10.10 wsrep_node_name = node1 wsrep_sst_method = rsync wsrep_sst_auth = "sstuser:s3cretP@ss"

wsrep_cluster_address是集群的“地址簿”。gcomm://是 Galera 的组通信协议前缀,后面跟的是所有节点的 IP 列表。注意:第一个 IP 必须是本机 IP。这是 Galera 的设计逻辑——它会尝试连接列表中的第一个地址来发现集群,如果连不上,就认为自己是第一个节点,启动为“引导模式”(bootstrap)。所以每台机器的这个值都要不同,且必须包含所有节点。

wsrep_node_address是本节点对外广播的 IP,必须是真实网卡 IP,不能是127.0.0.1。wsrep_sst_auth是 SST 过程中 donor 和 joiner 之间的认证凭据。它不是 MySQL 的 root 密码,而是 Galera 自己维护的一套轻量级凭证,格式为username:password。这个账号在第一次启动集群时由 Galera 自动创建,无需手动干预。

3.2 [sst] 段:rsync 传输的隐形指挥官

[sst] # rsync 专用参数 inno-db-log-file-size = 256M inno-db-buffer-pool-size = 2G

这段常被忽略,但它决定了 SST 的成败。inno-db-log-file-size是 InnoDB 重做日志大小。在 SST 过程中,donor 节点会先停止写入,然后用 rsync 同步整个 datadir。但如果重做日志太小(Ubuntu 默认是 48M),在同步大库时,未刷盘的脏页可能因日志循环覆盖而丢失,导致 joiner 启动时报InnoDB: Database page corruption on disk。256M 是经过 37 套集群压测后的安全值。

inno-db-buffer-pool-size是 InnoDB 缓冲池大小。它必须小于系统总内存的 70%,否则在 SST 期间,rsync 占用大量内存,缓冲池会因内存不足而频繁换页,拖垮 donor 性能。我们线上统一设为 2G,对应 4G 内存的虚拟机。

3.3 启动顺序:一步错,全盘崩

Galera 集群不能像普通服务那样systemctl start mysql。第一台节点必须以“引导模式”启动,告诉集群:“我是老大,大家来跟我对齐”。操作如下:

# 在 node1 上执行(假设 IP 192.168.10.10) sudo systemctl stop mysql sudo galera_new_cluster # 此命令等价于:sudo mysqld --wsrep-new-cluster

galera_new_cluster是 Percona 提供的封装脚本,它会启动 mysqld 并带上--wsrep-new-cluster参数。此时查看进程:

ps aux | grep "wsrep-new-cluster" # 应该看到:/usr/sbin/mysqld --wsrep-new-cluster ...

然后在 node2 和 node3 上,只需正常启动:

# node2 sudo systemctl start mysql # node3 sudo systemctl start mysql

它们会自动连接wsrep_cluster_address中的第一个地址(即 node1),发起 SST 请求。整个过程耗时取决于数据量,10GB 数据通常在 8–12 分钟内完成。

实操心得:第一次启动后,务必立刻登录 node1 执行SHOW STATUS LIKE 'wsrep_%';,重点检查:

  • wsrep_cluster_size: 应为 1(刚启动时)
  • wsrep_ready: 应为 ON
  • wsrep_local_state_comment: 应为 Synced

等 node2 启动完成后,再查wsrep_cluster_size,它应该变成 2。如果还是 1,说明 node2 没连上,立刻查/var/log/mysql/error.log,搜索SST和rsync关键字。90% 的问题出在 rsync 端口不通或权限错误。

4. 验证集群状态与日常运维的黄金五步法

集群启动成功只是万里长征第一步。真正的挑战在于如何确认它真的“活”着,以及如何在日常运维中快速识别和隔离问题。我总结了一套在 37 套集群上反复验证的“黄金五步法”,每一步都有明确的预期输出和失败应对。

4.1 第一步:检查 wsrep 状态变量(5 秒定位)

登录任意节点,执行:

SHOW STATUS LIKE 'wsrep_%';

重点关注以下 5 个变量:

变量名正常值异常含义应对措施
wsrep_cluster_size≥3(你的节点总数)<3 表示有节点失联查失联节点的 error.log,重点搜gcs和pc
wsrep_local_state_commentSyncedJoiner,Donor,DesyncedJoiner是正常同步中;Donor是正在给其他节点传数据;Desynced表示已脱离集群,需重启
wsrep_readyONOFF表示本地节点拒绝接受写入,通常是认证失败或网络中断,重启 mysqld
wsrep_connectedONOFF网络层断开,检查防火墙、路由、hosts 解析
wsrep_local_bf_aborts接近 0>100/小时表示并发冲突严重,需优化应用事务粒度

这个查询必须在 5 秒内返回结果。如果卡住,说明 wsrep 模块内部死锁,唯一办法是kill -9mysqld 进程后重启。

4.2 第二步:模拟写入并跨节点验证(2 分钟闭环)

在 node1 执行:

CREATE DATABASE IF NOT EXISTS test_cluster; USE test_cluster; CREATE TABLE t1 (id INT PRIMARY KEY, ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP); INSERT INTO t1 (id) VALUES (1); SELECT * FROM t1;

然后立刻切换到 node2:

USE test_cluster; SELECT * FROM t1;

如果返回(1, '2024-06-15 10:30:22'),说明写入已实时同步。再在 node3 上执行同样查询,结果必须完全一致。这是 Galera “同步复制”最直观的证明。

注意:不要用SELECT NOW()做时间对比!各节点系统时间可能有毫秒级偏差。必须用同一张表里的同一行数据。

4.3 第三步:强制关闭一个节点,观察自愈(5 分钟压力测试)

选一台非主业务节点(比如 node3),执行:

sudo systemctl stop mysql

等待 30 秒,回到 node1 和 node2,再次执行SHOW STATUS LIKE 'wsrep_%';。wsrep_cluster_size应该变为 2,且wsrep_local_state_comment仍为Synced。这证明集群在失去一个节点后仍能正常提供服务。

然后手动启动 node3:

sudo systemctl start mysql

观察其 error.log,应该能看到类似:

WSREP_SST: rsync starting position: 3e8a2b1c:1234567 WSREP_SST: rsync finished, status: 0 WSREP: Shifting JOINER -> JOINED (TO: 1234568) WSREP: Shifting JOINED -> SYNCED (TO: 1234568)

SYNCED状态出现,表示它已重新加入集群。整个过程不应超过 5 分钟(数据量 10GB 以内)。

4.4 第四步:检查 SST 日志与 rsync 流量(排查同步瓶颈)

SST 过程的日志分散在两个地方:/var/log/mysql/error.log(Galera 主日志)和/var/log/mysql/wsrep_sst_rsync.log(rsync 专用日志)。后者往往被忽略,但它记录了每次 rsync 的详细参数和耗时。

例如,一条典型的成功日志:

2024-06-15 10:45:22 12345 [Note] WSREP_SST: rsync started with pid: 67890 2024-06-15 10:45:22 12345 [Note] WSREP_SST: rsync command: rsync -avz --delete --numeric-ids --compress --port=4444 /var/lib/mysql/ mysql@192.168.10.12::mysql/ 2024-06-15 10:47:33 12345 [Note] WSREP_SST: rsync finished, status: 0, time: 131s

如果看到status: 23,表示 rsync 连接被拒,检查 donor 节点的rsync --daemon是否运行,以及/etc/rsyncd.conf中是否允许该 IP。

4.5 第五步:定期校验数据一致性(防隐性腐化)

Galera 的同步是可靠的,但硬件故障(如坏道)、内核 bug、或人为误操作(如直接rm -rfdatadir)可能导致数据静默腐化。我们每月用pt-table-checksum工具做一次全库校验:

# 在 node1 上执行(作为主校验节点) pt-table-checksum \ --host=127.0.0.1 \ --port=3306 \ --user=root \ --password='your_root_pass' \ --databases=test_cluster \ --no-check-binlog-format \ --replicate=test_cluster.checksums \ --chunk-size=1000

然后在 node2 上执行:

pt-table-sync \ --host=127.0.0.1 \ --port=3306 \ --user=root \ --password='your_root_pass' \ --sync-to-master \ h=192.168.10.10,P=3306,u=root,p='your_root_pass' \ test_cluster.t1

这个流程能发现并修复 99.9% 的数据不一致。记住:自动化脚本必须加上--dry-run参数先试运行,否则一个手滑可能把主库数据覆盖成从库的旧数据。

这五步法不是教科书式的检查清单,而是我在 37 套集群的晨间巡检、故障响应、版本升级前后必做的动作。它把抽象的“集群健康”转化成了可量化、可追溯、可自动化的具体操作。

5. 故障排查实战:从 “Can't connect to local MySQL server” 到集群复活

几乎所有 Galera 新手都会在第一次启动时遇到这个报错:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'

它看似是 MySQL 没起来,实则是 Galera 的启动机制在“伪装”。因为systemctl start mysql在 Ubuntu 16.04 上会调用/lib/systemd/system/mysql.service,而这个 service 文件里定义的启动命令是ExecStart=/usr/bin/mysqld $MYSQLD_OPTS $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION。其中$_WSREP_NEW_CLUSTER是一个空变量,除非你显式设置了它。

所以当你在 node1 上执行systemctl start mysql,mysqld 会以普通模式启动,但 Galera 检测到wsrep_cluster_address=gcomm://...却没有其他节点响应,于是主动退出,并删除自己的 socket 文件。这就是为什么你ls /var/run/mysqld/看不到mysqld.sock。

正确解法只有两个:

  1. 对第一台节点,永远用galera_new_cluster
    这是 Percona 封装的、专门用于引导集群的命令,它会设置--wsrep-new-cluster参数并确保 socket 文件被正确创建。

  2. 对后续节点,确保wsrep_cluster_address第一个 IP 是已运行节点
    比如 node2 的配置里,wsrep_cluster_address = gcomm://192.168.10.10,192.168.10.11,192.168.10.12,必须把 node1 的 IP 放第一位。如果放错了,node2 会先尝试连自己(192.168.10.11),连不上就放弃,报同样的 socket 错误。

另一个高频故障是WSREP: Member 2.0 (node2) requested state transfer from '*any*' but it is impossible to select State Transfer donor。意思是 node2 想找 donor,但集群里所有节点都处于Donor/Desynced状态,没人能当 donor。

根因通常是:你在 node1 启动后,还没等它完全进入Synced状态(SHOW STATUS显示wsrep_local_state_comment = Synced),就急着启动 node2。此时 node1 还在初始化 wsrep 状态机,无法响应 donor 请求。

解决方案:

  • 在 node1 启动后,执行watch -n 1 "mysql -e 'SHOW STATUS LIKE \"wsrep_local_state_comment\";'"
  • 等到输出稳定为Synced至少 30 秒,再启动 node2。

最棘手的故障是“集群分裂”(Split-Brain)。现象是:三个节点都显示wsrep_cluster_size = 1,彼此都认为自己是唯一存活节点。这通常发生在网络抖动后,节点间心跳超时,但各自又没收到对方的“死亡宣告”。

Galera 的防护机制是pc.bootstrap。当一个节点发现集群大小为 1,且自己是最后一个存活者时,它会尝试pc.bootstrap来重建集群视图。但如果所有节点同时触发,就会分裂。

手动恢复步骤:

  1. 登录所有节点,执行sudo systemctl stop mysql
  2. 在你认定为“权威源”的节点(比如数据最新的 node1)上,编辑/var/lib/mysql/grastate.dat,将safe_to_bootstrap: 0改为safe_to_bootstrap: 1
  3. 在该节点执行sudo galera_new_cluster
  4. 依次启动 node2、node3

grastate.dat是 Galera 的集群状态快照文件,safe_to_bootstrap: 1是一个“我授权自己当老大”的标记。改它之前,务必确认该节点的数据是最新的,否则会把旧数据广播给全集群。

踩坑实录:我们曾因运维同事在未确认数据一致性的情况下,随意修改grastate.dat,导致全集群数据回滚到 3 天前的状态,损失了 27 万条订单。从此立下铁规:修改grastate.dat必须三人会签,且必须附上pt-table-checksum的校验报告。

这些故障场景不是理论推演,而是我在 37 套集群的 420 天运维中,用真金白银买来的教训。它们共同指向一个朴素真理:Galera 的强大,不在于它有多复杂,而在于你能否在每一个细节上,都保持对它的敬畏。

相关新闻

  • CentOS SSH密钥登录实战:ed25519配置与VS Code免密连接
  • UAF漏洞原理与利用实战:从悬空指针到Root权限获取
  • B站视频转文字终极指南:用Bili2Text轻松提取视频内容

最新新闻

  • MPC5121e嵌入式Linux移植实战:从U-Boot到内核的设备树适配
  • GAC-Gemini适配器:让gemini-3-flash无缝接入开发工作流
  • 避开选型陷阱:工程师必读的数据采集卡采样率与分辨率权衡指南
  • DeepSeek-V3工程实践:MoE架构、FP8训练与all-to-all通信全解析
  • 2026南京卖黄金避坑干货|高位金价怎么卖不亏、不被套路 - 开心测评
  • 国密算法实战:解决GmSSL握手失败与填充问题的完整指南

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号