Galera Cluster是一个MySQL的Multi Master插件。简而言之,在多台服务器上配置好Galera Cluster以后,它们表现得像是同一个数据库,可同时读写,数据会自动同步。而且同步不需要低延迟的网络通信;它可以跨WAN工作。
简介
优点
- Multi-Master,所有节点均可写
- 可跨WAN工作,对延迟不敏感
- 可自举拓扑结构,节点会自动转发数据
- 自定义能力强
限制
- 只对InnoDB引擎有较好的支持,MyISAM尚在测试
- 默认配置的安全性不足(稍后会谈到)
- 需要较快的网速(因为每个节点启动需要完整同步一次数据)以及稳定的网络
- 选举机制
- 默认配置无法自举
同步技术
Galera基于选举机制,Cluster中已经同步上的多数节点组成的集合被称为PC(Primary Content)。
Galera的同步分为以下四个阶段:
- 读取配置文件,连接到第一个节点,从该节点获得cluster拓扑以及其余节点的连接数据
- 尝试连接某个PC节点,如果连不上,请求其它节点或尝试自动转发
- 向该PC节点请求一份完整的数据库dump,这个过程称为SST(State Snapshot Transfer)
- 进入增量同步模式,启动MySQL服务
Cluster拓扑设计
Cluster是一个运行时概念。一旦Cluster中多于半数的节点同下线,其余节点会认为自己和PC断开连接而拒绝bootstrap重新启动的新节点,整个Cluster就不复存在了,而重建过程需要下线所有节点。所以设计Cluster拓扑的时候要考虑以下几点:
- 最多有多少台节点会同时下线?这个数量严格不能多于半数。
- 如果节点之间不是full mesh连通,那么是否有可能有两条连接同时断开把cluster划分成元素个数均小于全集半数的三个子集?(如果你使用过IRC的话,可能比较熟悉net.split)
- 长期在线的节点数量必须是奇数,否则可能出现选举机制投票失败的情况。Galera提供了一个“假的”节点程序Galera Arbitrator,可以用于平衡节点数量以及自动转发数据,但是它自己并不存储完整的数据库。
一个显而易见的结论是,cluster需要至少三个节点。
祝你图论愉快。
安全性
SST过程可能没有任何鉴权或链路加密。在默认配置下,任何知道你数据库IP地址和SST端口的人都可以拿到你的数据库的完整dump。如果你的所有节点都在可信的LAN里面那么问题不大,不过如果数据库暴露在公网上的话,问题可就大了。这边推荐几种方法:
- 给所有的节点配置支持auto mesh的VPN,例如Tinc、DMVPN或ZeroTier,然后用防火墙阻止其余网络访问SST端口
- 通过自定义的SST脚本进行鉴权和加密
- 使用自签证书的TLS进行鉴权和加密(如果不想手工操作的话,ClusterControl有自动化部署方案)
集群配置
设计好Cluster以后,是时候来建立我们的第一个集群了。
在所有节点上安装数据库
MariaDB和Percona Server都默认带了Galera Cluster模块,我就不细说如何在MySQL上安装该模块了。在所有节点上安装MariaDB:
1 2 3 4 5 |
sudo apt-get install software-properties-common sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8 sudo add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://mirrors.tuna.tsinghua.edu.cn/mariadb/repo/10.2/ubuntu xenial main' sudo apt update sudo apt install mariadb-server mariadb-client |
(适用于Ubuntu 16.04,MariaDB 10.2,其余系统或数据库版本请参考官方文档。)
如果service自动启动了,那么先停止:
1 |
sudo systemctl stop mariadb |
Systemd用户请注意,由于节点启动时SST需要很长时间(数据库大的话可能长达几个小时),SST过程中service会处于starting状态,因此我们需要增加starting状态的超时时间:
1 2 3 |
sudo mkdir -p /etc/systemd/system/mariadb.service.d echo "[Service]\nTimeoutStartSec=36000\n" | sudo tee /etc/systemd/system/mariadb.service.d/galera.conf sudo systemctl daemon-reload |
配置第一个节点
第一个节点的启动过程和其余不一样,因为它将被强制设为PC。
新建文件 /etc/mysql/conf.d/galera.cnf ,填入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[mysqld] binlog_format=ROW default-storage-engine=innodb innodb_autoinc_lock_mode=2 # need to bind to non-local for sync bind-address=0.0.0.0 # Galera Provider Configuration wsrep_on=ON wsrep_provider=/usr/lib/galera/libgalera_smm.so # Galera Cluster Configuration wsrep_cluster_name="your_cluster_name" wsrep_cluster_address="gcomm://ip_1,ip_2,ip_3,..." # Galera Synchronization Configuration wsrep_sst_method=rsync wsrep_provider_options="pc.recovery=TRUE;debug=no;gcs.fc_debug=0;pc.wait_prim=no" # Galera Node Configuration wsrep_node_address="this_node_ip" wsrep_node_name="this_node_name" |
解释一下几个参数:
- wsrep_cluster_name :cluster的名字(任意字符串,整个cluster里的所有节点要设成一样)
- wsrep_cluster_address :格式为gcomm://后面加上它能连上的那部分节点IPv4,包括本机的(IPv6支持可能需要自己折腾一下),逗号分隔
- wsrep_sst_method :SST使用的方法;不同的方法的性能和副作用不同,也可能需要额外配置,参见官方文档,我这边使用了最简单的rsync
- wsrep_node_address :填写其它节点可以访问到的本机IP(本机只有一个网络端口的话可以不写这个选项;如果其它节点可能通过多个IP访问本机的话,写多个,逗号分隔)
- wsrep_node_name :一个字符串作为本节点标识符,其余节点可以用这个字符串找到本节点,需要全局唯一,里面可以有空格
然后启动第一个节点:
1 2 |
sudo galera_new_cluster sudo journalctl -xefu mariadb |
(仅Systemd;其余init用户参见文档)
半自动配置其余节点
首先用第一个节点的 /etc/mysql 覆盖其余节点的配置文件。建议这么做而不只是复制 galera.conf 的原因是,系统在安装数据库时会建立一个随机密码的用户用于对数据库执行一些定时清理任务,这个随机密码会被写在某个配置文件里(deb系是 /etc/mysql/debian.cnf ,其余发行版我不清楚),cluster起来以后数据库的用户密码会被同步过来,如果该用户在配置文件里的密码没一起更改,定时清理会失败。
每台机子上 galera.conf需要修改的内容如下:
-
- wsrep_cluster_address :如果这个节点只能连接到部分节点,那么只需要填写该部分节点的IP
- wsrep_node_address :本机IP
- wsrep_node_name :取一个独一无二的名字
- wsrep_sst_donor :如果这个节点到某些节点的网络特别好或者到某些节点的网络特别差,那么建议强制设置SST从哪台机子完成,语法为一个 wsrep_node_name的列表,逗号分隔,建议在最后加个逗号(表示如果找不到列表里的节点,那么尝试其余节点而不是报错退出,参见文档)
然后删除该机子上原有的数据库:
1 |
sudo rm -rf /var/lib/mysql/* |
最后启动节点:
1 2 |
sudo systemctl start mariadb --no-block sudo journalctl -xefu mariadb |
你会看到一系列SST日志。等到日志出现:
1 |
[Note] WSREP: Shifting JOINER -> JOINED (TO: xxxxxxx) |
说明SST结束,数据库开始工作了。
如果节点之间不是full mesh连接,请注意启动顺序。
集群维护
重启某一台节点
不需要特殊注意,重启即可。节点会重新进行SST。注意SST视方法的不同可能阻塞donor节点,需要考虑该过程对生产环境的影响。
重启cluster
前面说过了,cluster是个运行时概念。如果出现下列情况之一:
- 超过半数节点同时下线
- 网络断开导致所有尚互相连接的集群子集内节点数量均小于集群节点总数的半数
- 一台节点在启动时日志出现 [Warning] WSREP: Member x.0 (node_name) requested state transfer from '* any*', but it is impossible to select State Transfer donor: Resource temporarily unavailable
这意味着cluster已经消失了。这时候就需要人工重启集群。
首先需要找到数据库内容最全的节点。如果你能确定某个节点是数据最完整的,例如事实上只有某个节点有写入操作,那么可以不用找。否则在每台节点上查看 /var/lib/mysql/grastate.dat 文件,其内容大致如下:
1 2 3 4 5 |
# GALERA saved state version: 2.1 uuid: 906869e9-c508-11e7-880b-1e7862fdbb59 seqno: -1 safe_to_bootstrap: 0 |
找到 seqno 最大的那台节点,它上面有着最完整的数据库内容。( seqno 为 -1 意味着这个节点的MySQL没有graceful shutdown。)把该节点的 safe_to_bootstrap 改成 1 保存。然后把它作为第一台节点启动:
1 2 |
sudo galera_new_cluster sudo journalctl -xefu mariadb |
然后启动其余节点即可。如果节点之间不是full mesh连接,请注意启动顺序。
离线备份数据库
Galera Cluster可以很简单地离线备份数据库。启动一个节点专门用于备份,在需要备份时将该节点下线,完成备份后再启动该节点让它重新同步即可。
参考: