Mysql集群

目录

[一 Mysql 在服务器中的部署方法](#一 Mysql 在服务器中的部署方法)

环境准备

[1.1 部署mysql](#1.1 部署mysql)

[二 mysql的组从复制](#二 mysql的组从复制)

[2.1 配置mastesr](#2.1 配置mastesr)

[2.2 配置salve](#2.2 配置salve)

[2.3 一主两从 多线程回放](#2.3 一主两从 多线程回放)

[2.4 延迟复制](#2.4 延迟复制)

[2.5 慢查询日志](#2.5 慢查询日志)

[2.6 mysql的并行复制](#2.6 mysql的并行复制)

[2.7 原理刨析](#2.7 原理刨析)

[2.8 架构缺陷](#2.8 架构缺陷)

[三 半同步模式](#三 半同步模式)

3.1半同步模式原理

[3.2 gtid模式](#3.2 gtid模式)

3.3.启用半同步模式

[四 mysql高可用之组复制 (MGR)](#四 mysql高可用之组复制 (MGR))

[4.1 组复制流程](#4.1 组复制流程)

[4.2 组复制单主和多主模式](#4.2 组复制单主和多主模式)

4.3.实现mysql组复制

[五 mysql-router(mysql路由)](#五 mysql-router(mysql路由))

[六 mysql高可用之MHA](#六 mysql高可用之MHA)

6.1.MHA概述

[6.2 MHA部署实施](#6.2 MHA部署实施)

[6.2.1 搭建主两从架构](#6.2.1 搭建主两从架构)

6.2.2安装MHA所需要的软件

[6.2.3 配置MHA 的管理环境](#6.2.3 配置MHA 的管理环境)

[6.2.4 MHA的故障切换](#6.2.4 MHA的故障切换)

[6.2.3.1 master故障手动切换](#6.2.3.1 master故障手动切换)

[6.2.3.2 自动切换](#6.2.3.2 自动切换)

[6.2.5 为MHA添加VIP功能](#6.2.5 为MHA添加VIP功能)


一 Mysql 在服务器中的部署方法

官网:http://www.mysql.com

环境准备

|-------------|---------------|
| node | IP |
| mysql-node1 | 172.25.250.10 |
| mysql-node2 | 172.25.250.20 |
| mysql-node3 | 172.25.250.30 |
| mysql-mha | 172.25.250.50 |

1.1 部署mysql

node1,node2,node3

创建实验环境

#生成数据目录
[root@mysql-node1 ~]# mkdir -p /data/mysql
[root@mysql-node1 ~]# useradd -s /sbin/nologin -M mysql
[root@mysql-node1 ~]# chown mysql.mysql -R /data/mysql

安装依赖性

#安装所需软件
yum install -y cmake gcc-c++ openssl-devel ncurses-devel.x86_64 libtirpc-devel rpcgen.x86_64
[root@mysql-node1 ~]# yum install -y libtirpc-0.2.4-0.16.el7.x86_64
[root@mysql-node1 ~]# rpm -ivh libtirpc-devel-0.2.4-0.16.el7.x86_64.rpm

下载并解压源码包

[root@mysql-node1 ~]# tar zxf mysql-boost-5.7.44.tar.gz
[root@mysql-node1 ~]# cd mysql-5.7.44/

源码编译安装mysql

[root@mysql-node1 mysql-5.7.44]# cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \           #指定安装路径
-DMYSQL_DATADIR=/data/mysql \		                #指定数据目录需创建文件夹
-DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock \          #指定套接字文件
-DWITH_INNOBASE_STORAGE_ENGINE=1 \                  #指定启用INNODB存储引擎,默认用myisam
-DWITH_EXTRA_CHARSETS=all \                         #扩展字符集
-DDEFAULT_CHARSET=utf8mb4 \                         #指定默认字符集
-DDEFAULT_COLLATION=utf8mb4_unicode_ci \                #指定默认校验字符集
-DWITH_BOOST=/root/mysql-5.7.44/boost/boost_1_59_0      #指定c++库依赖


[root@mysql-node1 mysql-5.7.44]# make -j4 #-j4 表示有几个  例如:-j2 
核心就跑几个进程
[root@mysql-node1 mysql-5.7.44# make install

Note:当cmake出错后如果想重新检测,删除 mysql-5.7.44 中 CMakeCache.txt即可

部署mysql

[root@mysql-node1 mysql-5.7.44]# yum install initscripts.x86_64 -y

[root@mysql-node1 ~]# vim /etc/my.cnf
  1 [mysqld]
  2 datadir=/data/mysql			#指定数据目录
  3 socket=/data/mysql/mysql.sock	#指定套接字
  5 symbolic-links=0		#数据只能存放到数据目录中,禁止链接到数据目录

添加环境变量
[root@mysql-node1 ~]# vim .bash_profile 
[root@mysql-node1 ~]# source .bash_profile 
[root@mysql-node1 ~]# cat .bash_profile 
...
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin
...

#生成启动脚本
[root@mysql-node1 ~]# cd /usr/local/mysql/support-files
[root@mysql-node1 support-files]# ls
magic  mysqld_multi.server  mysql-log-rotate  mysql.server
[root@mysql-node1 support-files]# cp mysql.server /etc/init.d/mysqld

#初始化 
[root@mysql-node1 support-files]# mysqld --initialize --user=mysql
2024-08-22T10:42:07.191215Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2024-08-22T10:42:07.362700Z 0 [Warning] InnoDB: New log files created, LSN=45790
2024-08-22T10:42:07.388793Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2024-08-22T10:42:07.445965Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 2d9bb57c-6073-11ef-9714-000c29730697.
2024-08-22T10:42:07.446842Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2024-08-22T10:42:07.566913Z 0 [Warning] A deprecated TLS version TLSv1 is enabled. Please use TLSv1.2 or higher.
2024-08-22T10:42:07.566929Z 0 [Warning] A deprecated TLS version TLSv1.1 is enabled. Please use TLSv1.2 or higher.
2024-08-22T10:42:07.567605Z 0 [Warning] CA certificate ca.pem is self signed.
2024-08-22T10:42:07.601701Z 1 [Note] A temporary password is generated for root@localhost: s_>-lPe8epHV

[root@mysql-node1 ~]# cat passwd             #生成的随机数据库密码
s_>-lPe8epHV


#设定开机启动
[root@mysql-node1 init.d]# chkconfig mysqld on

#安全初始化
[root@mysql-node1 ~]# mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root: 
Error: Access denied for user 'root'@'localhost' (using password: YES)
[root@mysql-node1 ~]# mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root:         #输入当前密码

The existing password for the user account root has expired. Please set a new password.

New password:                         #输入新密码

Re-enter new password:                #重复新密码

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: no        #是否启用密码插件
Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : no    #是否重置密码

 ... skipping.
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : no

 ... skipping.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : no

 ... skipping.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : no    

 ... skipping.
All done! 

#主机2同主机1配置

可以直接使用rsync

[root@mysql-node1 ~]# rsync -al -r /usr/local/mysql root@172.25.250.20:/usr/local/

编译安装时可能存在的问题

#启动报错 
[root@mysql-node1 init.d]# /etc/init.d/mysqld start
Starting MySQL.2024-08-22T10:36:29.652184Z mysqld_safe error: log-error set to '/var/log/mariadb/mariadb.log', however file don't exists. Create writable for user 'mysql'.
 ERROR! The server quit without updating PID file (/data/mysql/mysql-node1.exam.com.pid).

#解决方案 重新初始化mysql
[root@mysql-node1 ~]# vim /etc/my.cnf
[root@mysql-node1 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0

[root@mysql-node2 mysql]# rm -rf /data/mysql/*
[root@mysql-node2 mysql]# mysqld --initialize --user=mysql

[root@mysql-node1 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node1.exam.com.err'.
 SUCCESS! 

#pid文件报错
[root@mysql-node3 ~]# /etc/init.d/mysqld restart
 ERROR! MySQL server PID file could not be found!
Starting MySQL.Logging to '/data/mysql/mysql-node3.exam.com.err'.
. ERROR! The server quit without updating PID file (/data/mysql/mysql-node3.exam.com.pid).

#先初始化node3 再从node1同步过去 再重启
[root@mysql-node1 mysql]# rsync -al -r /data/mysql/ root@172.25.250.30:/data/mysql/
root@172.25.250.30's password: 
[root@mysql-node1 mysql]# 

[root@mysql-node3 mysql]# /etc/init.d/mysqld restart
 ERROR! MySQL server PID file could not be found!
Starting MySQL. SUCCESS! 
[root@mysql-node3 mysql]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS! 
[root@mysql-node3 mysql]#

二 mysql的组从复制

2.1 配置mastesr

主:开启二进制日志
[root@mysql-node1 mysql]# vim /etc/my.cnf
[root@mysql-node1 mysql]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=1
log-bin=mysql-bin

[root@mysql-node1 mysql]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS! 
Starting MySQL. SUCCESS!

[root@mysql-node1 mysql]# mysql -uroot -predhat -e "select @@server_id";
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+

进入数据库配置用户权限

mysql> CREATE USER howe@'%' IDENTIFIED BY 'redhat';#生成专门用来做复制的用
户,此用户是用于slave端做认证用
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO howe@'%';    #对这个用户进行授权
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW MASTER STATUS;        #查看master的状态
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

2.2 配置salve

从:
[root@mysql-node2 ~]# vim /etc/my.cnf
[root@mysql-node2 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2


[root@mysql-node2 ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS!


[root@mysql-node2 ~]# mysql -predhat
mysql> change master to master_host='172.25.250.10',master_user='howe',master_password='redhat',master_log_file='mysql-bin.000001',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)


mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.25.250.10
                  Master_User: howe
                  Master_Port: 3306
                Connect_Retry: 60
					.......
		   	Slave_IO_Running: Yes
             Slave_SQL_Running: Yes
            		.......
             Replicate_Rewrite_DB: 
             Channel_Name: 
             Master_TLS_Version: 
		    1 row in set (0.00 sec)

mysql> CREATE DATABASE howe;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE TABLE howe.userlist (
    -> username varchar(20) not null,
    -> password varchar(50) not null
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO howe.userlist VALUE ('hello','123');
Query OK, 1 row affected (0.02 sec)

mysql>  SELECT * FROM howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
+----------+----------+
1 row in set (0.00 sec)

测试

#在node2上查看同步
[root@mysql-node2 ~]# mysql -uhowe -p
mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
+----------+----------+
1 row in set (0.01 sec)

在slave阶段中默认情况下是开启了写功能的,但是建议关闭slave节点的写功能来保证数据一致性

vim /etc/mysql.cnf

[mysqld]

super_read_only=on


2.3 一主两从 多线程回放

node3完成基础配置

#node1上直接通过rsync同步到node3
[root@mysql-node1 ~]# rsync -al -r /data/mysql root@172.25.250.30:/data/mysql

[root@mysql-node1 mysql]# rsync -al  /usr/local/mysql root@172.25.250.30:/usr/local
root@172.25.250.30's password:				#注意不要加/

[root@mysql-node3 ~]# mkdir -p /data/mysql
[root@mysql-node3 ~]# useradd -s /sbin/nologin -M mysql
[root@mysql-node3 ~]# chown -R mysql.mysql /data/mysql/
[root@mysql-node3 ~]# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld 

[root@mysql-node3 ~]# vim /etc/my.cnf
[root@mysql-node3 ~]# cat /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
server-id=3
#super_read_only=on 

[root@mysql-node3 ~]# vim .bash_profile 
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin
[root@mysql-node3 ~]# source .bash_profile

初始化
[root@mysql-node3 ~]# mysqld --initialize --user=mysql
[root@mysql-node3 ~]# ls /data/mysql/		#初始化后有数据和授权表 同时注意/etc/my.cnf的目录是否正确 不然起不了服务

[root@mysql-node3 ~]# /etc/init.d/mysqld start
Starting MySQL SUCCESS!

#拉平数据 安全初始化  no no y y y y ...
==================================================================================
#node1 锁库锁表 
生产环境中备份时需要锁表,保证备份前后的数据一致
mysql> FLUSH TABLES WITH READ LOCK;
备份后再解锁
mysql> UNLOCK TABLES;
mysqldump命令备份的数据文件,在还原时先DROP TABLE,需要合并数据时需要删除此语句

==============================================================================
#node1 数据库备份
[root@mysql-node1 ~]# mysqldump -uroot -p howe > howe.sql
Enter password: 
[root@mysql-node1 ~]# cat howe.sql 
----------------------------------------
/*!40000 ALTER TABLE `userlist` DISABLE KEYS */;
INSERT INTO `userlist` VALUES ('hello','123');
/*!40000 ALTER TABLE `userlist` ENABLE KEYS */;
------------------------------------------

#把sql文件拷贝到node3 
[root@mysql-node1 ~]# scp howe.sql root@172.25.250.30:/rhel7/
root@172.25.250.30's password: 
howe.sql                                                                 100% 1946     1.8MB/s   00:00

#node3 进入数据库并建立数据库 ---用来恢复数据库
[root@mysql-node3 rhel7]# ls
howe.sql

[root@mysql-node3 ~]# mysql -uroot -predhat -e "CREATE DATABASE howe;"
mysql: [Warning] Using a password on the command line interface can be insecure.	#不需要管 提示输入密码不安全

导入数据库
[root@mysql-node3 rhel7]# mysql -uroot -predhat howe < howe.sql
mysql: [Warning] Using a password on the command line interface can be insecure.

=============================================================================
#
[root@mysql-node3 ~]# mysql -uroot -predhat 
mysql> change master to master_host='172.25.250.10',master_user='howe',master_password='redhat',master_log_file='mysql-bin.000001',master_log_pos=805;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> show slave status\G;
				.....
             Slave_IO_Running: yes		 
            Slave_SQL_Running: Yes
				......
========================================================================
#node1 插入
mysql> insert into howe.userlist values ('user2','456');
Query OK, 1 row affected (0.00 sec)

#node2 node3 查看
mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
| user2    | 456      |				#新插入的加进来了
+----------+----------+
2 rows in set (0.00 sec)

问题:uuid一致

			Slave_IO_Running: no		 
             Slave_SQL_Running: Yes
				.....
	      Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.					#报错 uuid一致
             	.....
[root@mysql-node3 mysql]# ls /data/mysql
auto.cnf
[root@mysql-node3 mysql]# rm auto.cnf 
[root@mysql-node3 mysql]# /etc/init.d/mysqld restart


mysql> stop slave;			#停掉
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G;
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

生产环境中备份时需要锁表,保证备份前后的数据一致

mysql> FLUSH TABLES WITH READ LOCK;

备份后再解锁

mysql> UNLOCK TABLES;

mysqldump命令备份的数据文件,在还原时先DROP TABLE,需要合并数据时需要删除此语句


2.4 延迟复制

延迟复制时用来控制sql线程的,和i/o线程无关 这个延迟复制不是i/o线程过段时间来复制,i/o是正常工作的 是日志已经保存在slave端了,那个sql要等多久进行回放 当master端误操作,可以在slave端进行数据备份

#slave node3端
mysql> stop slave sql_thread;		停止
Query OK, 0 rows affected (0.00 sec)

mysql> change master to master_delay=60;		设置延迟
Query OK, 0 rows affected (0.01 sec)

mysql> start slave sql_thread;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
				....
                  SQL_Delay: 60
                  ....

=================================================

node1 在master中写入数据后过了延迟时间才能被查询到

mysql> delete from howe.userlist where username='user1';
Query OK, 0 rows affected (0.01 sec)

mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
| user2    | 456      |
+----------+----------+
2 rows in set (0.00 sec)

#过了60s后查询node3
mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
| user2    | 456      |
+----------+----------+
2 rows in set (0.01 sec)

2.5 慢查询日志

  • 慢查询,顾名思义,执行很慢的查询

  • 当执行SQL超过long_query_time参数设定的时间阈值(默认10s)时,就被认为是慢查询,这个SQL语句就是需要优化的

  • 慢查询被记录在慢查询日志里

  • 慢查询日志默认是不开启的

  • 如果需要优化SQL语句,就可以开启这个功能,它可以让你很容易地知道哪些语句是需要优化的

    #开启慢查询
    mysql> set global slow_query_log=on;
    Query OK, 0 rows affected (0.01 sec)

    mysql> set long_query_time=4;
    Query OK, 0 rows affected (0.00 sec)

    mysql> show variables like "long%";
    +-----------------+----------+
    | Variable_name | Value |
    +-----------------+----------+
    | long_query_time | 4.000000 |
    +-----------------+----------+
    1 row in set (0.00 sec)

    mysql> show variables like "slow%"; #慢查询日志开启
    +---------------------+----------------------------------+
    | Variable_name | Value |
    +---------------------+----------------------------------+
    | slow_launch_time | 2 |
    | slow_query_log | ON |
    | slow_query_log_file | /data/mysql/mysql-node1-slow.log |
    +---------------------+----------------------------------+
    3 rows in set (0.00 sec)

    mysql> select sleep (10); #超过10s视为慢查询
    +------------+
    | sleep (10) |
    +------------+
    | 0 |
    +------------+
    1 row in set (10.00 sec)

    #查看慢查询日志
    [root@mysql-node1 ~]# cat /data/mysql/mysql-node1-slow.log
    /usr/local/mysql/bin/mysqld, Version: 5.7.44-log (Source distribution). started with:
    Tcp port: 3306 Unix socket: /data/mysql/mysql.sock
    Time Id Command Argument

    Time: 2024-08-22T19:39:28.679928Z

    User@Host: root[root] @ localhost [] Id: 13

    Query_time: 10.000618 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0

    SET timestamp=1724355568;
    select sleep (10);


2.6 mysql的并行复制

主从的日志多线程回放

#slave2端:
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2
super_read_only=on			   #强制只读
gtid_mode=ON				   #打开gtid
enforce-gtid-consistency=ON		#保证gtid强一致
slave-parallel-type=LOGICAL_CLOCK		#基于组提交
slave-parallel-workers=16			#开启线程数量
master_info_repository=TABLE		#master信息在表中记录,默认记录
relay_log_info_repository=TABL		#日志回放恢复功能开启

#重启
[root@mysql-node2 ~]# /etc/init.d/mysqld restart 
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS!

默认情况下slave中使用的是sql单线程回放

在master中时多用户读写,如果使用sql单线程回放那么会造成组从延迟严重

开启MySQL的多线程回放可以解决上述问题

MySQL 组提交(Group commit)是一个性能优化特性,它允许在一个事务日志同步操作中将多个 事务的日志记录一起写入。这样做可以减少磁盘I/O的次数,从而提高数据库的整体性能。


2.7 原理刨析

三个线程

实际上主从同步的原理就是基于 binlog 进行数据同步的。在主从复制过程中,会基于3 个线程来操作,一个主库线程,两个从库线程。

  • 二进制日志转储线程(Binlog dump thread)是一个主库线程。当从库线程连接的时候, 主库可以将二进制日志发送给从库,当主库读取事件(Event)的时候,会在 Binlog 上加锁,读取完成之后,再将锁释放掉。
  • 从库 I/O 线程会连接到主库,向主库发送请求更新 Binlog。这时从库的 I/O 线程就可以读取到主库的二进制日志转储线程发送的 Binlog 更新部分,并且拷贝到本地的中继日志 (Relay log)。
  • 从库 SQL 线程会读取从库中的中继日志,并且执行日志中的事件,将从库中的数据与主库保持同步。

复制三步骤

  • 步骤1:Master将写操作记录到二进制日志(binlog)。
  • 步骤2:Slave将Master的binary log events拷贝到它的中继日志(relay log);
  • 步骤3:Slave重做中继日志中的事件,将改变应用到自己的数据库中。 MySQL复制是异步的且串行化的,而且重启后从接入点开始复制。

具体操作

1.slaves端中设置了master端的ip,用户,日志,和日志的Position,通过这些信息取得master的认证及

信息

2.master端在设定好binlog启动后会开启binlog dump的线程

3.master端的binlog dump把二进制的更新发送到slave端的

4.slave端开启两个线程,一个是I/O线程,一个是sql线程,

  • i/o线程用于接收master端的二进制日志,此线程会在本地打开relaylog中继日志,并且保存到本地 磁盘
  • sql线程读取本地relog中继日志进行回放

5.什么时候我们需要多个slave?

当读取的而操作远远高与写操作时。我们采用一主多从架构

数据库外层接入负载均衡层并搭配高可用机制

2.8 架构缺陷

主从架构采用的是异步机制

master更新完成后直接发送二进制日志到slave,但是slaves是否真正保存了数据master端不会检测

master端直接保存二进制日志到磁盘

当master端到slave端的网络出现问题时或者master端直接挂掉,二进制日志可能根本没有到达slave

master出现问题slave端接管master,这个过程中数据就丢失了

这样的问题出现就无法达到数据的强一致性,零数据丢失


三 半同步模式

3.1半同步模式原理

1.用户线程写入完成后master中的dump会把日志推送到slave端

2.slave中的io线程接收后保存到relaylog中继日志

3.保存完成后slave向master端返回ack

4.在未接受到slave的ack时master端时不做提交的,一直处于等待当收到ack后提交到存储引擎

5.在5.6版本中用到的时after_commit模式,after_commit模式时先提交在等待ack返回后输出ok

3.2 gtid模式

当为启用gtid时我们要考虑的问题

在master端的写入时多用户读写,在slave端的复制时单线程日志回放,所以slave端一定会延迟与

master端

这种延迟在slave端的延迟可能会不一致,当master挂掉后slave接管,一般会挑选一个和master延迟日志最接近的充当新的master

那么为接管master的主机继续充当slave角色并会指向到新的master上,作为其slave

这时候按照之前的配置我们需要知道新的master上的pos的id,但是我们无法确定新的master和slave之间差多少

当激活GITD之后

当master出现问题后,slave2和master的数据最接近,会被作为新的master

slave1指向新的master,但是他不会去检测新的master的pos id,只需要继续读取自己gtid_next即可

设置gtid

#在master端和slave端开启gtid模式
[root@mysql-node1 ~]# vim /etc/my.cnf
[root@mysql-node1 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON

#重启
[root@mysql-node1 ~]# /etc/init.d/mysqld restart 
Shutting down MySQL. SUCCESS! 
Starting MySQL. SUCCESS!

=======================================================

#node1查看是否开启gtid
mysql> show master status;
mysql-bin.000003 |      154

[root@mysql-node1 ~]# mysqlbinlog -vv /data/mysql/mysql-bin.000003 
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;

=================================================================

#重新设定slave
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)

mysql> change master to
    -> master_host='172.25.250.10',
    -> master_user='howe',
    -> master_password='redhat',
    -> master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status\G;
	    ......
    Auto_Position: 1	#功能开启
        ......

3.3.启用半同步模式

在master端配置启用半同步模式

[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=1
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_master_enabled=1	#开启半同步功能

#安装半同步插件
[root@mysql-node1 ~]# mysql -uroot -predhat
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.02 sec)

#查看插件情况
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
    -> FROM INFORMATION_SCHEMA.PLUGINS
    -> WHERE PLUGIN_NAME LIKE '%semi%';
+----------------------+---------------+
| PLUGIN_NAME          | PLUGIN_STATUS |
+----------------------+---------------+
| rpl_semi_sync_master | ACTIVE        |
+----------------------+---------------+
1 row in set (0.00 sec)

#打开半同步功能
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)

#查看半同步功能状态
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled              | ON         |
| rpl_semi_sync_master_timeout              | 10000      |
| rpl_semi_sync_master_trace_level          | 32         |
| rpl_semi_sync_master_wait_for_slave_count | 1          |
| rpl_semi_sync_master_wait_no_slave        | ON         |
| rpl_semi_sync_master_wait_point           | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.00 sec)

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 0     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 0     |
| Rpl_semi_sync_master_no_times              | 0     |
| Rpl_semi_sync_master_no_tx                 | 0     |
| Rpl_semi_sync_master_status                | ON    |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
| Rpl_semi_sync_master_tx_wait_time          | 0     |
| Rpl_semi_sync_master_tx_waits              | 0     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 0     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

====================================================================

在slave端开启半同步功能  
先下载模块 再开启
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)


[root@mysql-node2 ~]# cat /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=2
gtid_mode=ON
enforce-gtid-consistency=ON
rpl_semi_sync_master_enabled=1

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.01 sec)

mysql> SET GLOBAL rpl_semi_sync_slave_enabled=1;
Query OK, 0 rows affected (0.00 sec)

mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)

mysql> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name                             | Value      |
+-------------------------------------------+------------+
| rpl_semi_sync_slave_enabled               | ON         |
| rpl_semi_sync_slave_trace_level           | 32         |
+-------------------------------------------+------------+
8 rows in set (0.00 sec)

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_slave_status                 | ON    |
+--------------------------------------------+-------+
15 rows in set (0.00 sec)

==============================================================

测试
master
mysql> insert into howe.userlist values('tongbu','321');
Query OK, 1 row affected (0.02 sec)

slave
mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| hello    | 123      |
| user2    | 456      |
| haha     | xixi     |
| tongbu   | 321      |
+----------+----------+
4 rows in set (0.00 sec)
===========================

#模拟故障
关闭slave  会发现master只有等到slave开启后才可以继续写入

#slave都挂掉后还能写入数据?
答:写入之后10s 自动转换成了异步模式,当slave恢复会自动恢复

四 mysql高可用之组复制 (MGR)

MySQL Group Replication(简称 MGR )是 MySQL 官方于 2016 年 12 月推出的一个全新的高可用与高扩展的解决方案

组复制是 MySQL 5.7.17 版本出现的新特性,它提供了高可用、高扩展、高可靠的 MySQL 集群服务

MySQL 组复制分单主模式和多主模式,传统的mysql复制技术仅解决了数据同步的问题,

MGR 对属于同一组的服务器自动进行协调。对于要提交的事务,组成员必须就全局事务序列中给定事务的顺序达成一致

提交或回滚事务由每个服务器单独完成,但所有服务器都必须做出相同的决定

如果存在网络分区,导致成员无法达成事先定义的分割策略,则在解决此问题之前系统不会继续进行,这是一种内置的自动裂脑保护机制

MGR由组通信系统( Group Communication System ,GCS ) 协议支持

该系统提供故障检测机制、组成员服务以及安全且有序的消息传递

4.1 组复制流程

首先我们将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致性协议层 (Consensus 层)的同意,也就是读写事务想要进行提交,必须要经过组里"大多数人"(对应 Node 节 点)的同意,大多数指的是同意的节点数量需要大于 (N/2+1),这样才可以进行提交,而不是原发起 方一个说了算。而针对只读(RO)事务则不需要经过组内同意,直接 提交 即可

Note 节点数量不能超过9台

4.2 组复制单主和多主模式

single-primary mode(单写或单主模式)

单写模式 group 内只有一台节点可写可读,其他节点只可以读。当主服务器失败时,会自动选择新的主 服务器

multi-primary mode(多写或多主模式)

组内的所有机器都是 primary 节点,同时可以进行读写操作,并且数据是最终一致的。

4.3.实现mysql组复制

为了避免出错,在所有节点中从新生成数据库数据

配置文件说明:

[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0    
server-id=1                          #配置server唯一标识号
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" #禁用指定存储
引擎    
gtid_mode=ON                         #启用全局事件标识
enforce_gtid_consistency=ON          #强制gtid一致
master_info_repository=TABLE         #复制事件数据到表中而不记录在数据目录中
relay_log_info_repository=TABLE
binlog_checksum=NONE                 #禁止对二进制日志校验
log_slave_updates=ON                 #打开数据库中继,
                                 #当slave中sql线程读取日志后也会写入到自己的binlog中
log_bin=binlog                     #重新指定log名称 
binlog_format=ROW #使用行日志格式 
plugin_load_add='group_replication.so'             #加载组复制插件
transaction_write_set_extraction=XXHASH64             #把每个事件编码为加密散列
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" #通知插件正
                                            式加入 ,或创建的组名#名称为uuid格式
group_replication_start_on_boot=off #在server启动时不自动启动组复
制
group_replication_local_address="172.25.254.10:33061" #指定插件接受其他成员的信息端
口
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,
172.25.254.30:33061"                               #本地地址允许访问成员列表
group_replication_ip_whitelist="172.25.254.0/24,127.0.0.1/8"     #主机白名单
#不随系统自启而启动,只在初始成员主机中手动开启,
#需要在两种情况下做设定:1.初始化建组时 2.关闭并重新启动整个组时
group_replication_bootstrap_group=off 
group_replication_single_primary_mode=OFF         #使用多主模式
group_replication_enforce_update_everywhere_checks=ON     #组同步中有任何改变
检测更新
group_replication_allow_local_disjoint_gtids_join=1     #放弃自己信息以
master事件为主

编辑主配置文件:

#清除数据
[root@mysql-node1 ~]# /etc/init.d/mysqld stop 
[root@mysql-node1 ~]# rm -rf /data/mysql/*

#配置myc.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=1
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
gtid_mode=ON
enforce-gtid-consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin_load_add='group_replication.so'
transaction_write_set_extraction=XXHASH64
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address="172.25.250.10:33061"
group_replication_group_seeds="172.25.250.10:33061,172.25.250.20:33061,172.25.250.30:33061"
group_replication_ip_whitelist="172.25.250.0/24,127.0.0.1/8"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
group_replication_enforce_update_everywhere_checks=ON
group_replication_allow_local_disjoint_gtids_join=1

#初始化 
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
[root@mysql-node1 ~]# /etc/init.d/mysqld restart 
[root@mysql-node1 ~]# mysql -uroot -p'g*)lg0wf>?bY'    #此密码是初始化生成的

#配置sql
mysql> alter user root@localhost identified by 'redhat';
Query OK, 0 rows affected (0.01 sec)

mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)

mysql> create user howe@'%' identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)

mysql> grant replication slave on *.* to howe@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)

mysql> change master to master_user='howe',master_password='redhat' for channel 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

====================================

#只在node1上执行
mysql> set global group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> start group_replication;
Query OK, 0 rows affected, 1 warning (2.01 sec)

mysql> set global group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)
======================================
#
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST          | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
| group_replication_applier | 4ab28c48-6228-11ef-802a-000c29730697 | mysql-node1.exam.com |        3306 | ONLINE       |
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
1 row in set (0.00 sec)

全部主机做本地解析

[root@mysql-node1 ~]# vim /etc/hosts
[root@mysql-node1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.250.10   mysql-node1.exam.com
172.25.250.20   mysql-node2.exam.com
172.25.250.30   mysql-node3.exam.com

复制配置文件到myql-node20和mysql-node30

[root@mysql-node1 ~]# scp /etc/my.cnf root@172.25.250.20:/etc/my.cnf

[root@mysql-node1 ~]# scp /etc/my.cnf root@172.25.250.30:/etc/my.cnf

#再修改配置 例如id
 5 server-id=2        #node3写3
 19 group_replication_local_address="172.25.250.20:33061"    #node3为30

#重新初始化
[root@mysql-node2 ~]# rm -rf /data/mysql/*
[root@mysql-node2 ~]# mysqld --user=mysql --initialize

[root@mysql-node2 ~]# /etc/init.d/mysqld start 
Starting MySQL.Logging to '/data/mysql/mysql-node2.exam.com.err'.
 SUCCESS! 

#sql设置
mysql> alter user root@localhost identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)

mysql> set sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)

mysql> create user howe@'%' identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)

mysql> grant replication slave on *.* to howe@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> set sql_log_bin=1;
Query OK, 0 rows affected (0.00 sec)

mysql> change master to master_user='howe',master_password='redhat' for channel 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.02 sec)


mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected, 1 warning (5.69 sec)

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST          | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
| group_replication_applier | 2e6b21bd-622a-11ef-ab66-000c29bc9bab | mysql-node2.exam.com |        3306 | ONLINE       |
| group_replication_applier | 4ab28c48-6228-11ef-802a-000c29730697 | mysql-node1.exam.com |        3306 | ONLINE       |
+---------------------------+--------------------------------------+----------------------+-------------+--------------+
2 rows in set (0.00 sec)

效果:

测试:

在node1进行添写操作

[root@mysql-node1 ~]# mysql -uroot -predhat
mysql> create database howe;
Query OK, 1 row affected (0.00 sec)

mysql> create table howe.userlist(
    -> username varchar(10) primary key not null,
    -> password varchar(50) not null
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into howe.userlist values ('user1','111');
Query OK, 1 row affected (0.01 sec)

mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1    | 111      |
+----------+----------+
1 row in set (0.00 sec)

node2 进行添写操作

mysql> insert into howe.userlist values ('user2','222');
Query OK, 1 row affected (0.00 sec)

mysql> select * from howe.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1    | 111      |
| user2    | 222      |
+----------+----------+
2 rows in set (0.00 sec)

node3 上查看

'


五 mysql-router(mysql路由)

MySQL Router

是一个对应用程序透明的InnoDB Cluster连接路由服务,提供负载均衡、应用连接故障转移和客户端路由。

利用路由器的连接路由特性,用户可以编写应用程序来连接到路由器,并令路由器使用相应的路由策略 来处理连接,使其连接到正确的MySQL数据库服务器

Mysql route的部署方式

#安装mysql-router
[root@mysql-node1 ~]# rpm -ivh mysql-router-community-8.4.0-1.el7.x86_64.rpm 
warning: mysql-router-community-8.4.0-1.el7.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID a8d3785c: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-router-community-8.4.0-1.el################################# [100%]


#配置mysql-router
[root@mysql-node1 ~]# vim /etc/mysqlrouter/mysqlrouter.conf 
[routing:ro]
bind_address = 0.0.0.0
bind_port = 7001
destinations = 172.25.250.10:3306,172.25.250.20:3306,172.25.250.30:3306
routing_strategy = round-robin


#修改sql node(1,2,3)都要做
mysql> create user root@'%' identified by 'redhat';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all on *.* to root@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

#再回到node1连接
[root@mysql-node1 ~]# systemctl restart mysqlrouter.service 
[root@mysql-node1 ~]# netstat -lntup | grep 7001
tcp        0      0 0.0.0.0:7001            0.0.0.0:*               LISTEN      2740/mysqlrouter    

[root@mysql-node1 ~]# mysql -uroot -predhat -h 172.25.250.10 -p 7001

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)

mysql> quit
Bye

再来一次
mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+
1 row in set (0.00 sec)

查看调度效果

Note mysql router 并不能限制数据库的读写,访问分流


六 mysql高可用之MHA

6.1.MHA概述

MHA(Master High Availability)是一套用于 MySQL 高可用环境的解决方案。

一、主要功能

  1. 自动故障转移

    • 实时监控 MySQL 主服务器的状态,当主服务器出现故障时,自动将从服务器提升为新的主服务器,实现快速的故障转移,减少服务中断时间。
    • 能够在几秒内完成故障转移,确保数据库服务的高可用性。
  2. 数据一致性保证

    • 在故障转移过程中,MHA 会尝试从宕机的主服务器上保存尽可能多的二进制日志,以最大程度地保证数据的一致性。
    • 通过确保新主服务器上的数据与故障前的主服务器数据保持一致,减少了数据丢失和不一致的风险。
  3. 多从服务器支持

    • 可以管理多个从服务器,在故障转移时可以选择最佳的从服务器作为新的主服务器。
    • 支持不同拓扑结构的 MySQL 复制环境,包括一主多从、多主多从等。
  4. 手动干预和管理

    • 提供了命令行工具和脚本,允许管理员进行手动干预和管理,如手动触发故障转移、查看服务器状态等。
    • 管理员可以根据实际情况进行灵活的配置和调整。

二、工作原理

  1. 节点角色

    • MHA 环境中包含一个管理节点(Manager Node)和多个数据库节点(Database Node)。管理节点负责监控和管理整个高可用集群,数据库节点包括主服务器和从服务器。
    • 管理节点通常运行在独立的服务器上,与数据库节点通过网络进行通信。
  2. 监控机制

    • 管理节点定期通过 SSH 连接到数据库节点,检查 MySQL 服务的运行状态、复制状态和二进制日志位置等信息。
    • 如果发现主服务器出现故障,管理节点会立即启动故障转移流程。
  3. 故障转移流程

    • 首先,管理节点尝试从宕机的主服务器上保存未同步的二进制日志。
    • 然后,从多个从服务器中选择一个最佳的候选服务器,通常是数据最接近主服务器的从服务器。
    • 管理节点将候选服务器提升为新的主服务器,并更新其他从服务器的配置,使其指向新的主服务器进行复制。
    • 最后,管理节点可以选择尝试修复原来的主服务器,使其重新加入集群作为从服务器。

为什么要用MHA? Master的单点故障问题

什么是 MHA

  • MHA(Master High Availability)是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。
  • MHA 的出现就是解决MySQL 单点的问题。
  • MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作。
  • MHA能在故障切换的过程中最大程度上保证数据的一致性,以达到真正意义上的高可用。

MHA 的组成

  • MHA由两部分组成:MHAManager (管理节点) MHA Node (数据库节点),
  • MHA Manager 可以单独部署在一台独立的机器上管理多个master-slave集群,也可以部署在一台 slave 节点上。
  • MHA Manager 会定时探测集群中的 master 节点。
  • 当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master, 然后将所有其他的 slave 重新指向新的 master。

MHA 的特点

  • 自动故障切换过程中,MHA从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失
  • 使用半同步复制,可以大大降低数据丢失的风险,如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性
  • 目前MHA支持一主多从架构,最少三台服务,即一主两从

故障切换备选主库的算法

1.一般判断从库的是从(position/GTID)判断优劣,数据有差异,最接近于master的slave,成为备选主。

2.数据一致的情况下,按照配置文件顺序,选择备选主库。

3.设定有权重(candidate_master=1),按照权重强制指定备选主。

(1)默认情况下如果一个slave落后master 100M的relay logs的话,即使有权重,也会失效。

(2)如果check_repl_delay=0的话,即使落后很多日志,也强制选择其为备选主。

6.2 MHA部署实施

6.2.1 搭建主两从架构

master端
#本地解析+免密
172.25.250.10   mysql-node1.exam.com
172.25.250.20   mysql-node2.exam.com
172.25.250.30   mysql-node3.exam.com
172.25.250.50   mysql-mha.exam.com

[root@mysql-mha MHA-7]# ssh-keygen -t rsa
[root@mysql-mha MHA-7]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.250.10
[root@mysql-mha MHA-7]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.250.20
[root@mysql-mha MHA-7]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.250.30


#停掉后 恢复一主两从
[root@mysql-node3 ~]# /etc/init.d/mysqld stop 
Shutting down MySQL. SUCCESS! 

#my.cnf + stop
  1 [mysqld]
  2 datadir=/data/mysql
  3 socket=/data/mysql/mysql.sock
  4 symbolic-links=0
  5 server-id=1
  6 log-bin=mysql-bin
  7 gtid_mode=ON
  8 enforce-gtid-consistency=ON


#初始化 + start + 搭建一主两从
[root@mysql-node2 ~]# /etc/init.d/mysqld stop 
[root@mysql-node1 ~]# rm -rf /data/mysql/*
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
[root@mysql-node1 ~]# /etc/init.d/mysqld start 
Starting MySQL.Logging to '/data/mysql/mysql-node1.exam.com.err'.
 SUCCESS! 

#node1
[root@mysql-node1 ~]# mysql -uroot -p'u##JDyye#7i7'

mysql> alter user root@localhost identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)

mysql> create user howe@'%' identified by 'redhat';
Query OK, 0 rows affected (0.00 sec)

mysql> grant replication slave on *.* to howe@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.01 sec)

mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)

-------------------------------------------------
slave端
#node2 node3 
mysql> alter user root@localhost identified by 'redhat';

mysql> stop slave;

mysql> CHANGE MASTER TO MASTER_HOST='172.25.250.10', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;

mysql> start slave;

mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

mysql> SET GLOBAL rpl_semi_sync_slave_enabled =1;

mysql> STOP SLAVE IO_THREAD;

mysql> START SLAVE IO_THREAD;

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)
#如果出现OFF 检查master日志是否开启

6.2.2安装MHA所需要的软件

#在MHA中
[root@mysql-mha ~]# ls
anaconda-ks.cfg  master_ip_failover  master_ip_online_change  MHA-7.zip
[root@mysql-mha ~]# unzip MHA-7.zip 
[root@mysql-mha ~]# ls
anaconda-ks.cfg  master_ip_failover  master_ip_online_change  MHA-7  MHA-7.zip

[root@mysql-mha ~]# cd MHA-7/
[root@mysql-mha MHA-7]# ls
[root@mysql-mha MHA-7]# yum install *.rpm -y


[root@mysql-mha MHA-7]# mkdir /etc/mha
[root@mysql-mha MHA-7]# tar zxf mha4mysql-manager-0.58.tar.gz 
[root@mysql-mha MHA-7]# ls
[root@mysql-mha MHA-7]# cd mha4mysql-manager-0.58/
[root@mysql-mha mha4mysql-manager-0.58]# ls
AUTHORS  COPYING  lib          MANIFEST       README  samples  tests
bin      debian   Makefile.PL  MANIFEST.SKIP  rpm     t
[root@mysql-mha mha4mysql-manager-0.58]# cd samples/
[root@mysql-mha samples]# ls
conf  scripts
[root@mysql-mha samples]# cd conf/
[root@mysql-mha conf]# ls
app1.cnf  masterha_default.cnf
#定向为一个文件
[root@mysql-mha conf]# cat masterha_default.cnf app1.cnf > /etc/mha/app1.cnf

在软件中包含的工具包介绍

1.Manager工具包主要包括以下几个工具:

  • masterha_check_ssh #检查MHA的SSH配置状况
  • masterha_check_repl #检查MySQL复制状况
  • masterha_manger #启动MHA
  • masterha_check_status #检测当前MHA运行状态
  • masterha_master_monitor #检测master是否宕机
  • masterha_master_switch #控制故障转移(自动或者手动)
  • masterha_conf_host #添加或删除配置的server信息

2.Node工具包 (通常由masterHA主机直接调用,无需人为执行)

  • save_binary_logs #保存和复制master的二进制日志
  • apply_diff_relay_logs #识别差异的中继日志事件并将其差异的事件应用于其他的slave
  • filter_mysqlbinlog #去除不必要的ROLLBACK事件(MHA已不再使用这个工具)
  • purge_relay_logs #清除中继日志(不会阻塞SQL线程)

在node中

#mha端复制过去
[root@mysql-mha MHA-7]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.250.10:/root

[root@mysql-node1 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y

6.2.3 配置MHA 的管理环境

1.生成配置目录和配置文件

[root@mysql-mha ~]# mkdir /etc/mha
[root@mysql-mha MHA-7]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@mysql-mha MHA-7]# cd mha4mysql-manager-0.58/samples/conf/
[root@mysql-mha conf]# cat masterha_default.cnf app1.cnf > /etc/mha/app1.cnf

配置app1.cnf

2.检测配置:

检测网络及ssh免密

#进行免密
[root@mysql-mha .ssh]# ssh-keygen 

[root@mysql-mha ~]# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.25.250.10


[root@mysql-mha .ssh]# ssh-copy-id -i id_rsa.pub root@172.25.250.20

[root@mysql-mha .ssh]# ssh-copy-id -i id_rsa.pub root@172.25.250.30

[root@mysql-mha .ssh]# scp id_rsa root@172.25.250.10:/root/.ssh
          
[root@mysql-mha .ssh]# scp id_rsa root@172.25.250.20:/root/.ssh

[root@mysql-mha .ssh]# scp id_rsa root@172.25.250.30:/root/.ssh


#如果scp速度慢
[root@mysql-node1 ~]# vim /etc/ssh/sshd_config 
[root@mysql-node1 ~]# systemctl restart sshd
检测网络及ssh免密
masterha_check_ssh --conf=/etc/mha/app1.cnf
检测数据主从复制情况
[root@mysql-mha mha]# masterha_check_repl --conf=/etc/mha/app1.cnf

问题 一主两从检测不成功

检查my.cnf文件是否写入log-bin=mysql-bin


6.2.4 MHA的故障切换

MHA的故障切换过程

共包括以下的步骤:

1.配置文件检查阶段,这个阶段会检查整个集群配置文件配置

2.宕机的master处理,这个阶段包括虚拟ip摘除操作,主机关机操作

3.复制dead master和最新slave相差的relay log,并保存到MHA Manger具体的目录下

4.识别含有最新更新的slave

5.应用从master保存的二进制日志事件(binlog events)

6.提升一个slave为新的master进行复制

7.使其他的slave连接新的master进行复制

#在master数据节点还在正常工作情况下 
[root@mysql-mha ~]# masterha_master_switch \
--conf=/etc/mha/app1.cnf \
--master_state=alive \
--new_master_host=172.25.250.20 \
--new_master_port=3306 \
--orig_master_is_new_slave \
--running_updates_limit=10000

一路yes
#node1 中手动切换master到node2

CHANGE MASTER TO MASTER_HOST='172.25.250.20', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_HOST='172.25.250.20', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;

#最后检测一主两从
masterha_check_repl --conf=/etc/mha/app1.cnf
6.2.3.1 master故障手动切换

master切回node1

[root@mysql-node2 ~]# /etc/init.d/mysqld stop 
Shutting down MySQL........... SUCCESS! 

20>10
[root@mysql-mha masterha]# masterha_master_switch \
--master_state=dead \
--conf=/etc/mha/app1.cnf \
--dead_master_host=172.25.250.20 \
--dead_master_port=3306 \
--new_master_host=172.25.250.10 \
--new_master_port=3306 \
--ignore_last_failover
一路回车

--ignore_last_failover 表示忽略在/etc/masterha/目录中在切换过程中生成的锁文件

==================================================
#node2
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_HOST='172.25.250.10', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
同时检查node3 是否master回到node1

检测
masterha_check_repl --conf=/etc/mha/app1.cnf

6.2.3.2 自动切换
[root@mysql-mha ~]# cd /etc/mha/
[root@mysql-mha mha]# rm -rf app1.failover.complete	#删掉所文件
#监控程序通过指定配置文件监控master状态,当master出问题后自动切换并退出避免重复做故障切换

[root@mysql-mha mha]# masterha_manager --conf=/etc/mha/app1.cnf

停掉node1

恢复故障节点

[root@mysql-node1 ~]# /etc/init.d/mysqld start 
Starting MySQL. SUCCESS! 

#node2
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_HOST='172.25.250.10', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
同时检查node3 是否master回到node1

清除锁文件

[root@mysql-mha mha]# rm -rf app1.failover.complete

6.2.5 为MHA添加VIP功能

添加到/root

[root@mysql-mha ~]# cp master_ip_failover master_ip_online_change /usr/local/bin/
[root@mysql-mha ~]# chmod +x /usr/local/bin/master_ip_*

编辑文件

[root@mysql-mha ~]# vim /usr/local/bin/master_ip_failover

[root@mysql-mha ~]# vim /usr/local/bin/master_ip_online_change
#启动监控程序
masterha_manager --conf=/etc/mha/app1.cnf

##在master节点添加VIP
[root@mysql-node1 ~]# ip a a 172.25.250.100/24 dev eth0

#模拟故障
[root@mysql-node1 ~]# /etc/init.d/mysqld stop 
Shutting down MySQL............ SUCCESS! 

恢复故障主机

#新master中

CHANGE MASTER TO MASTER_HOST='172.25.250.10', MASTER_USER='howe',MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;

手动恢复后查看vip变化

[root@mysql-node2 ~]# /etc/init.d/mysqld stop 
Shutting down MySQL............ SUCCESS! 

CHANGE MASTER TO MASTER_HOST='172.25.250.10', MASTER_USER='howe',
MASTER_PASSWORD='redhat', MASTER_AUTO_POSITION=1;

masterha_master_switch \
--master_state=dead \
--conf=/etc/mha/app1.cnf \
--dead_master_host=172.25.250.10 \
--dead_master_port=3306 \
--new_master_host=172.25.250.20 \
--new_master_port=3306 --ignore_last_failover

检测一主两从
masterha_check_repl --conf=/etc/mha/app1.cnf

此时VIP已经回到master

相关推荐
nbsaas-boot16 分钟前
探索 JSON 数据在关系型数据库中的应用:MySQL 与 SQL Server 的对比
数据库·mysql·json
cmdch201717 分钟前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis
程序员学习随笔18 分钟前
PostgreSQL技术内幕21:SysLogger日志收集器的工作原理
数据库·postgresql
Sun_12_219 分钟前
SQL注入(SQL lnjection Base)21
网络·数据库
秦时明月之君临天下20 分钟前
PostgreSQL标识符长度限制不能超过63字节
数据库·postgresql
woshilys22 分钟前
sql server 备份恢复
数据库·sqlserver
CodeCraft Studio22 分钟前
【实用技能】如何在 SQL Server 中处理 Null 或空值?
数据库·oracle·sqlserver
奥顺34 分钟前
PHPUnit使用指南:编写高效的单元测试
大数据·mysql·开源·php
撒呼呼41 分钟前
# 起步专用 - 哔哩哔哩全模块超还原设计!(内含接口文档、数据库设计)
数据库·spring boot·spring·mvc·springboot
程序员shen1616111 小时前
抖音短视频saas矩阵源码系统开发所需掌握的技术
java·前端·数据库·python·算法