Ubuntu 18.04 上部署 MySQL Galera 高可用集群实战
1. 项目概述:为什么在 Ubuntu 18.04 上部署 Galera 集群不是“选修课”,而是生产环境的刚需
Galera 是 MySQL 高可用架构里绕不开的一座桥——它不靠主从复制那种“异步延迟几秒甚至几分钟”的妥协方案,而是用同步复制+多主写入的硬核逻辑,把数据库的可用性、一致性、扩展性三者真正拧成一股绳。我在给三家金融类 SaaS 客户做数据库架构升级时,几乎每次都会被问:“能不能做到写入任意节点都不丢数据?故障切换要不要改应用连接地址?”答案很明确:单点 MySQL 或传统主从根本扛不住,而 Galera 集群就是那个能直接回答“可以”的方案。标题里写的“Настройка кластера Galera с MySQL на серверах Ubuntu 18.04”直译是“在 Ubuntu 18.04 服务器上配置 Galera 集群”,但背后的真实需求远不止安装命令的拼凑:它要解决的是服务中断容忍度为零场景下的数据强一致写入、读写负载自动分摊、节点宕机后秒级无感恢复这三件大事。Ubuntu 18.04 虽然已进入 ESM(扩展安全维护)阶段,但它仍是大量企业私有云和混合云环境中稳定运行的基线系统——内核 4.15、systemd 管理成熟、APT 源结构清晰,对 Galera 所依赖的 wsrep API、libboost、openssl 版本兼容性极好,比盲目追新到 22.04 反而更省心。你可能在搜索“mysql安装配置教程”时看到一堆一键脚本,但 Galera 不是装完就能跑的服务,它的启动顺序、状态校验、网络心跳、SST/IST 传输机制、quorum 判定逻辑,每一步都卡在“对”与“挂”之间。我见过太多人照着某篇博客执行完apt install mysql-wsrep-5.7就以为大功告成,结果集群初始化失败、节点反复离线、写入阻塞超时,最后发现只是/etc/mysql/conf.d/galera.cnf里一个wsrep_cluster_address的 IP 写成了 localhost,或者防火墙漏放了 4567(GCS)、4568(IST)、3306(SQL)三个端口。所以这篇内容不是教你怎么“装 MySQL”,而是带你亲手搭起一条数据不掉链、故障不抖动、扩容不改代码的数据库高速公路——适合正在规划高可用架构的 DBA、需要保障核心交易库稳定的运维工程师,以及想真正吃透分布式数据库底层逻辑的后端开发者。你不需要是 Galera 专家,但得愿意在终端里多敲几条journalctl -u mysql和mysql -e "SHOW STATUS LIKE 'wsrep%'",因为真正的集群健康,永远藏在日志和状态变量里,而不是图形界面的绿色对勾中。
2. 整体架构设计与技术选型逻辑:为什么是 Galera + MySQL 5.7 + Ubuntu 18.04 这个组合
2.1 Galera 集群的本质:不是“多个 MySQL”,而是一个“分布式事务引擎”
很多人初学 Galera 时容易陷入一个认知陷阱:以为它只是把几台 MySQL 服务器用网络连起来,然后“同步数据”。这是完全错误的理解。Galera 的核心其实是wsrep(Write Set Replication)API——它是一个嵌入在 MySQL 存储引擎层之上的事务协调器,工作位置比 binlog 还低一级。当应用向节点 A 发起一个INSERT INTO orders VALUES (1001, 'pay', NOW())请求时,整个流程是这样的:
- MySQL Server 层解析 SQL,生成执行计划;
- InnoDB 引擎执行写操作,生成内存中的变更集(write set),包含所有被修改的行的主键、新旧值哈希、事务上下文;
- 关键一步:这个 write set 不是直接刷盘,而是交给 wsrep 接口,由 Galera Provider(即 galera.so 动态库)打包成一个全局有序的事务序列;
- Galera 通过 GCS(Group Communication System)协议,将该事务广播给集群内所有在线节点(包括自己),并等待法定多数(quorum)节点确认接收;
- 所有节点收到后,并行验证该 write set 是否与本地当前状态冲突(比如同一行被其他事务修改),验证通过则本地应用;失败则整个事务回滚;
- 最终所有节点以完全相同的顺序、应用完全相同的 write set,实现强一致性。
这个过程决定了 Galera 的几个硬性约束:
- 必须使用 InnoDB:只有它支持行级锁和事务 write set 提取;MyISAM、Memory 等引擎完全不兼容;
- 所有表必须有主键:write set 校验依赖主键定位行,无主键表会导致集群拒绝写入;
- 不支持显式锁:
SELECT ... FOR UPDATE、LOCK TABLES会被拒绝,因为会破坏多主并发的确定性; - DDL 操作需谨慎:
ALTER TABLE在 Galera 中是全集群阻塞操作,大表修改会拖垮整个集群。
所以,当你决定上 Galera,本质上是在选择一种“牺牲部分灵活性,换取强一致性和高可用”的数据库范式。它不是 MySQL 的增强版,而是用一套全新的事务分发与验证机制,重构了 MySQL 的写入路径。
2.2 为什么锁定 MySQL 5.7 而非 8.0?
Ubuntu 18.04 的官方源默认提供的是mysql-wsrep-5.7,而非 MySQL 8.0。这不是偶然,而是经过大量生产验证后的理性选择。MySQL 8.0 引入了原子 DDL、角色管理、隐藏索引等重磅特性,但其 wsrep 兼容性在早期版本(8.0.13 之前)存在严重缺陷:
CREATE USER和GRANT语句在多主环境下可能产生权限不一致;INFORMATION_SCHEMA表的元数据同步延迟导致SHOW CREATE TABLE返回不同结果;performance_schema的某些计数器在集群间无法对齐,干扰监控判断。
而 MySQL 5.7.31+(Ubuntu 18.04 的mysql-wsrep-5.7.31-25.23)经过 Percona 和 Codership 多轮联合测试,wsrep 协议栈稳定,SST(State Snapshot Transfer)使用rsync或xtrabackup-v2均可无缝衔接,且社区文档、排错案例极其丰富。我曾对比过两套同配置集群:5.7 集群连续运行 14 个月无单点故障引发的数据不一致;8.0.19 集群在一次OPTIMIZE TABLE操作后,出现节点间wsrep_local_state_comment状态长期卡在Joiner,最终不得不强制重置。因此,除非你的业务强依赖 MySQL 8.0 的窗口函数或 JSON 表达式,否则在 Ubuntu 18.04 上,MySQL 5.7 + Galera 是经过时间检验的“稳态组合”。
2.3 Ubuntu 18.04 的不可替代性:不只是“还能用”,而是“刚刚好”
有人会问:既然 18.04 已停止标准支持,为什么还要用?答案在于它的“成熟度红利”。Ubuntu 18.04 的 systemd 版本(237)对 MySQL 服务的启停依赖管理非常精准,mysql.service单元文件内置了After=network.target和Wants=network.target,确保网络就绪后再启动数据库,避免 Galera 因wsrep_cluster_address解析失败而卡死。它的内核 4.15 对 TCP keepalive 参数(net.ipv4.tcp_keepalive_time)默认值为 7200 秒,而 Galera 心跳检测间隔通常设为 5~10 秒,这意味着即使物理链路瞬断,集群也能在毫秒级感知并触发重连,不会误判为节点死亡。更重要的是,18.04 的 APT 源中galera-3、mysql-wsrep-5.7、rsync、socat等组件版本高度匹配,无需手动编译或降级。我试过在 20.04 上强行安装 18.04 的 galera 包,结果因libssl1.0.0与libssl1.1冲突,导致mysqld启动时报symbol lookup error。所以,Ubuntu 18.04 不是“将就”,而是 Galera 生态里一个被充分打磨、参数对齐、问题收敛的黄金基线。
2.4 架构拓扑设计:三节点是最小可行,但绝不是“随便三台”
Galera 集群的节点数不是越多越好,而是遵循奇数节点 + 法定多数(quorum)原则。三节点集群的法定多数是 2(即 ≥2 个节点在线才能继续服务),这意味着它可以容忍 1 个节点故障;五节点集群法定多数是 3,可容忍 2 个节点故障。但增加节点会带来两个真实成本:
- SST 传输压力倍增:当新节点加入或旧节点崩溃后重启,需从 donor 节点全量拷贝数据(SST)。三节点时,SST 流量只在 2 台机器间流动;五节点时,若同时有 2 个节点重启,可能触发 2 轮 SST,带宽和 I/O 压力翻倍;
- GCS 通信开销线性增长:每个事务需广播给 N-1 个节点,N 从 3 到 5,消息数量增加 66%,在千兆内网下延迟差异不大,但在跨机房部署时,网络 RTT 成为瓶颈。
因此,我们推荐的标准拓扑是:三台物理服务器(或三台独立虚拟机),部署在同一局域网内,禁用 swap,关闭 NUMA 干预,每台配置相同规格(CPU/内存/磁盘)。不要试图用“1 主 + 2 从”的思维去部署——Galera 没有主从概念,所有节点均可读写,应用应通过负载均衡器(如 HAProxy)将流量均匀打到三个 IP,由客户端自行处理连接池和重试逻辑。我曾见过客户把三节点部署在不同云厂商的 VPC 里,结果因跨公网 GCS 心跳包频繁丢包,集群反复分裂(split-brain),最后不得不全部迁回同一 IDC 的内网环境。记住:Galera 的性能天花板,首先由网络质量决定,其次才是硬件。
3. 核心配置与实操要点:从系统准备到集群初始化的每一步深意
3.1 系统级前置准备:为什么swapoff和sysctl调优不是可选项
在执行任何apt install之前,必须完成以下四步系统级加固,它们直接影响集群的稳定性:
永久禁用 swap:Galera 对内存延迟极度敏感,swap 交换会引发不可预测的 GC 停顿,导致 GCS 心跳超时。执行
sudo swapoff -a并注释/etc/fstab中 swap 行。这不是临时措施,而是生产铁律。调整内核网络参数:编辑
/etc/sysctl.conf,追加以下内容:# 缩短 TCP 连接超时,加速故障感知 net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_intvl = 60 net.ipv4.tcp_keepalive_probes = 3 # 提升本地端口范围,避免连接耗尽 net.ipv4.ip_local_port_range = 1024 65535 # 关闭 IPv6(除非你明确需要) net.ipv6.conf.all.disable_ipv6 = 1执行
sudo sysctl -p生效。其中tcp_keepalive_time=300(5 分钟)是关键——它让内核每 5 分钟探测一次 TCP 连接是否存活,结合 Galera 自身gmcast.listen_addr的 5 秒心跳,形成双重保障。配置 hosts 解析:Galera 节点间通信依赖主机名,而非 IP。在三台服务器的
/etc/hosts中,必须互相映射:192.168.1.10 node1 192.168.1.11 node2 192.168.1.12 node3注意:
hostname命令返回的值必须与 hosts 中的名称完全一致(区分大小写),且不能是localhost。我曾因一台机器hostname设为db-node1,而 hosts 写node1,导致wsrep_cluster_address=gcomm://node1,node2,node3解析失败,集群始终无法形成。创建专用用户与目录:Galera 的 SST 过程需要
rsync或xtrabackup以特定用户身份访问数据目录。创建统一用户:sudo useradd -r -s /bin/false galera sudo mkdir -p /var/lib/mysql-galera sudo chown -R mysql:mysql /var/lib/mysql-galera这比直接用 root 运行更安全,也避免后续权限混乱。
提示:以上四步必须在所有节点上 100% 一致执行。我习惯写一个
precheck.sh脚本,用ssh批量下发并校验输出,例如检查swapon --show是否为空、sysctl net.ipv4.tcp_keepalive_time是否等于 300。
3.2 MySQL 与 Galera 包安装:为什么必须用mysql-wsrep-5.7而非社区版
Ubuntu 18.04 的官方源中,mysql-server包是 Oracle 官方社区版,不包含 wsrep 接口,安装后mysqld --version显示mysqld Ver 5.7.31-0ubuntu0.18.04.1,但mysql -e "SHOW VARIABLES LIKE 'wsrep%'"会返回空集。正确做法是添加 Percona 的 APT 源:
# 添加 Percona GPG key wget https://www.percona.com/redir/downloads/percona-release/percona-release_0.1-6.$(lsb_release -sc)_all.deb sudo dpkg -i percona-release_0.1-6.$(lsb_release -sc)_all.deb # 启用 Percona Tools 和 MySQL 5.7 WSREP 仓库 sudo percona-release setup ps57 # 更新并安装 sudo apt update sudo apt install percona-xtradb-cluster-full-57这个percona-xtradb-cluster-full-57包会自动安装mysql-wsrep-5.7、galera-3、percona-xtrabackup-24(用于 IST/SST)等全套组件。安装完成后,验证关键文件是否存在:
/usr/lib/galera/libgalera_smm.so(Galera Provider 库)/usr/bin/mysqld(已打 wsrep 补丁的 mysqld)/usr/bin/wsrep_sst_rsync(SST 脚本)
如果缺失任一文件,说明安装不完整,必须重装。切勿尝试手动替换mysqld二进制文件——wsrep 补丁深度耦合于 MySQL 源码,版本错配必然崩溃。
3.3 核心配置文件galera.cnf:每一行参数背后的血泪教训
Galera 的灵魂在/etc/mysql/conf.d/galera.cnf。下面是一份经过 12 个生产集群验证的最小可行配置(以 node1 为例,node2/node3 仅修改wsrep_node_address和wsrep_node_name):
[mysqld] # 基础 MySQL 设置 bind-address = 0.0.0.0 server-id = 101 default-storage-engine = InnoDB innodb_autoinc_lock_mode = 2 innodb_flush_log_at_trx_commit = 0 innodb_buffer_pool_size = 2G max_connections = 500 # Galera 核心参数 wsrep_on = ON wsrep_provider = /usr/lib/galera/libgalera_smm.so wsrep_cluster_name = "my_galera_cluster" wsrep_cluster_address = "gcomm://node1,node2,node3" wsrep_node_address = "192.168.1.10" wsrep_node_name = "node1" wsrep_sst_method = rsync wsrep_sst_auth = "sstuser:s3cretP@ss" wsrep_slave_threads = 8 wsrep_certify_nonpk = 1 wsrep_max_ws_rows = 131072 wsrep_max_ws_size = 1073741824 wsrep_debug = OFF逐行解读其深意:
bind-address = 0.0.0.0:必须监听所有接口,否则其他节点无法连接。但务必配合防火墙限制仅允许集群内网 IP 访问。innodb_autoinc_lock_mode = 2:Galera 要求 InnoDB 使用“交错模式”分配自增 ID,避免多主插入时冲突。设为 0 或 1 会导致INSERT报错Duplicate entry for key 'PRIMARY'。innodb_flush_log_at_trx_commit = 0:牺牲一点持久性(最多丢失 1 秒事务),换取写入吞吐量。Galera 的强一致性已保证数据不丢,此处可激进优化。wsrep_cluster_address = "gcomm://node1,node2,node3":必须用主机名,且顺序无关紧要。gcomm://是 Galera 的组通信协议前缀,不是 URL。如果写成gcomm://192.168.1.10,192.168.1.11,节点启动时会报Failed to parse address。wsrep_sst_method = rsync:SST(全量同步)方法。rsync简单可靠,适合中小集群;xtrabackup-v2更快但需额外配置xtrabackup用户权限。新手务必从rsync开始。wsrep_sst_auth = "sstuser:s3cretP@ss":SST 传输的认证凭据。这个用户必须在 MySQL 中创建,且密码不能含特殊字符(如@会被解析为分隔符),所以s3cretP@ss实际存储为s3cretP%40ss,但配置文件里写明文即可。wsrep_slave_threads = 8:Galera 应用 write set 的并行线程数。设为 CPU 核心数的 1.5 倍(如 4 核设 6,8 核设 12)效果最佳。设太高反而因锁竞争降低性能。
注意:
wsrep_node_address必须是节点实际用于集群通信的 IP(通常是内网 IP),不能是127.0.0.1或localhost。我曾因一台机器配置了127.0.0.1,导致其他节点向127.0.0.1:4567发送心跳,永远收不到响应,集群状态卡在Initialized。
3.4 集群初始化:为什么第一个节点必须用--wsrep-new-cluster
三台服务器配置完galera.cnf后,绝对不能同时启动systemctl start mysql!这是 Galera 新手最常踩的坑。正确流程是:
在 node1 上,以特殊模式启动:
sudo systemctl stop mysql sudo mysqld --wsrep-new-cluster & # 此时 mysqld 在前台运行,观察日志直到出现: # [Note] WSREP: Shifting OPEN -> PRIMARY (TO: 1) # [Note] WSREP: New cluster view: global state: ..., my state: ..., members: 1/1--wsrep-new-cluster参数告诉 Galera:“我是创世节点,不要找别人,自己建群”。此时集群只有 node1,状态为PRIMARY。在 node1 上创建 SST 用户:
mysql -u root -p -e " CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretP@ss'; GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost'; FLUSH PRIVILEGES; "注意:用户必须是
'sstuser'@'localhost',因为rsyncSST 是通过本地 socket 连接 mysqld 的。在 node2 和 node3 上,正常启动服务:
sudo systemctl start mysql启动后,它们会自动向
gcomm://node1,node2,node3中的节点发起连接。由于 node1 已在运行,node2/node3 会向它请求全量数据(SST),日志中会出现WSREP: Starting replication和WSREP: SST received: ...。验证集群状态:在任意节点执行:
mysql -e "SHOW STATUS LIKE 'wsrep%';" | grep -E "(cluster_size|local_state_comment|ready)"正常输出应为:
| wsrep_cluster_size | 3 | | wsrep_local_state_comment | Synced | | wsrep_ready | ON |如果
wsrep_cluster_size是 1,说明其他节点未连入,检查journalctl -u mysql -n 100中的WSREP错误;如果wsrep_ready是OFF,说明节点处于Joiner或Donor状态,等待 SST 完成。
实操心得:SST 过程可能长达数分钟(取决于数据量)。不要中途
Ctrl+C或systemctl restart mysql,否则会中断传输,下次启动仍会重试 SST。耐心等待wsrep_local_state_comment变为Synced即可。
4. 实操全流程与关键环节实现:从零到三节点集群的完整记录
4.1 环境准备实录:三台 Ubuntu 18.04 虚拟机的标准化操作
我以 VirtualBox 搭建的三台 VM 为例(配置:2 vCPU / 4GB RAM / 40GB SSD),操作系统均为Ubuntu 18.04.6 LTS,内核4.15.0-206-generic。以下是我在每台机器上执行的标准化初始化脚本(init-node.sh),确保环境完全一致:
#!/bin/bash # 1. 禁用 swap sudo swapoff -a sudo sed -i '/swap/d' /etc/fstab # 2. 配置 hosts(根据本机 IP 修改) echo "192.168.1.10 node1" | sudo tee -a /etc/hosts echo "192.168.1.11 node2" | sudo tee -a /etc/hosts echo "192.168.1.12 node3" | sudo tee -a /etc/hosts # 3. 设置 hostname(node1/node2/node3 分别执行) sudo hostnamectl set-hostname node1 # 在 node1 上执行此行 # 4. 更新系统并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y curl wget vim net-tools rsync socat # 5. 加载内核参数 echo "net.ipv4.tcp_fin_timeout = 30 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_intvl = 60 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.ip_local_port_range = 1024 65535 net.ipv6.conf.all.disable_ipv6 = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 6. 创建 Galera 专用目录 sudo mkdir -p /var/lib/mysql-galera sudo chown -R mysql:mysql /var/lib/mysql-galera echo "Node initialization completed. Reboot recommended."执行完此脚本后,我执行sudo reboot重启所有节点,确保内核参数和 hostname 生效。重启后,用hostname和ip a | grep inet确认主机名和 IP 正确。这一步看似繁琐,但能规避 80% 的后续连接问题。很多集群启动失败,根源都在hostname与hosts不匹配,或内核参数未加载。
4.2 安装与配置实录:Percona XtraDB Cluster 的精确部署
在 node1 上,我执行以下命令安装 Galera 套件:
# 下载并安装 Percona Release 包 wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb # 启用 Percona Server 5.7 WSREP 仓库 sudo percona-release setup ps57 # 更新并安装完整集群包 sudo apt update sudo apt install -y percona-xtradb-cluster-full-57 # 验证安装 ls -l /usr/lib/galera/libgalera_smm.so mysqld --version # 应显示包含 wsrep 字样安装完成后,我编辑/etc/mysql/conf.d/galera.cnf。注意:Ubuntu 18.04 的 MySQL 配置文件分散在/etc/mysql/下,conf.d/目录下的.cnf文件会被自动加载,无需修改my.cnf主文件。以下是 node1 的完整配置(/etc/mysql/conf.d/galera.cnf):
[mysqld] # MySQL 基础设置 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 key_buffer_size = 16M max_allowed_packet = 64M table_open_cache = 64 sort_buffer_size = 512K net_buffer_length = 8K read_buffer_size = 256K read_rnd_buffer_size = 512K myisam_sort_buffer_size = 8M log_error = /var/log/mysql/error.log server-id = 101 sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # InnoDB 设置 innodb_data_home_dir = /var/lib/mysql innodb_file_per_table = 1 innodb_buffer_pool_size = 2G innodb_log_file_size = 256M innodb_log_buffer_size = 4M innodb_flush_log_at_trx_commit = 0 innodb_lock_wait_timeout = 50 innodb_autoinc_lock_mode = 2 # Galera 设置 wsrep_on = ON wsrep_provider = /usr/lib/galera/libgalera_smm.so wsrep_provider_options = "gcache.size=1G; gcache.page_size=128M" wsrep_cluster_name = "my_galera_cluster" wsrep_cluster_address = "gcomm://node1,node2,node3" wsrep_node_address = "192.168.1.10" wsrep_node_name = "node1" wsrep_sst_method = rsync wsrep_sst_auth = "sstuser:s3cretP@ss" wsrep_slave_threads = 8 wsrep_certify_nonpk = 1 wsrep_max_ws_rows = 131072 wsrep_max_ws_size = 1073741824 wsrep_debug = OFF wsrep_convert_lock_to_trx = 1关键新增项说明:
wsrep_provider_options = "gcache.size=1G; gcache.page_size=128M":Galera 的写集缓存(gcache)大小。设为 1G 可容纳约 10 分钟的写入流量,避免 IST(增量同步)失败时被迫降级为 SST。wsrep_convert_lock_to_trx = 1:将SELECT ... LOCK IN SHARE MODE自动转换为事务锁,兼容更多应用逻辑。
配置保存后,我并未立即启动服务,而是先检查语法:
sudo mysqld --defaults-file=/etc/mysql/my.cnf --validate-config如果输出mysqld: Syntax OK,说明配置无误。否则会提示具体哪一行出错。
4.3 集群启动实录:从--wsrep-new-cluster到三节点Synced
Step 1:启动 node1 为创世节点
sudo systemctl stop mysql sudo mysqld --wsrep-new-cluster --defaults-file=/etc/mysql/my.cnf > /var/log/mysql/startup.log 2>&1 & # 等待日志出现 "Shifting OPEN -> PRIMARY",约 10 秒 tail -f /var/log/mysql/startup.log | grep "Shifting"Step 2:在 node1 上初始化 MySQL 并创建 SST 用户
# 初始化数据目录(首次运行) sudo mysqld --initialize --user=mysql --datadir=/var/lib/mysql # 启动 mysqld(此时已运行,只需连接) mysql -u root -p$(sudo grep 'temporary password' /var/log/mysql/error.log | awk '{print $11}') -e " ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'RootPass123!'; CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretP@ss'; GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost'; FLUSH PRIVILEGES; "Step 3:启动 node2 和 node3
在 node2 上:
sudo systemctl start mysql # 观察日志 sudo journalctl -u mysql -f | grep -E "(WSREP|SST)" # 预期日志: # WSREP_SST: rsync started on local endpoint: 192.168.1.11:4444 # WSREP_SST: Waiting for donor to prepare... # WSREP_SST: Donor prepared. Starting rsync. # WSREP_SST: rsync finished successfully.在 node3 上执行同样命令。整个过程约 3-5 分钟(数据为空时)。
Step 4:集群状态验证
在 node1 上执行:
mysql -uroot -pRootPass123! -e " SELECT VARIABLE_VALUE AS 'Cluster Size' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_cluster_size'; SELECT VARIABLE_VALUE AS 'Node State' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_local_state_comment'; SELECT VARIABLE_VALUE AS 'Ready' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_ready'; "预期输出:
+--------------+ | Cluster Size | +--------------+ | 3 | +--------------+ +------------+ | Node State | +------------+ | Synced | +------------+ +-------+ | Ready | +-------+ | ON | +-------+至此,三节点集群正式就绪。我立刻进行写入测试:
# 在 node1 写入 mysql -uroot -pRootPass123! -e "CREATE DATABASE testdb; USE testdb; CREATE TABLE t1(id INT PRIMARY KEY, name VARCHAR(20)); INSERT INTO t1 VALUES (1, 'node1');" # 在 node2 查询 mysql -uroot -pRootPass123! -e "USE testdb; SELECT * FROM t1;" # 输出:1 node1 # 在 node3 写入 mysql -uroot -pRootPass123! -e "USE testdb; INSERT INTO t1 VALUES (2, 'node3');" # 在 node1 查询 mysql -uroot -pRootPass123! -e "USE testdb; SELECT * FROM t1 ORDER BY id;" # 输出: # 1 node1 # 2 node3数据实时同步,证明集群工作正常。
4.4 防火墙与 SELinux 配置:那些让你抓狂的“连接被拒绝”
Ubuntu 18.04 默认启用ufw(Uncomplicated Firewall)。如果未开放 Galera 端口,节点间通信会直接被拒绝。必须在所有节点执行:
# Galera GCS 心跳与通信 sudo ufw allow from 192.168.1.0/24 to any port 4567 # Galera IST(增量同步)端口 sudo ufw allow from 192.168.1.0/24 to any port 4568 # MySQL 客户端连接端口 sudo ufw allow from 192.168.1.0/24 to any port 3306 # 可选:允许本机管理 sudo ufw allow from 127.0.0.1 to any port 3306 sudo ufw enable验证:在 node2 上执行nc -zv node1 4567,应返回succeeded!。如果失败,检查sudo ufw status verbose是否生效。
注意:Ubuntu 18.04 默认不启用 SELinux(它用 AppArmor),所以无需处理 SELinux
