MySQL - Galera集群

MySQL   2025-01-12 15:19   507   0  

一、Galera-Cluster 的介绍

Galera Cluster 是 Codership 公司开发的一套免费开源的高可用方案,官网为 http://galeracluster.com。
Galera Cluster 即为安装了 Galera 的 Mariadb 集群(本文只介绍 Mariadb Garela 集群)。
其本身具有 multi-master 特性,支持多点写入。
Galera Cluster 的三个(或多个)节点是对等关系,每个节点均支持写入,
集群内部会保证写入数据的一致性与完整性,具体实现原理会在本篇中做简要介绍。

官方给出的特性如下:

  • 真正的多主集群,Active-Active 架构;

  • 同步复制,没有复制延迟;

  • 多线程复制;

  • 没有主从切换操作,无需使用虚 IP;

  • 热备份,单个节点故障期间不会影响数据库业务;

  • 支持节点自动加入,无需手动拷贝数据;

  • 支持 InnoDB 存储引擎;

  • 对应用程序透明,原生 MySQL 接口;

  • 无需做读写分离;

  • 部署使用简单。

二、Galera-Cluster 的运行原理

主要关注点是数据一致性。 事务既可以应用于每个节点,也可以不全部应用。 所以,只要它们配置正确,数据库保持同步。
Galera 复制插件不同于传统的 MySQL 复制,可以解决多个问题,包括多主写入冲突,复制滞后和主从不同步。
由于 galera 集群需要 MySQL 服务器支持 wsrep API,所以我们需要下载一个有 wsrepAPI 的模块或者支持该模块的 mysql,
wsrep API 是数据库的通用复制插件接口,比较类似一种应用程序,主要针对写复制, 主要用于定义应用程序如何调用复制库实现回写。

d3c13040b15345298a571878eb15da0a.png

三、部署配置

1、准备环境

| 主机名 | IP | 注释 | | --- | --- | --- | | node01 | 192.168.50.121 | 主服务 | | node03 | 192.168.50.122 | 从服务 | | node02 | 192.168.50.123 | 从服务 | | node04 | 192.168.50.124 | 负载均衡 |

2、官网下载安装包

Downloads | Galera Cluster for MySQL

①、下载 Galera 复制库

image.png
image.png
image.png

②、下载带有写集复制 API 的 MySQL 5.7 Server 扩展

image.png
image.png

3、安装依赖包

yum -y install lsof net-tools perl socat openssl openssl-devel boost-devel stunnel

image.png

4、上传安装包并安装 rpm 包(它们之间有依赖关系,按顺序安装)

清理 Mariadb

rpm -qa | grep mariadb
rpm -qa | grep -i mariadb | xargs rpm -e --nodeps
rpm -qa | grep mariadb

image.png
安装

rpm -ivh mysql-wsrep-common-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh mysql-wsrep-libs-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh mysql-wsrep-client-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh mysql-wsrep-libs-compat-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh mysql-wsrep-server-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh mysql-wsrep-devel-5.7-5.7.41-25.33.el7.x86_64.rpm
rpm -ivh galera-3-25.3.37-1.el7.x86_64.rpm

image.png
image.png

5、启动 mysql 查看密码

systemctl start mysqld
systemctl status mysqld
systemctl enable mysqld
cat /var/log/mysqld.log | grep password

image.png

6、进入数据库设置密码

mysql -uroot -p'a0huuX+ey5rx'
set global validate_password_policy=0;
set global validate_password_length=0;
set password=password('CWCcwy@123!');
flush privileges;
use mysql;
grant all on *.* TO 'wxhntmy'@'%' identified by 'CWCcwy@123!';
flush privileges;

image.png
关于 mysql 密码策略相关参数;

  1. validatepasswordlength 固定密码的总长度

  2. validatepassworddictionary_file 指定密码验证的文件路径

  3. validatepasswordmixedcasecount 整个密码中至少要包含大/小写字母的总个数

  4. validatepasswordnumber_count 整个密码中至少要包含阿拉伯数字的个数

  5. validatepasswordpolicy 指定密码的强度验证等级,默认为 MEDIUM

  • 0/LOW:只验证长度;

  • 1/MEDIUM:验证长度、数字、大小写、特殊字符;

  • 2/STRONG:验证长度、数字、大小写、特殊字符、字典文件;

  1. validatepasswordspecialcharcount 整个密码中至少要包含特殊字符的个数

更多说明查看mysql官网关于密码验证选项和变量:https://dev.mysql.com/doc/refman/8.0/en/validate-password-options-variables.html

7、配置 galera 集群,防火墙放行端口

①、修改 /etc/my.cnf 配置文件

vim /etc/my.cnf

在最后加入下边内容

server_id=1
binlog_format=row
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_autoinc_lock_mode=2

wsrep_on=ON
wsrep_provider=/usr/lib64/galera-3/libgalera_smm.so
wsrep_cluster_name='galera'
wsrep_cluster_address='gcomm://'
wsrep_node_name='node01'
wsrep_node_address='192.168.50.121'
wsrep_sst_auth=wxhntmy:CWCcwy@123!
wsrep_sst_method=rsync

image.png

  • server_id 要集群内唯一,比如 node1的为1,node2的为2…

  • binlog_format=row binlog的格式

  • innodbfileper_table=1 独立的表空间

  • innodbautoinclock_mode=2 自增锁模式取值

  • 0这个表示 tradition 传统

  • 1 这个表示 consecutive 连续

  • 2 这个表示 interleaved 交错

  • wsrep_on=ON wsrep功能开启

  • wsrepprovider=/usr/lib64/galera/libgalerasmm.so 开启so模块

  • wsrepclustername 集群名字,可以自定义,但是同一集群要保持一致

  • wsrepclusteraddress 第一个节点的值为'gcomm://',第一个节点起来后,其他节点可以配置为集群除自身外所有节点ip地址 如:'gcomm://192.168.50.121,192.168.50.122'

  • wsrepnodename 节点主机名

  • wsrepnodeaddress 节点ip

  • wsrepsstauth 创建的用于同步的用户和密码 (我创建的用户为 wxhntmy 密码为 CWCcwy@123!)

②、开启防火墙端口

firewall-cmd --add-port=3306/tcp --permanent
firewall-cmd --add-port=4567/tcp --permanent
firewall-cmd --add-port=4567/udp --permanent
firewall-cmd --add-port=4568/tcp --permanent
firewall-cmd --add-port=4444/tcp --permanent
firewall-cmd --reload

image.png

  • 4567 , Galera做数据复制的通讯和数据传输端口,需要在防火墙放开TCP和UDP

  • 4568 , Galera做增量数据传输使用的端口(Incremental State Transfer, IST),需要防火墙放开TCP

  • 4444 , Galera做快照状态传输使用的端口(State Snapshot Transfer, SST),需要防火墙放开TCP

必须关闭 SELINUX

sed -ri '/^SELINUX=/cSELINUX=disabled' /etc/selinux/config
setenforce 0

③、安装 rsync

yum -y install rsync
systemctl enable rsyncd
systemctl start rsyncd

image.png

④、添加 hosts

cat >> /etc/hosts << EOF
192.168.50.121 node01
192.168.50.122 node02
192.168.50.123 node03
EOF

image.png

8、启动第一个节点

systemctl restart mysqld
systemctl status mysqld

image.png

mysql -uroot -p'CWCcwy@123!'
show status like 'wsrep%';

image.png

mysql> show status like 'wsrep%';
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | f1c652cf-edd1-11ed-a10f-968ace4bc2c6 |
| wsrep_protocol_version       | 9                                    |
| wsrep_last_committed         | 0                                    |
| wsrep_replicated             | 0                                    |
| wsrep_replicated_bytes       | 0                                    |
| wsrep_repl_keys              | 0                                    |
| wsrep_repl_keys_bytes        | 0                                    |
| wsrep_repl_data_bytes        | 0                                    |
| wsrep_repl_other_bytes       | 0                                    |
| wsrep_received               | 2                                    |
| wsrep_received_bytes         | 144                                  |
| wsrep_local_commits          | 0                                    |
| wsrep_local_cert_failures    | 0                                    |
| wsrep_local_replays          | 0                                    |
| wsrep_local_send_queue       | 0                                    |
| wsrep_local_send_queue_max   | 1                                    |
| wsrep_local_send_queue_min   | 0                                    |
| wsrep_local_send_queue_avg   | 0.000000                             |
| wsrep_local_recv_queue       | 0                                    |
| wsrep_local_recv_queue_max   | 2                                    |
| wsrep_local_recv_queue_min   | 0                                    |
| wsrep_local_recv_queue_avg   | 0.500000                             |
| wsrep_local_cached_downto    | 18446744073709551615                 |
| wsrep_flow_control_paused_ns | 0                                    |
| wsrep_flow_control_paused    | 0.000000                             |
| wsrep_flow_control_sent      | 0                                    |
| wsrep_flow_control_recv      | 0                                    |
| wsrep_flow_control_active    | false                                |
| wsrep_flow_control_requested | false                                |
| wsrep_cert_deps_distance     | 0.000000                             |
| wsrep_apply_oooe             | 0.000000                             |
| wsrep_apply_oool             | 0.000000                             |
| wsrep_apply_window           | 0.000000                             |
| wsrep_apply_waits            | 0                                    |
| wsrep_commit_oooe            | 0.000000                             |
| wsrep_commit_oool            | 0.000000                             |
| wsrep_commit_window          | 0.000000                             |
| wsrep_local_state            | 4                                    |
| wsrep_local_state_comment    | Synced                               |
| wsrep_cert_index_size        | 0                                    |
| wsrep_causal_reads           | 0                                    |
| wsrep_cert_interval          | 0.000000                             |
| wsrep_open_transactions      | 0                                    |
| wsrep_open_connections       | 0                                    |
| wsrep_incoming_addresses     | 192.168.50.121:3306                  |
| wsrep_cluster_weight         | 1                                    |
| wsrep_desync_count           | 0                                    |
| wsrep_evs_delayed            |                                      |
| wsrep_evs_evict_list         |                                      |
| wsrep_evs_repl_latency       | 0/0/0/0/0                            |
| wsrep_evs_state              | OPERATIONAL                          |
| wsrep_gcomm_uuid             | f1c5fe7f-edd1-11ed-be51-52686bc6b62c |
| wsrep_gmcast_segment         | 0                                    |
| wsrep_cluster_conf_id        | 1                                    |
| wsrep_cluster_size           | 1                                    |
| wsrep_cluster_state_uuid     | f1c652cf-edd1-11ed-a10f-968ace4bc2c6 |
| wsrep_cluster_status         | Primary                              |
| wsrep_connected              | ON                                   |
| wsrep_local_bf_aborts        | 0                                    |
| wsrep_local_index            | 0                                    |
| wsrep_provider_name          | Galera                               |
| wsrep_provider_vendor        | Codership Oy <info@codership.com>    |
| wsrep_provider_version       | 3.37(rf47405c8)                      |
| wsrep_ready                  | ON                                   |
+------------------------------+--------------------------------------+
64 rows in set (0.00 sec)

mysql>

注意:如果第一台节点起不来就将 /var/lib/mysql/ 目录下的两个缓存文件删除再启动。

ls -l /var/lib/mysql/

image.png

rm -rf /var/lib/mysql/grastate.dat
rm -rf /var/lib/mysql/galera.cache

9、接下来的每一台机器都做以上操做

①、node02

在第一加入(node02 192.168.50.122)修改(/etc/my.cnf)

vim /etc/my.cnf
server_id=2
binlog_format=row
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_autoinc_lock_mode=2

wsrep_on=ON
wsrep_provider=/usr/lib64/galera-3/libgalera_smm.so
wsrep_cluster_name='galera'
wsrep_cluster_address='gcomm://192.168.50.121,192.168.50.123'
wsrep_node_name='node02'
wsrep_node_address='192.168.50.122'
wsrep_sst_auth=wxhntmy:CWCcwy@123!
wsrep_sst_method=rsync

image.png

systemctl restart mysqld
systemctl status mysqld

image.png

②、node03

在第二加入(node03 192.168.50.123)修改(/etc/my.cnf)

vim /etc/my.cnf
server_id=3
binlog_format=row
default_storage_engine=InnoDB
innodb_file_per_table=1
innodb_autoinc_lock_mode=2

wsrep_on=ON
wsrep_provider=/usr/lib64/galera-3/libgalera_smm.so
wsrep_cluster_name='galera'
wsrep_cluster_address='gcomm://192.168.50.121,192.168.50.122'
wsrep_node_name='node03'
wsrep_node_address='192.168.50.123'
wsrep_sst_auth=wxhntmy:CWCcwy@123!
wsrep_sst_method=rsync

image.png

systemctl restart mysqld
systemctl status mysqld

image.png

③、从服务器启动服务后,在主服务器察看集群信息

登录 node01

mysql -uwxhntmy -P3306 -h192.168.50.121 -p'CWCcwy@123!'
show status like 'wsrep%';

image.png

四、Galera 集群搭建完成,进行测试

1、测试一

分别向三个节点 建库,建表, 插入数据操作,验证多点写入,观察数据是否同步

mysql -uwxhntmy -P3306 -h192.168.50.121 -p'CWCcwy@123!'
mysql -uwxhntmy -P3306 -h192.168.50.122 -p'CWCcwy@123!'
mysql -uwxhntmy -P3306 -h192.168.50.123 -p'CWCcwy@123!'
create database test;
show databases;
use test;
CREATE TABLE test.test_table (message VARCHAR(250));
---节点1
INSERT INTO test.test_table VALUES ('node01');
---节点2
INSERT INTO test.test_table VALUES ('node02');
---节点3
INSERT INTO test.test_table VALUES ('node03');
select * from test.test_table;

在所有其余两个数据库中都可以查询到插入数据的存在
image.png
image.png
image.png

2、测试二

