0x01 前言

我博客建立之初的数据库只有一个,后来因为多次搬迁导致运行环境不断重建,虽然有定时备份,但还是担心数据库丢失。因此,我重新设计博客的架构,将前端、后端与数据库都分开并且建立多个副本。

我博客运行环境的2.0版本是master-slave架构,master放置在腾讯云广州区的VPS中,而slave则部署在我家里的服务器里。同时在这两个不同的服务器上分别运行独立的PHP环境,然后在香港的VPS上配置nginx反向代理,所有数据均通过SSH隧道加密。

为了降低腾讯云的费用支出,我家中服务器的优先级在香港VPS上的nginx upstream配置高于腾讯云,所以大部分请求都会转发到我家里。

但这有个问题,因为我家里的数据库是slave身份,数据更新不会同步到master上,所以我将Wordpress设置成读写分离,需要写库的请求则发送到腾讯云上。毕竟腾讯云的机房在广州,延迟一般在8ms,数据来回加上处理的时间大大增加了我博客的响应时间。

最终,我决定采用mariadb galera实现数据库同步复制的功能。

0x02 准备

mariadb galera的配置内容比较多,在这里我只根据我的实际情况简略配置,如果需要用在生产环境请无比详细了解相关信息。

mariadb galera至少需要2个mariadb服务器,2个以上会更好;该服务对网络也有一定的要求,下面我会针对类似我这种DDNS的情况作出说明,但建议在拥有固定IP或内网可达的情况下部署。

这对这次测试,我建立了2个虚拟机,分别命名为db-t1与db-t2:

我内部会自动将hostname注册到DNS服务器中,所以在下面的配置我都使用hostname代替IP,这代表该配置支持域名与IP地址。

0x03 安装

首先在两个节点上安装mariadb:

然后检查mariadb的状态:

默认情况下,mariadb服务会设为自动启动,但安装完成后并不会启动,所以需要手动启动并对两个节点进行初始化设定:

再次检查运行状态:

确认无误后执行以下命令:

完成后尝试使用mysql命令登入数据库:

确认正常后继续下一步配置。

0x04 master db-t1

第一个启动的节点所使用的命令和后续节点的启动命令有所不同,因为我这是全新安装配置,所以将第一个启动的节点称为master。

当使用中的集群出现脑裂现象或其他异常需要重启时,有一套不同的流程,这个在文章后面简单说明。

在db-t1上建立一个用于同步的账户,通过mysql登入数据库,然后执行以下命令:

然后确认二进制文件libgalera_smm.so的绝对路径:

最后准备配置信息:

配置信息中一些字段的含义如下:

  • wsrep_cluster_name:集群名称,各个节点需一致;
  • wsrep_cluster_address:集群节点IP或域名,可附带端口,默认端口为4567,如
    • gcomm://10.1.1.97
    • gcomm://10.1.1.97:4567
    • gcomm://db-t1.t.com
    • gcomm://db-t1.t.com:4567
  • wsrep_node_address:定义本节点的域名或IP,可附带端口,默认为4567;
  • wsrep_sst_receive_address:定义本节点接受传入请求的域名或IP,可附带端口,默认的端口根据wsrep_sst_method定义的快照传输方式的不同而不同;
  • wsrep_node_name:本节点名称,在集群中需唯一;
  • wsrep_sst_auth:快照传输方式的验证信息;
  • wsrep_sst_method:定义快照传输方式,一共有以下方式:
    • rsync:默认端口:4444
    • mysqldump:3306
    • xtrabackup
    • xtrabackup-v2
    • mariabackup
  • bind-address:数据库监听的IP地址

默认情况下,wsrep会监听TCP 4567端口,当有新节点加入时,新节点会通过wsrep_cluster_address中设定的节点信息,拉取该节点的信息。

当没有设定wsrep_node_address或wsrep_sst_receive_address,galera将监听数据库bind-address中设定的IP地址,如果没有设定bind-address,则监听默认的IP地址。

如果mariadb服务器有多个IP地址,则可以通过上面两个变量设定监听特定的IP地址或端口。例如在腾讯云环境中,系统中的IP地址为10开头的内网IP,公网请求则通过NAT的方式传入,此时就需要设定上面的两个变量,指定域名或公网IP,否则galera集群将无法正常工作。

如果内网IP可达,则无需设定上面两个变量。

wsrep_sst_method可以设定不同的数据库同步方式,默认是使用rsync,请根据实际情况设定并在防火墙中放行特定的端口。

完成配置信息的设定后,将其写入以下文件:

而后停止正在运行的mariadb服务:

最后通过以下命令启动集群的第一个节点:

注意!只是启动集群中的第一个节点需要只用以上命令启动,并且wsrep_cluster_address的值需要设定为’gcomm://’。

成功启动后使用以下命令检查服务是否正常:

在返还的表格中需要注意两个内容:

  • wsrep_cluster_size:集群节点数量
  • wsrep_ready:服务状态

如果wsrep_ready的值为OFF,请检查数据库日志,排查原因;如果为ON,则服务正常。

然后检查wsrep_incoming_addresses的值,可以发现第一个节点的信息为:db-t1.t.com:3306,也就是wsrep_sst_receive_address设定的值。

0x05 master db-t2

在完成初始化设定的db-t2上修改server.conf配置文件,填入以下内容:

因为这是集群中的第二个节点,只需要通过以下命令启动即可:

重启后,db-t2节点会通过db-t1.t.com的4567端口索取集群各个节点的信息,然后根据wsrep_sst_method中设定的同步方式访问db-t1.t.com:3306端口,同步完成后才算启动完成。

如果集群中的数据库较大,请耐心等待,完成后通过以下命令即可检查相关信息:

返还的表格中需要注意以下内容:

  • wsrep_cluster_size:集群节点数量;
  • wsrep_incoming_addresses:集群各个节点的SST地址与端口;
  • wsrep_local_state_comment:本节点的同步状态;
  • wsrep_ready:服务状态。

0x06 收尾

在启动第一个节点的时候,wsrep_cluster_address的值为:’gcomm://’,因此需要作出修改。

在修改之前需要确认集群至少有2个节点,并且集群状态正常,集群所有数据都已经完成同步。

在检查集群状态时返还的列表中找到wsrep_last_committed项,比对各个节点的值,如果第一个节点的值在集群中是最大的,请不要停止服务!

确认已经同步完成后,通过以下命令停止db-t1中的mariadb服务:

然后修改server.conf配置文件,将db-t2的地址填写到wsrep_cluster_address中:

因为集群中已经有节点正在运行,所以使用以下命令正常启动mariadb即可:

然后使用以下命令再次检查集群状态:

主要检查以下内容:

  • wsrep_cluster_size:集群节点数量;
  • wsrep_incoming_addresses:集群各个节点的SST地址与端口;
  • wsrep_local_state_comment:本节点的同步状态;
  • wsrep_ready:服务状态。

如果一切正常,那么就可以进行测试了。

0x07 测试

如果你的集群正处于使用的状态,那么wsrep_last_committed这个参数应该是有数值的,在测试前我们先检查,在db-t1上执行以下命令:

因此我的集群是全新的,所以数值为0,如果检查db-t2上的数值,会发现也是如此。

现在登入到db-t1的数据库,然后新建一个数据库与用户,并将该数据库授权给该用户:

此时再检查集群中db-t1的数据:

可以看到wsrep_last_committed已经发生了变化。

现在在db-t2上使用t1这个用户登入到数据库:

可以发现,在db-t1上新建的用户与数据库已经同步到db-t2服务器上了,然后再db-t2上检查集群状态,会发现数值与db-t1一致。

此时我们用t1这个用户在db-t2上的t1数据库里新建一个表:

然后再回到db-t1服务器里,检查该表是否完成建立:

如果再检查两者的wsrep_last_committed,会发现是一致的,如果不一致,则说明集群出现了问题。

0x08 结语

集群可以添加多个节点,在实际应用中,强烈建议至少要有一个节点处于高可用的环境中,这样才能保证集群不会崩溃,毕竟重新启动集群是非常繁琐的一件事。

如果集群出现异常,导致脑裂或其他异常,这时候就需要手动启动各个节点。首先停止所有节点,然后用防火墙屏蔽掉4567端口,逐一启动节点,分别检查节点中wsrep_last_committed的值,选取wsrep_last_committed值最大的节点作为master,使用以下命令启动:

最后逐一修改各个节点的防火墙,放行4567端口,如果有需要的话,还可以重启节点。

针对DDNS的环境会有很严重的问题,在DDNS环境中只能通过域名解析出IP获取当前的服务器公网IP。但解析工作会交由集群中的某个节点执行,而且一旦集群运行,该域名就不会再被解析,而是以IP地址的形式在集群中传播。

当DDNS的IP发生变化时,会产生集群崩溃的问题,我不知道是不是我配置有无还是别的原因,但在我测试过程中发现无法再DDNS环境中配置集群。

配置集群的时候建议使用固定的IP地址,如果是DDNS环境,则建议使用云服务或自建一个NAT网关或VPN网关,统一分配一个内网IP。