您好,在本文中,我想分享一些从两个主MySQL节点构建高可用MySQL数据库集群的经验,具有基于HAProxy和Heartbeat的负载平衡和故障转移功能。
在大多数现代项目中,数据库的可用性是生死攸关的问题。好的解决方案是从多个MySQL服务器创建一个分布式数据库集群,它可以处理负载平衡,故障转移功能和数据复制。此外,高负载下您可以拆分传入的请求。
在这个例子中,我将展示从两个主节点创建一个MySQL集群,主要思想是创建一对具有相同配置的服务器和一个用于接收请求的虚拟IP。即使在完全丢失其中一个节点后,此群集仍将继续工作。
我们将使用两个服务器(虚拟或裸机)和一对MySQL主服务器以及一对HAProxy,主虚拟IP将配置Heartbeat。请注意,在此示例中,只有一个HAProxy在一个时间段内使用,第二个HAProxy将站在热备用。MySQL服务器将循环使用循环类型的负载平衡。
选择具有两个服务器的模式使示例更简单。当然,如果你有一个额外的服务器,你可以创建一个更复杂的配置,将带有Heartbeat的HAProxy放在外部LB集群中,依此类推。但无论如何,这个例子足以在你的项目中构建一个强大的数据库集群。
0.准备。
首先,我们需要为MySQL复制选择少数子网,为Heartbeat选择HAProxy,更好地将它们分开,如果您的服务器有一些网络接口,也可以将这些子网放在不同的接口上。
192.168.0.0/24 - 用于数据库流量的网络
192.168.0.1 IP为MySQL1,192.168.0.2的IP为MySQL2。
10.10.10.0/24 - Heartbeat和HAProxy的网络。
10.10.10.1虚拟IP采取的请求,10.10.10.2主要用于IP sever1,10.10.10.3主要用于IP 服务器2。
1.使用主 - 主复制配置MySQL服务器。
首先,我们需要在我们的两台服务器上安装MySQL:
# apt-get update && apt-get upgrade -y
# apt-get install mysql-server mysql-client
然后在第一个和第二个节点上编辑/etc/mysql/my.cnf,以启用MySQL服务器之间的复制,并使它们使用192.168.0.0/24子网中的IPS:
Server1配置。
[mysqld]
bind-address = 192.168.0.1
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
log_bin_index = /var/log/mysql/mysql-bin.log.index
relay_log = /var/log/mysql/mysql-relay-bin
relay_log_index = /var/log/mysql/mysql-relay-bin.index
expire_logs_days = 10
max_binlog_size = 100M
log_slave_updates = 1
auto-increment-increment = 2
auto-increment-offset = 1
Server2配置。
[mysqld]
bind-address = 192.168.0.2
server_id = 2
log_bin = /var/log/mysql/mysql-bin.log
log_bin_index = /var/log/mysql/mysql-bin.log.index
relay_log = /var/log/mysql/mysql-relay-bin
relay_log_index = /var/log/mysql/mysql-relay-bin.index
expire_logs_days = 10
max_binlog_size = 100M
log_slave_updates = 1
auto-increment-increment = 2
auto-increment-offset = 2
然后重新启动它们并确保MySQL在指定的IP上生成:
server1# systemctl restart mysql
server1# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.0.1:3306 0.0.0.0:* LISTEN 9057/mysqld
server2# systemctl restart mysql
server2# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.0.2:3306 0.0.0.0:* LISTEN 8740/mysqld
现在将创建一个用于在数据库之间进行复制的用户,可以使用pwgen
实用程序生成足够强大的密码。连接到每个MySQL服务器并使用来自对方服务器的IP创建此用户:
server1# mysql -u root -p
MariaDB> GRANT REPLICATION SLAVE ON *.* TO 'replicauser'@'192.168.0.2' IDENTIFIED BY 'somestrongpassword';
server2# mysql -u root -p
MariaDB> GRANT REPLICATION SLAVE ON *.* TO 'replicauser'@'192.168.0.1' IDENTIFIED BY 'somestrongpassword';
检查replicauser是否可以访问每个MySQL服务器。
server1# mysql -u replicauser -p -h 192.168.0.2
Enter password: somestrongpassword
Welcome to the MariaDB monitor. Commands end with ; or \g.
bla bla....
server2# mysql -u replicauser -p -h 192.168.0.1
Enter password: somestrongpassword
Welcome to the MariaDB monitor. Commands end with ; or \g.
bla bla....
好的,现在我们可以继续配置MySQL服务器之间的复制。从那时起,最好从两个MySQL服务器打开两个控制台,因为我们需要根据另一个服务器的输出输入命令。
获取server1上的MySQL主服务器状态:
server1# mysql -u root -p
MariaDB> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 | 531 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
我们需要从此输出中获取File和Position信息。在server2上打开MySQL控制台并配置与第一台服务器的从属关系。
server2# mysql -u root -p
MariaDB> STOP SLAVE;
MariaDB> CHANGE MASTER TO master_host='192.168.0.1', master_port=3306, master_user='replicauser', master_password='somestrongpassword', master_log_file='mysql-bin.000002', master_log_pos=531;
MariaDB> START SLAVE;
现在从server2查询主状态,并在第一台服务器上配置MySQL的从属关系。
server2# mysql -u root -p
MariaDB> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 | 531 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
server1# mysql -u root -p
MariaDB> STOP SLAVE;
MariaDB> CHANGE MASTER TO master_host='192.168.0.2', master_port=3306, master_user='replicauser', master_password='somestrongpassword', master_log_file='mysql-bin.000002', master_log_pos=531;
MariaDB> START SLAVE;
好的,如果一切正常,我们必须在MySQL主服务器之间进行工作复制。您可以创建一些测试数据库并检查它。
server1# mysql -u root -p
MariaDB> CREATE DATABASE TESTDB;
MariaDB> CREATE TABLE TESTDB.REPLICA (`id` varchar(40));
然后检查此数据库是否也出现在第二台服务器上:
server2# mysql -u root -p
MariaDB> SHOW TABLES IN TESTDB;
+------------------+
| Tables_in_TESTDB |
+------------------+
| REPLICA |
+------------------+
1 row in set (0.00 sec)
正如您所看到的,TESTDB基础已成功复制到server2。我们刚刚完成了创建故障转移群集的第一阶段。
2. 在两台服务器上配置HAProxy。
在第二阶段,我们将在两台服务器上安装和配置两个完全相同的HAProxy,以平衡MySQL服务器之间的传入请求。
首先,我们需要在我们的MySQL服务器上添加额外的用户(必须在没有任何密码的情况下创建用户),HAProxy将使用该用户来检查MySQL服务器的运行状况。
server1# mysql -u root -p
MariaDB> CREATE USER 'haproxy_check'@'%';
MariaDB> FLUSH PRIVILEGES;
您可以在我们的任何MySQL服务器上创建此用户,因为我们在它们之间配置了复制。使用以下命令检查是否已添加用户:
server1# mysql -u root -p -e "SELECT User, Host FROM mysql.user"
Enter password:
+---------------+-------------+
| User | Host |
+---------------+-------------+
| haproxy_check | % |
| replicauser | 192.168.0.2 |
| root | localhost |
+---------------+-------------+
server2# mysql -u root -p -e "SELECT User, Host FROM mysql.user"
Enter password:
+---------------+-------------+
| User | Host |
+---------------+-------------+
| haproxy_check | % |
| replicauser | 192.168.0.1 |
| root | localhost |
+---------------+-------------+
另外,让我们创建一个具有root权限的用户,以便稍后进行一些测试请求:
server1# mysql -u root -p
MariaDB> CREATE USER 'haproxy_root'@'%' IDENTIFIED BY 'password';
MariaDB> GRANT ALL PRIVILEGES ON *.* TO 'haproxy_root'@'%';
现在是HAProxy安装的时候了:
server1# apt-get install haproxy
server2# apt-get install haproxy
保存原始配置并创建新配置:
server1# mv /etc/haproxy/haproxy.cfg{,.back}
server1# vi /etc/haproxy/haproxy.cfg
接下来在两台服务器上添加此配置:
global
user haproxy
group haproxy
defaults
mode http
log global
retries 2
timeout connect 3000ms
timeout server 5000ms
timeout client 5000ms
listen stats
bind 10.10.10.1:9999
stats enable
stats hide-version
stats uri /stats
stats auth statadmin:statadminpass
listen mysql-cluster
bind 10.10.10.1:3306
mode tcp
option mysql-check user haproxy_check
balance roundrobin
server mysql-1 192.168.0.1:3306 check
server mysql-2 192.168.0.2:3306 check
如您所见,两个HAProxy服务都将使用10.10.10.1共享IP地址。此虚拟IP将在服务器之间移动,因此我们需要制定一些技巧并启用net.ipv4.ip_nonlocal_bind sysctl选项,以允许系统服务绑定到非本地IP。
将此选项添加到文件/etc/sysctl.conf:
server1# vi /etc/sysctl.conf
net.ipv4.ip_nonlocal_bind=1
server2# vi /etc/sysctl.conf
net.ipv4.ip_nonlocal_bind=1
然后运行
sysctl -p
在此之后,我们可以在两台服务器上启动HAProxy:
server1# systemctl start haproxy
server2# systemctl start haproxy
检查他们是从共享IP 10.10.10.1开始的:
server1# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.0.1:3306 0.0.0.0:* LISTEN 918/mysqld
tcp 0 0 10.10.10.1:3306 0.0.0.0:* LISTEN 802/haproxy
tcp 0 0 10.10.10.1:9999 0.0.0.0:* LISTEN 802/haproxy
tcp 0 0 10.10.10.2:22 0.0.0.0:* LISTEN 785/sshd
server2# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.0.2:3306 0.0.0.0:* LISTEN 918/mysqld
tcp 0 0 10.10.10.1:3306 0.0.0.0:* LISTEN 802/haproxy
tcp 0 0 10.10.10.1:9999 0.0.0.0:* LISTEN 802/haproxy
tcp 0 0 10.10.10.3:22 0.0.0.0:* LISTEN 785/sshd
一切看起来都没问题,两台服务器都是使用虚拟IP启动的,我们也在9999端口配置了统计页面,因此您可以使用statadmin:statadminpass 检查http://10.10.10.1:9999/stats上的HAProxy状态。
3. 使用共享IP配置Heartbeat。
在最后阶段,我们需要在两台服务器上配置Heartbeat服务,并创建共享IP,用于提供传入请求。如果其中一个发生错误,此IP将在服务器之间迁移。
在两台服务器上安装Heartbeat:
server1# apt-get install heartbeat
server1# systemctl enable heartbeat
server2# apt-get install heartbeat
server2# systemctl enable heartbeat
现在我们需要为它创建一些配置文件,它们对于server1和server2大致相同。
创建一个/etc/ha.d/authkeys,在此文件中,Heartbeat存储数据以相互进行身份验证。两个服务器上的文件都是相同的:
server1# vi /etc/ha.d/authkeys
auth 1
1 md5 securepass
server2# vi /etc/ha.d/authkeys
auth 1
1 md5 securepass
将securepass
更改为您的强安全密码。此外,此文件只需由root拥有,因此:
server1# chmod 600 /etc/ha.d/authkeys
server2# chmod 600 /etc/ha.d/authkeys
接下来将在两台服务器上为Heartbeat创建一个主要配置,对于server1和server2,它会有所不同,创建/etc/ha.d/ha.cf:
服务器1
server1# vi /etc/ha.d/ha.cf
# keepalive: how many seconds between heartbeats
#
keepalive 2
#
# deadtime: seconds-to-declare-host-dead
#
deadtime 10
#
# What UDP port to use for udp or ppp-udp communication?
#
udpport 694
bcast ens18
mcast ens18 225.0.0.1 694 1 0
ucast ens18 10.10.10.3
# What interfaces to heartbeat over?
udp ens18
#
# Facility to use for syslog()/logger (alternative to log/debugfile)
#
logfacility local0
#
# Tell what machines are in the cluster
# node nodename ... -- must match uname -n
node server1
node server2
服务器2
server1# vi /etc/ha.d/ha.cf
# keepalive: how many seconds between heartbeats
#
keepalive 2
#
# deadtime: seconds-to-declare-host-dead
#
deadtime 10
#
# What UDP port to use for udp or ppp-udp communication?
#
udpport 694
bcast ens18
mcast ens18 225.0.0.1 694 1 0
ucast ens18 10.10.10.2
# What interfaces to heartbeat over?
udp ens18
#
# Facility to use for syslog()/logger (alternative to log/debugfile)
#
logfacility local0
#
# Tell what machines are in the cluster
# node nodename ... -- must match uname -n
node server1
node server2
您可以通过在服务器上运行获得此配置的节点名称uname -n
。
最后我们需要在server1和server2上创建/etc/ha.d/haresources文件。文件是相同的,在这个文件中我们默认声明我们的共享IP地址和主节点:
server1# vi /etc/ha.d/haresources
server1 10.10.10.1
server2# vi /etc/ha.d/haresources
server1 10.10.10.1
毕竟让我们在两台服务器上启动Heartbeat服务,你必须看到在server1上我们有虚拟IP:
server1# ip a
....
2: ens19: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether bla:bla:bla:bla brd ff:ff:ff:ff:ff:ff
inet 192.168.0.1/24 brd 192.168.0.255 scope global ens19
valid_lft forever preferred_lft forever
inet6 fe80::bla:bla:bla:bla/64 scope link
valid_lft forever preferred_lft forever
3: ens18: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether bla:bla:bla:bla:bla:bla brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 brd 10.10.10.255 scope global ens18
valid_lft forever preferred_lft forever
inet 10.10.10.1/24 brd 10.10.10.255 scope global secondary
....
好了,现在我们在server1上分配了虚拟IP,并在其上监听HAProxy,因此我们可以检查它是如何工作的,进行测试请求。从某些外部服务器运行此命令:
# mysql -h 10.10.10.1 -u haproxy_root -p -e "show variables like 'server_id'"
Enter password:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 1 |
+---------------+-------+
# mysql -h 10.10.10.1 -u haproxy_root -p -e "show variables like 'server_id'"
Enter password:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
一切正常,你可以看到我们的MySQL服务器之间的“round robin”平衡。现在我们需要在server1脱机时检查故障转移,例如。转到并重新启动或关闭server1,检查虚拟IP是否已移至server2,并且对MySQL服务器的请求仍然正常,但现在服务器2上只有MySQL会响应:
server2# ip a
....
2: ens19: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether bla:bla:bla:bla brd ff:ff:ff:ff:ff:ff
inet 192.168.0.2/24 brd 192.168.0.255 scope global ens19
valid_lft forever preferred_lft forever
inet6 fe80::bla:bla:bla:bla/64 scope link
valid_lft forever preferred_lft forever
3: ens18: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether bla:bla:bla:bla:bla:bla brd ff:ff:ff:ff:ff:ff
inet 10.10.10.3/24 brd 10.10.10.255 scope global ens18
valid_lft forever preferred_lft forever
inet 10.10.10.1/24 brd 10.10.10.255 scope global secondary
....
再次检查MySQL请求:
# mysql -h 10.10.10.1 -u haproxy_root -p -e "show variables like 'server_id'"
Enter password:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
# mysql -h 10.10.10.1 -u haproxy_root -p -e "show variables like 'server_id'"
Enter password:
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 2 |
+---------------+-------+
server1在线后,虚拟IP将移回其中。
好了,我们只是配置并测试了我们的MySQL集群,它现在准备服务请求。
转:https://towardsdatascience.com/high-availability-mysql-cluster-with-load-balancing-using-haproxy-and-heartbeat-40a16e134691