下线其中一个节点 killall mysqld (不要是发起人 192.168.50.121 ),剩余节点继续添加数据, 拉开距离。
此时离线数据库重新上线,启动服务即可,观察是否能追上其他人的数据
当断开后一段时间重新连接会发现数据一样能够自动同步回来

3、测试三

让 发起人节点 离线。 剩余服务器继续插入数据,拉开距离
再让 发起人 重新上线

vim /etc/my.cnf
wsrep_cluster_address='gcomm://192.168.50.122,192.168.50.123'

此时 gcomm:// 不再为空,要向其他服务器同步数据

4、测试四

停止集群所有数据库
最后离开集群/停止的数据库 主机,要最先启动。否则可能导致数据丢失。
如果要一台不是最后离开的主机强制启动。 修改 /mysql/grastate.dat
修改 safetobootstrap: 0 为1,修改最先启动的数据库/etc/my.cnf
修改 wsrepclusteraddress='gcomm://' 为空,不向任何主机进行同步
然后再启动数据库服务,接着启动其他数据库!

五、负载均衡

1、TCP 负载均衡

以下为示意图

NGINX 充当数据库服务器的反向代理,监听 MySQL 默认端口 3306。这为客户端提供了一个简单的接口,同时后端 MySQL 节点可以向外扩展(甚至脱机),且不会对客户端产生任何影响。
TCP 负载均衡在 stream 配置上下文中进行配置,因此我们在 nginx.conf 主文件中添加了一个 stream 块来创建基本的 MySQL 负载均衡配置。

vim /etc/nginx/nginx.conf
stream { 
    include stream.conf; 
}

image.png

  1. 这可以将我们的 TCP 负载均衡配置与主配置文件分隔开来。然后我们在与 nginx.conf 相同的目录下创建 stream.conf。请注意,默认情况下,conf.d 目录是留给 http 配置上下文的,因此无法向该目录添加 stream 配置文件。

  2. 首先,我们定义一个名为 galera_cluster 的上游组,其中包含 Galera 集群中的三个 MySQL 节点。在我们的测试环境中,它们都支持在本地主机上通过唯一的端口号进行访问。zone 指令定义了所有 NGINX worker 进程共享的内存容量,以维持负载均衡状态。Server{} 块配置了 NGINX 处理客户端的方式。NGINX 监听 MySQL 默认端口 3306,并将所有流量转发到在上游块中定义的 Galera 集群。

  3. 然而,如果我们的应用使用连接池访问数据库,那么以轮询方式打开集群连接可能会导致每个节点上的连接数量不均衡。此外,我们不能将连接视为给定的工作负载,因为连接可能处于空闲状态(等待应用查询)或正在处理查询。因此,对于 TCP 长连接,更合适的负载均衡算法是 Least Connections,配置 least_conn 指令

  4. 现在,当客户端打开到数据库的新连接时,NGINX 会选择当前连接数最少的集群节点。

  5. 跨集群共享数据库工作负载的一大优势在于它还可提供高可用性。进行上述配置后,NGINX 将服务器标记为 “不可用”,如果无法建立新的 TCP 连接则停止向其发送 TCP 数据包。

vim /etc/nginx/stream.conf
upstream galera_cluster {
    server 192.168.50.121:3306; # node1
    server 192.168.50.122:3306; # node2
    server 192.168.50.123:3306; # node3
    zone tcp_mem 64k;
    least_conn;
}

server {
    listen 3306; # MySQL default
    proxy_pass galera_cluster;
}

image.png

2、日志记录

NGINX 支持灵活地记录日志,因此它所有的 TCP/UDP 处理进程都可以被记录下来,以便进行调试或离线分析。对于 TCP 协议(例如 MySQL),NGINX 会在连接关闭时写入日志条目。log_format 指令定义了该日志中出现的值。我们可以从 Stream 模块中的任何变量中进行选择。我们在 stream.conf 文件顶部的 stream 上下文中定义了日志格式。

log_format mysql '$remote_addr [$time_local] $protocol $status $bytes_received '
                 '$bytes_sent $upstream_addr $upstream_connect_time '
                 '$upstream_first_byte_time $upstream_session_time $session_time';

添加 access_log 指令以启用日志记录,并指定日志文件的路径以及上个代码段中定义的日志格式的名称。

access_log /var/log/nginx/galera_access.log mysql;
vim /etc/nginx/nginx.conf

image.png
这会生成日志条目,示例见下。

tail -f /var/log/nginx/galera_access.log

image.png

3、测试

yum install -y net-tools
netstat -tulnp | grep 3306

image.png

mysql -uwxhntmy -P3306 -h192.168.50.124 -p'CWCcwy@123!'
SHOW VARIABLES WHERE Variable_name = 'hostname';

image.png


博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。