数据库英雄:探索MySQL高可用性的秘密武器

目录

一、引言

[1.1 数据库高可用性的重要性](#1.1 数据库高可用性的重要性)

[1.2 MySQL在现代架构中的角色](#1.2 MySQL在现代架构中的角色)

二、MySQL集群技术概览

[2.1 集群技术的定义和目标](#2.1 集群技术的定义和目标)

[2.2 MySQL集群的类型和用例](#2.2 MySQL集群的类型和用例)

三、搭建MySQL组从复制环境

[3.1 环境准备和依赖安装](#3.1 环境准备和依赖安装)

[3.2 配置组从复制](#3.2 配置组从复制)

[3.3 当有数据时添加slave2](#3.3 当有数据时添加slave2)

四、深入理解MySQL复制机制

[4.1 二进制日志(Binlog)的工作原理](#4.1 二进制日志(Binlog)的工作原理)

[4.2 复制过程的三个阶段](#4.2 复制过程的三个阶段)

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

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

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

五、半同步模式

5.1半同步模式原理

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

5.3启用半同步模式

[六、MySQL Group Replication (MGR) 实现](#六、MySQL Group Replication (MGR) 实现)

[6.1 MGR的架构和优势](#6.1 MGR的架构和优势)

[6.2 单主模式与多主模式的探讨](#6.2 单主模式与多主模式的探讨)

[6.3 配置和管理MGR集群](#6.3 配置和管理MGR集群)

[七、MySQL Router的部署与优化](#七、MySQL Router的部署与优化)

[7.1 路由服务的介绍](#7.1 路由服务的介绍)

[7.2 配置MySQL Router以优化连接](#7.2 配置MySQL Router以优化连接)

八、构建高可用环境:MHA解决方案

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

[8.3 手动和自动故障转移](#8.3 手动和自动故障转移)


一、引言

在当今的数字化时代,数据已成为企业最宝贵的资产之一。数据库系统作为存储、管理和检索这些数据的核心组件,其稳定性和可用性对业务的连续性和可靠性至关重要。高可用性(High Availability, HA)数据库解决方案确保了即使在面临硬件故障、软件崩溃或网络问题时,数据仍然可以被访问和处理,从而最大程度地减少系统停机时间。

1.1 数据库高可用性的重要性

数据库的高可用性(High Availability, HA)对于确保业务连续性和数据完整性至关重要。

  • 业务连续性:高可用性确保即使在硬件故障、软件故障或网络问题等情况下,数据库系统也能持续运行,从而减少业务中断的风险。

  • 数据完整性:通过实时数据备份和恢复机制,高可用性解决方案可以保护数据不受意外丢失或损坏的影响。

  • 性能优化:高可用性系统通常包括负载均衡和资源优化技术,以确保在高负载情况下数据库的性能不会显著下降。

  • 故障恢复:在发生故障时,高可用性系统能够快速识别问题并自动切换到备用系统,最小化系统停机时间。

  • 灾难恢复:高可用性通常与灾难恢复计划相结合,以确保在发生重大灾难时,数据和系统能够迅速恢复。

数据库的高可用性是确保企业能够在不断变化的市场环境中保持竞争力的关键因素之一。通过实施有效的高可用性策略,企业不仅能够保护其数据资产,还能够确保业务的稳定运行,从而在激烈的市场竞争中保持领先地位。

1.2 MySQL在现代架构中的角色

MySQL 在现代架构中扮演着核心的角色,它是一个关系型数据库管理系统,广泛应用于各种规模的应用程序中。

  • 数据存储和管理:MySQL 作为后端数据库,负责存储和管理应用程序的数据。它支持大量的数据存储,并提供数据的增删改查等操作。

  • 高并发处理:在高并发的 Web 应用和移动应用中,MySQL 通过其高效的查询处理和索引机制,能够处理大量的并发请求。

  • 数据完整性和安全性:MySQL 提供了强大的数据完整性和安全性保障,包括事务处理、备份和恢复、用户权限控制等。

  • 灵活性和可扩展性:MySQL 支持多种存储引擎,如 InnoDB 和 MyISAM,不同的存储引擎有不同的特性,可以根据应用需求选择合适的存储引擎。

  • 云集成:随着云计算的发展,MySQL 也能够很好地与云服务集成,提供云数据库服务,如自动扩展、备份和灾难恢复等。

在现代架构中,MySQL 不断适应新的技术趋势和需求,例如通过在线表结构变更(Online DDL)支持不阻塞 DML 和 DQL 操作的表结构修改,以及通过云服务提供高性能和低成本的数据架构解决方案。这些特性使得 MySQL 成为构建现代应用程序的可靠选择。


二、MySQL集群技术概览

2.1 集群技术的定义和目标

2.1.1 集群技术的定义

集群技术是将一组相互独立的计算机通过高速网络连接起来,组成一个计算机系统,从而以单一系统的模式加以管理。这些计算机可以是同构的,也可以是异构的。每个计算机在集群中被称为一个节点。集群中的节点可以协同工作,共同完成一个特定的任务,对外表现为一个统一的整体。

2.1.2 集群技术的目标

在现代架构中,集群技术的目标主要包括:

  • 高性能:通过分散负载和增加吞吐量来提高数据库的性能。在集群中,每个节点都可以处理一部分数据和请求,从而提高整个集群的性能。

  • 高可用性:即使一个或多个节点发生故障,集群中的其他节点也能自动接管故障节点的工作,确保服务的连续性和可靠性。这通常通过故障检测及迁移、多节点备份等机制实现。

  • 可伸缩性:集群可以通过增加或减少节点来适应不断变化的数据需求和业务增长,从而轻松地扩展系统的处理能力和存储容量。

  • 负载均衡:集群可以通过分散负载来避免单个节点过载,通过负载均衡技术,如基于轮询或基于权重的负载均衡,将请求分发到不同的节点上。

  • 数据安全:集群通过备份和数据复制来确保数据的安全性和可用性。在节点故障时,可以利用备份数据或复制数据来恢复服务。

2.2 MySQL集群的类型和用例

主从复制模式

  • 这是最常见的集群模式之一,一个主服务器(Master)负责所有的写操作,并将这些更改异步复制到一个或多个从服务器(Slave)上。这种模式可以提高读性能,因为读请求可以分散到多个从服务器上。但是,它可能存在数据延迟的问题,即从服务器的数据可能会有一定的延迟。
  • 对于读操作远远多于写操作的应用场景非常适用,比如电商网站的商品浏览页面,大量用户进行商品查询操作,而商品信息的更新相对较少。
  • 对数据安全性要求较高的系统,一旦主节点出现故障,可以快速切换到从节点,保证系统的可用性。

MySQL Cluster

  • 这是MySQL官方提供的集群解决方案,支持多主多从结构。它通过内存存储引擎NDB来整合多个MySQL实例,提供统一的服务集群。这种集群模式支持自动水平扩容和读写负载均衡,但可能以牺牲性能为代价来保证数据的强一致性。
  • 适用于对性能要求极高的实时应用,如高频交易系统、电信运营商的核心业务系统等。
  • 在大数据场景下,可以作为高速缓存层,提高数据的访问速度。

Galera 集群

  • 基于多主复制的架构,所有节点都可以同时读写数据。采用同步复制机制,保证数据的强一致性。具有自动故障转移和节点自动加入的功能。
  • 对于需要实时数据同步和高可用性的应用,如金融交易系统、在线游戏等,Galera 集群是一个很好的选择。
  • 在分布式系统中,Galera 集群可以提供可靠的数据存储和访问,确保各个节点的数据一致。

组复制(MySQL Group Replication)

  • 这是一种较新的集群技术,支持多主复制和自动故障切换。
  • 它适用于需要灵活复制基础设施的环境,如云数据库服务,以及需要高可用分片的场景。

三、搭建MySQL组从复制环境

3.1 环境准备和依赖安装

在企业中90%的服务器操作系统均为Linux ,对于Mysql的安装通常用源码编译的方式来进行

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

3.1.1 安装依赖性

dnf不行就用yum,之后相同

bash 复制代码
[root@mysql_1 ~]# dnf install cmake gcc-c++ openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen.x86_64

3.1.2 下载并解压源码包

bash 复制代码
[root@mysql_1 ~]# tar zxf mysql-boost-5.7.44.tar.gz
[root@mysql_1 ~]# cd /root/mysql-5.7.44

3.1.3 源码编译安装MySQL

bash 复制代码
[root@mysql_1  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_1 mysql-5.7.44]# make -j2            #核心就跑几个进程,不只是电脑上到核心,虚拟机也要配相应的核心,经我验证4核4gb最不容易出问题           
[root@mysql_1 mysql-5.7.44# make install

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

3.1.4 部署mysql

初始化失败就删掉mysql,之后再次初始化

rm -rf /data/mysql/*

bash 复制代码
#生成启动脚本
[root@mysql_1 ~]# dnf  install initscripts-10.11.6-1.el9.x86_64 -y
[root@mysql_1 ~]# cd /usr/local/mysql/support-files/
[root@node_1 support-files]# cp mysql.server /etc/init.d/mysqld

 #修改环境变量
[root@node10 ~]# vim ~/.bash_profile
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin

[root@mysql_1 ~]# source  ~/.bash_profile

#生成配置文件
[root@node_1 support-files]# yum install mariadb-connector-c-config-3.2.6-1.el9_0.noarch -y
[root@node_1 my.cnf.d]# vim /etc/my.cnf
#全删重写
[mysqld]
datadir=/data/mysql                            #指定数据目录
socket=/data/mysql/mysql.sock                  #指定套接字
symbolic-links=0                               #数据只能存放到数据目录中,禁止链接到数据目录

 #数据库初始化建立mysql基本数据
[root@mysql_1 ~]# mysqld --initialize --user=mysql
[root@mysql_1 ~]# /etc/init.d/mysqld start
[root@mysql_1 ~]# chkconfig  mysqld on

#数据库安全初始化
[root@mysql_1 ~]# 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) : y
 Success.
 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) 
: y- Dropping test database...
 Success.- Removing privileges on test database...
 Success.
 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) : y
 Success.

测试

3.2 配置组从复制

修改密码

alter user root@localhost identified by 'your passwd';

3.2.1 配置mastesr

bash 复制代码
[root@mysql_1 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 symbolic-links=0
 log-bin=mysql-bin
 server-id=1

[root@mysql_1 ~]# /etc/init.d/mysqld restart

 #进入数据库配置用户权限
[root@mysql_1 ~]# mysql -uroot -p123
 mysql> CREATE USER 'repl'@'%' IDENTIFIED BY '123';        #生成专门用来做复制的用户,此用户是用于slave端做认证用 
 mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'%';        #对这个用户进行授权
 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)

3.2.2 配置salve

bash 复制代码
[root@mysql_2 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 symbolic-links=0
 log-bin=mysql-bin
 server-id=2

[root@mysql_2 ~]# /etc/init.d/mysqld restart
[root@mysql_2 ~]# mysql -uroot -p123
mysql>  CHANGE MASTER TO MASTER_HOST='172.25.254.10',MASTER_USER='repl',MASTER_PASSWORD='123',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.06 sec)

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

测试

bash 复制代码
#在master中写入数据
mysql>  CREATE DATABASE lee;
Query OK, 1 row affected (0.00 sec)

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

mysql>  INSERT INTO lee.userlist VALUE ('lee','123');
Query OK, 1 row affected (0.01 sec)

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

#在slave中查看数据是否有同步过来
mysql>  SELECT * FROM lee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| lee      | 123      |
+----------+----------+
1 row in set (0.00 sec)

3.3 当有数据时添加slave2

bash 复制代码
#完成基础配置
[root@mysql-node3 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 symbolic-links=0
 server-id=3
[root@mysql-node3 ~]# /etc/init.d/mysqld restart

#从master节点备份数据
[root@mysql_1 ~]# mysqldump -uroot -p123 lee > zpy.sql
[root@mysql_1 ~]# rsync -al lee.sql root@172.25.254.30:/mnt/

#利用master节点中备份出来的zpy.sql在slave2中拉平数据
[root@mysql_3 mnt]# mysql -uroot -p123456 zpy < zpy.sql
[root@mysql_3 mnt]# mysql -uroot -p123456

mysql> change master to master_host='172.25.254.10',master_user='repl',master_password='123',master_log_file='mysql-bin.000001',master_log_pos=799;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

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

测试

bash 复制代码
mysql> INSERT INTO lee.userlist VALUES('lee2','123');
Query OK, 1 row affected (0.01 sec)


四、深入理解MySQL复制机制

4.1 二进制日志(Binlog)的工作原理

三个线程

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

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

4.2 复制过程的三个阶段

步骤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?

  • 当读取的而操作远远高与写操作时。我们采用一主多从架构
  • 数据库外层接入负载均衡层并搭配高可用机制

4.3 延迟复制

  • 延迟复制时用来控制sql线程的,和i/o线程无关
  • 这个延迟复制不是i/o线程过段时间来复制,i/o是正常工作的
  • 是日志已经保存在slave端了,那个sql要等多久进行回放
bash 复制代码
#在slave1上做
mysql> stop slave sql_thread;
Query OK, 0 rows affected (0.01 sec)

mysql>  change master to master_delay=60;
Query OK, 0 rows affected (0.00 sec)

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

mysql>  show slave status\G;
             Master_Info_File: /data/mysql/master.info
                    SQL_Delay: 60
          SQL_Remaining_Delay: NULL

测试

bash 复制代码
#在master上新增一组数据
mysql> INSERT INTO lee.userlist VALUES('lee3','123');
Query OK, 1 row affected (0.01 sec)

在slave2上已经传过来了

过60秒之后,salve1才传过来

4.4 慢查询日志

  • 慢查询,顾名思义,执行很慢的查询
  • 当执行SQL超过long_query_time参数设定的时间阈值(默认10s)时,就被认为是慢查询,这个 SQL语句就是需要优化的
  • 慢查询被记录在慢查询日志里
  • 慢查询日志默认是不开启的
  • 如果需要优化SQL语句,就可以开启这个功能,它可以让你很容易地知道哪些语句是需要优化的
bash 复制代码
mysql> SHOW variables  like "slow%";
+---------------------+------------------------------+
| Variable_name       | Value                        |
+---------------------+------------------------------+
| slow_launch_time    | 2                            |
| slow_query_log      | OFF                          |
| slow_query_log_file | /data/mysql/mysql_1-slow.log |
+---------------------+------------------------------+
3 rows in set (0.00 sec)

mysql>  SET GLOBAL slow_query_log=ON;        #慢查询日志开启
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW VARIABLES like "slow%";
+---------------------+------------------------------+
| Variable_name       | Value                        |
+---------------------+------------------------------+
| slow_launch_time    | 2                            |
| slow_query_log      | ON                           |
| slow_query_log_file | /data/mysql/mysql_1-slow.log |
+---------------------+------------------------------+
3 rows in set (0.00 sec)


mysql>  SET long_query_time=5;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES like "long%";
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 5.000000 |
+-----------------+----------+
1 row in set (0.01 sec)

测试

4.5 mysql的并行复制

  • 默认情况下slave中使用的是sql单线程回放
  • 在master中时多用户读写,如果使用sql单线程回放那么会造成组从延迟严重
  • 开启MySQL的多线程回放可以解决上述问题
bash 复制代码
#在salve2中做
[root@mysql_3 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=2
 gtid_mode=ON
 enforce-gtid-consistency=ON
 slave-parallel-type=LOGICAL_CLOCK              #基于组提交  
 slave-parallel-workers=16                      #开启线程数量
 master_info_repository=TABLE                   #master信息在表中记录,默认记录
 relay_log_info_repository=TABLE                #回放日志信息在表中记录,默认记录
 relay_log_recovery=ON                          #日志回放恢复功能开启

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

测试

此时sql线程转化为协调线程,16个worker负责处理sql协调线程发送过来的处理请求

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


五、半同步模式

5.1半同步模式原理

  • 用户线程写入完成后master中的dump会把日志推送到slave端
  • slave中的io线程接收后保存到relaylog中继日志
  • 保存完成后slave向master端返回ack
  • 在未接受到slave的ack时master端时不做提交的,一直处于等待当收到ack后提交到存储引擎
  • 在5.6版本中用到的时after_commit模式,after_commit模式时先提交在等待ack返回后输出ok

5.2 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

bash 复制代码
[root@mysql_1 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=1
 log-bin=mysql-bin
 gtid_mode=ON
 enforce-gtid-consistency=ON
 symbolic-links=0

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


[root@mysql_2 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=2
 log-bin=mysql-bin
 gtid_mode=ON
 enforce-gtid-consistency=ON
 symbolic-links=0

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


[root@mysql_3 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=3
 log-bin=mysql-bin
 gtid_mode=ON
 enforce-gtid-consistency=ON
 symbolic-links=0

[root@mysql_3 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS! 
Starting MySQL. SUCCESS! 
bash 复制代码
#停止slave端
[root@mysql_2 ~]# mysql -uroot -p123
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)


[root@mysql_3 ~]# mysql -uroot -p123
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
bash 复制代码
 #开启slave端的gtid(2和3)
mysql>  CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl', 
    -> MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.05 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 

5.3启用半同步模式

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

bash 复制代码
[root@mysql_1 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=1
 log-bin=mysql-bin
 gtid_mode=ON
 enforce-gtid-consistency=ON
 rpl_semi_sync_master_enabled=1             #开启半同步功能         
 symbolic-links=0

[root@mysql_1 ~]# mysql -uroot -p123
#安装半同步插件
mysql>  INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.01 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)

5.3.2 在slave端开启半同步功能

bash 复制代码
#2,3都做
[root@mysql-node2 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=1
 log-bin=mysql-bin
 gtid_mode=ON
 enforce-gtid-consistency=ON
 rpl_semi_sync_master_enabled=1          
symbolic-links=0

[root@mysql-node2 ~]# mysql -p123
mysql>  INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.06 sec)

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

#重启io线程,半同步才能生效
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    |
+---------------------------------+-------+
2 rows in set (0.04 sec)

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

测试

bash 复制代码
mysql>  insert  into lee.userlist values ('lee4','123');
Query OK, 1 row affected (0.01 sec)

mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name                              | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients               | 2     |
| Rpl_semi_sync_master_net_avg_wait_time     | 0     |
| Rpl_semi_sync_master_net_wait_time         | 0     |
| Rpl_semi_sync_master_net_waits             | 2     |
| 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      | 1464  |
| Rpl_semi_sync_master_tx_wait_time          | 1464  |
| Rpl_semi_sync_master_tx_waits              | 1     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 1     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

模拟故障

bash 复制代码
#在slave端
[root@mysql-node2 ~]# mysql -uroot -p123
 mysql> STOP SLAVE IO_THREAD;
 Query OK, 0 rows affected (0.00 sec)

#在master端插入数据
mysql> insert  into lee.userlist values ('lee5','555');
Query OK, 1 row affected (10.01 sec)

mysql>  SHOW STATUS LIKE 'Rpl_semi%';
+--------------------------------------------+-------+
| 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             | 1     |
| Rpl_semi_sync_master_no_times              | 1     |
| Rpl_semi_sync_master_no_tx                 | 1     |
| Rpl_semi_sync_master_status                | OFF   |
| Rpl_semi_sync_master_timefunc_failures     | 0     |
| Rpl_semi_sync_master_tx_avg_wait_time      | 1464  |
| Rpl_semi_sync_master_tx_wait_time          | 1464  |
| Rpl_semi_sync_master_tx_waits              | 1     |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
| Rpl_semi_sync_master_wait_sessions         | 0     |
| Rpl_semi_sync_master_yes_tx                | 1     |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)

六、MySQL Group Replication (MGR) 实现

6.1 MGR的架构和优势

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

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

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

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

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

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

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

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

6.2 单主模式与多主模式的探讨

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

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

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

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

6.3 配置和管理MGR集群

配置mastesr

bash 复制代码
[root@mysql_1 ~]# vim /etc/my.cnf
[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"     #主机白名单
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_1 ~]# rm -fr /data/mysql/*
[root@mysql_1 ~]# /etc/init.d/mysqld stop
[root@mysql_1 ~]# mysqld --user=mysql --initialize
[root@mysql_1 ~]# /etc/init.d/mysqld start
[root@mysql_1 ~]# mysql -uroot -p'eRmb0A00O<qS'
mysql>  alter user root@localhost identified by '123';        
Query OK, 0 rows affected (0.01 sec)

mysql>  SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.01 sec)

mysql>  CREATE USER rpl_user@'%' IDENTIFIED BY '123';
ERROR 1396 (HY000): Operation CREATE USER failed for 'rpl_user'@'%'
Query OK, 0 row in set (0.00 sec)

mysql>  GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
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='rpl_user', MASTER_PASSWORD='123' FOR CHAANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.02 sec)

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.13 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 | 7137d804-6aaf-11ef-8c10-000c29416836 | mysql_1.timinglee.org |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-----------------------+-------------+--------------+
1 row in set (0.00 sec)
mysql> \q

[root@mysql_1 ~]# vim /etc/hosts            #在2和3中都要写,不然加入组后会报错
172.25.254.10   mysql_1.timinglee.org
172.25.254.20   mysql_2.timinglee.org
172.25.254.30   mysql_3.timinglee.org

[root@mysql_1 ~]# scp /etc/my.cnf root@172.25.254.20:/etc/my.cnf       
[root@mysql_1 ~]# scp /etc/my.cnf root@172.25.254.30:/etc/my.cnf

配置slave

在最后检查组成员时都表示online就说明一切正常,如果发现最后一段是recover或是error就是报错。

首先在hosts中检查有没有进行域名解析

其次,检查my.cnf,查漏补缺

最后看有没有按步骤来,一步都不能少或错,检查字母

报错就删除重来 rm -fr /data/mysql/*

bash 复制代码
[root@mysql_2 & 3 ~]# rm -fr /data/mysql/*
[root@mysql_2 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 symbolic-links=0
 server-id=2                 #在3上写3
 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.254.20:33061"       #在3上要写30
 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"
 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_2 ~]# /etc/init.d/mysqld stop
[root@mysql_2 ~]# mysqld --user=mysql --initialize
[root@mysql_2 ~]# /etc/init.d/mysqld start
[root@mysql_2 ~]# mysql -uroot -p'q(wPj>(u3jar'
mysql>  SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

mysql>  CREATE USER rpl_user@'%' IDENTIFIED BY '123';
Query OK, 0 rows affected (0.00 sec)

mysql>  GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)

mysql>  FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)

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

mysql>  CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='123' FOR CHAANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

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

#都表示online就说明配置完成
mysql>  SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-----------------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST           | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-----------------------+-------------+--------------+
| group_replication_applier | 052988a3-6ab1-11ef-82f3-000c294691e8 | mysql_2.timinglee.org |        3306 | ONLINE       |
| group_replication_applier | 5a65cf1a-6ab2-11ef-ae8a-000c29bff379 | mysql_3.timinglee.org |        3306 | ONLINE       |
| group_replication_applier | 7137d804-6aaf-11ef-8c10-000c29416836 | mysql_1.timinglee.org |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-----------------------+-------------+--------------+
3 rows in set (0.01 sec)

测试

在每个节点都可以完成读写

bash 复制代码
#在mysql_1中
mysql> create database lee;
Query OK, 1 row affected (0.01 sec)

mysql>  CREATE TABLE lee.userlist(
    -> username VARCHAR(10) PRIMARY KEY NOT NULL,
    ->  password VARCHAR(50) NOT NULL
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>  INSERT INTO lee.userlist VALUES ('user1','111');
Query OK, 1 row affected (0.06 sec)

mysql>  SELECT * FROM lee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1    | 111      |
+----------+----------+
1 row in set (0.00 sec)

#在mysql_2中
mysql>  INSERT INTO lee.userlist values ('user2','222');
Query OK, 1 row affected (0.47 sec)

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

#在mysql_3中
mysql>  INSERT INTO lee.userlist values ('user3','333');
Query OK, 1 row affected (0.01 sec)

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

七、MySQL Router的部署与优化

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

7.1 路由服务的介绍

MySQL Router

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

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

7.2 配置MySQL Router以优化连接

bash 复制代码
#我是直接上传的rpm文件
[root@mysql_1 ~]# ls
anaconda-ks.cfg                                公共
initial-setup-ks.cfg                           模板
lee.sql                                        视频
libtirpc-devel-0.2.4-0.16.el7.x86_64.rpm       图片
mysql-5.7.44                                   文档
mysql-boost-5.7.44.tar.gz                      下载
mysql-router-community-8.4.0-1.el7.x86_64.rpm  音乐
passwd                                         桌面
timinglee.sql

#安装mysql-router
[root@mysql_1 ~]# rpm -ivh mysql-router-community-8.4.0-1.el7.x86_64.rpm
bash 复制代码
 #配置mysql-router
[root@mysql_1 ~]# /etc/init.d/mysqld stop
Shutting down MySQL............ SUCCESS! 

[root@mysql_1 ~]# vim /etc/mysqlrouter/mysqlrouter.conf 
#两种模式
[routing:ro]
bind_address = 0.0.0.0
bind_port = 7001
destinations = 172.25.254.20:3306,172.25.254.30:3306
routing_strategy = round-robin

[routing:rw]
bind_address = 0.0.0.0
bind_port = 7002
destinations = 172.25.254.30:3306,172.25.254.20:3306
routing_strategy = first-available

[root@mysql_1 ~]# systemctl start mysqlrouter.service

测试

bash 复制代码
#在2和3上建立测试用户
mysql> CREATE USER lee@'%' IDENTIFIED BY 'lee';
mysql> GRANT ALL ON lee.* TO lee@'%';

#远程登录
[root@mysql-router ~]# mysql -ulee -plee -h 172.25.254.40 -P 7001

进入查看id,后退出,再进入再查看id,就不一样了。就是实现了负载均衡,轮训调度


八、构建高可用环境:MHA解决方案

8.1 MHA的工作原理和概述

7.1.1 MHA的概述

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

7.1.2 MHA 的组成

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

7.1.3 MHA 的特点

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

7.1.4 故障切换备选主库的算法

  • 一般判断从库的是从(position/GTID)判断优劣,数据有差异,最接近于master的slave,成为备选 主。
  • 数据一致的情况下,按照配置文件顺序,选择备选主库。
  • 设定有权重(candidate_master=1),按照权重强制指定备选主。
  • 默认情况下如果一个slave落后master 100M的relay logs的话,即使有权重,也会失效。
  • 如果check_repl_delay=0的话,即使落后很多日志,也强制选择其为备选主

7.1.5MHA工作原理

  • 目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群必须最少有3台数据库服务器, 一主二从,即一台充当Master,台充当备用Master,另一台充当从库
  • MHA Node 运行在每台 MySQL 服务器上
  • MHAManager 会定时探测集群中的master 节点
  • 当master 出现故障时,它可以自动将最新数据的slave 提升为新的master
  • 然后将所有其他的slave 重新指向新的master,VIP自动漂移到新的master
  • 整个故障转移过程对应用程序完全透明

8.2 MHA部署实施

8.2.1 搭建主两从架构

bash 复制代码
#在master节点中
[root@mysql_1 ~]# /etc/init.d/mysqld stop
Shutting down MySQL... SUCCESS! 
[root@mysql_1 ~]# rm -fr /data/mysql/*
[root@mysql_1 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=1
 log-bin=mysql-bin
 gtid_mode=ON
 log_slave_updates=ON
 enforce-gtid-consistency=ON
 symbolic-links=0

[root@mysql_1 ~]# mysqld --user=mysql --initialize
[root@mysql_1 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql_1.timinglee.org.err'.
 SUCCESS! 
[root@mysql_1 ~]# mysql -uroot -p'34j7MQ#pqecw'
mysql> alter user root@localhost identified by '123';
Query OK, 0 rows affected (0.00 sec)

mysql>  CREATE USER 'repl'@'%' IDENTIFIED BY '123';
Query OK, 0 rows affected (0.00 sec)

mysql>  GRANT REPLICATION SLAVE ON *.* TO repl@'%';
Query OK, 0 rows affected (0.01 sec)

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

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


#在slave1和slave2中
[root@mysql_2 ~]# /etc/init.d/mysqld stop
Shutting down MySQL. SUCCESS! 
[root@mysql_2 ~]# rm -fr /data/mysql/*
[root@mysql_2 ~]# vim /etc/my.cnf
 [mysqld]
 datadir=/data/mysql
 socket=/data/mysql/mysql.sock
 server-id=1
 log-bin=mysql-bin
 gtid_mode=ON
 log_slave_updates=ON
 enforce-gtid-consistency=ON
 symbolic-links=0

[root@mysql_2 ~]# mysqld --user=mysql --initialize
[root@mysql_2 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql_2.timinglee.org.err'.
 SUCCESS! 
[root@mysql_2 ~]# mysql -uroot -p'epgKi5kv4w+h'
mysql> alter user root@localhost identified by '123';
Query OK, 0 rows affected (0.01 sec)

mysql>  CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl', 
    -> MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.05 sec)

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

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.01 sec)

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

8.2.2安装MHA所需要的软件

在mha主机中做免密认证

bash 复制代码
#先在四台主机上做解析
[root@mysql-mha ~]# vim /etc/hosts
172.25.254.40   mysql-mha.timinglee.org
172.25.254.10   mysql_1.timinglee.org
172.25.254.20   mysql_2.timinglee.org
172.25.254.30   mysql_3.timinglee.org

#进行免密认证
[root@mysql-mha ~]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:G1N3JNJ3t5FsZRbmSD0ZkizBqaWyXK2KzydEG6kqkvQ root@mysql-mha.timinglee.org
The key's randomart image is:
+---[RSA 2048]----+
|          oo=o=+X|
|           *o=*@o|
|        . * oooo=|
|       = = o . . |
|      + S .      |
| .   . = =       |
|... . o o        |
|o. E ..o .       |
|. .   .oo        |
+----[SHA256]-----+

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

下载压缩包文件

bash 复制代码
[root@mysql-mha ~]# unzip MHA-7.zip 
[root@mysql-mha ~]# cd MHA-7/
[root@mysql-mha MHA-7]# ls
mha4mysql-manager-0.58-0.el7.centos.noarch.rpm
mha4mysql-manager-0.58.tar.gz
mha4mysql-node-0.58-0.el7.centos.noarch.rpm
perl-Config-Tiny-2.14-7.el7.noarch.rpm
perl-Email-Date-Format-1.002-15.el7.noarch.rpm
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
perl-MIME-Lite-3.030-1.el7.noarch.rpm
perl-MIME-Types-1.38-2.el7.noarch.rpm
perl-Net-Telnet-3.03-19.el7.noarch.rpm
perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm

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

将node包发送至节点端
[root@mysql-mha MHA-7]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.10:/root   
[root@mysql-mha MHA-7]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.20:/root   
[root@mysql-mha MHA-7]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.30:/root

#在三个节点处下载node包
[root@mysql_1 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y
[root@mysql_2 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y
[root@mysql_3 ~]# yum install mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y

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

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线程

8.2.3 配置MHA 的管理环境

  • 因为我们当前只有一套主从,所以我们只需要写一个配置文件即可
  • rpm包中没有为我们准备配置文件的模板
  • 可以解压源码包后在samples中找到配置文件的模板文件
bash 复制代码
[root@mysql-mha ~]# mkdir /etc/masterha
[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/masterha/app1.cnf
[root@mysql-mha ~]# vim /etc/masterha/app1.cnf 
[server default]
user=root
password=123
ssh_user=root
repl_user=repl
repl_password=123
master_binlog_dir= /data/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.11        #第二个-s后跟的必须是server里没有的ip,之后必须添加上
ping_interval=3
# master_ip_failover_script= /script/masterha/master_ip_failover
# shutdown_script= /script/masterha/power_manager
# report_script= /script/masterha/send_report
# master_ip_online_change_script= /script/masterha/master_ip_online_change
[server default]
manager_workdir=/etc/masterha
manager_log=/etc/masterha/manager.log

[server1]
hostname=172.25.254.10
candidate_master=1
check_repl_delay=0

[server2]
hostname=172.25.254.20
candidate_master=1
check_repl_delay=0

[server3]
hostname=172.25.254.30
no_master=1

[root@mysql_2 ~]# ip a a 172.25.254.11/24 dev eth0

允许远程连接

#因为1是master,所以2和3就不用做了
[root@mysql_1 ~]# mysql -uroot -p123

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

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


[root@mysql-mha ~]# cd .ssh/
[root@mysql-mha .ssh]# ls
id_rsa  id_rsa.pub  known_hosts
[root@mysql-mha .ssh]# scp id_rsa 172.25.254.10:/root/.ssh/
id_rsa                                            100% 1675   529.6KB/s   00:00    
[root@mysql-mha .ssh]# scp id_rsa 172.25.254.20:/root/.ssh/
id_rsa                                            100% 1675   529.1KB/s   00:00    
[root@mysql-mha .ssh]# scp id_rsa 172.25.254.30:/root/.ssh/
id_rsa                                            100% 1675   593.2KB/s   00:00   

测试

8.2.4 检测配置

检测网络及ssh

检测主从复制

[root@mysql-mha .ssh]#  masterha_check_repl --conf=/etc/masterha/app1.cnf

8.3 手动和自动故障转移

MHA的故障切换过程 共包括以下的步骤:

  • 配置文件检查阶段,这个阶段会检查整个集群配置文件配置
  • 宕机的master处理,这个阶段包括虚拟ip摘除操作,主机关机操作
  • 复制dead master和最新slave相差的relay log,并保存到MHA Manger具体的目录下
  • 识别含有最新更新的slave
  • 应用从master保存的二进制日志事件(binlog events)
  • 提升一个slave为新的master进行复制
  • 使其他的slave连接新的master进行复制

8.3.1 master未出现故障手动切换

oot@mysql-mha ~]# masterha_master_switch \

--conf=/etc/masterha/app1.cnf \ #指定配置文件

--master_state=alive \ #指定master节点状态

--new_master_host=172.25.254.20 \ #指定新master节点

--new_master_port=3306 \ #执行新master节点端口

--orig_master_is_new_slave \ #原始master会变成新的slave

--running_updates_limit=10000 #切换的超时时间

bash 复制代码
[root@mysql-mha ~]# masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=172.25.254.20 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000

It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 172.25.254.10(172.25.254.10:3306)? (YES/no): yes

Starting master switch from 172.25.254.10(172.25.254.10:3306) to 172.25.254.20(172.25.254.20:3306)? (yes/NO): yes

master_ip_online_change_script is not defined. If you do not disable writes on the current master manually, applications keep writing on the current master. Is it ok to proceed? (yes/NO): yes

测试

8.3.2 master故障手动切换

bash 复制代码
[root@mysql-mha ~]# masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=172.25.254.20 --dead_master_port=3306 --new_master_host=172.25.254.10 --new_master_port=3306 --ignore_last_failover

Master 172.25.254.20(172.25.254.20:3306) is dead. Proceed? (yes/NO): yes

Starting master switch from 172.25.254.20(172.25.254.20:3306) to 172.25.254.10(172.25.254.10:3306)? (yes/NO): yes

测试

恢复故障mysql节点

bash 复制代码
[root@mysql_2 ~]# /etc/init.d/mysqld start
Starting MySQL.. SUCCESS! 
[root@mysql_2 ~]# mysql -uroot -p123
mysql>  CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='repl',MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.05 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 172.25.254.10
                  Master_User: repl
                  Master_Port: 3306

8.3.3 自动切换

bash 复制代码
 #删掉切换锁文件
[root@mysql-mha masterha]#  rm -fr app1.failover.complete

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

#模拟master故障
[root@mysql_1 ~]# /etc/init.d/mysqld stop
这时候那个监测自己就停止了。 

恢复故障节点
[root@mysql_1 ~]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!
[root@mysql_1 ~]# mysql -uroot -p123
mysql>  CHANGE MASTER TO MASTER_HOST='172.25.254.20', MASTER_USER='repl', MASTER_PASSWORD='123', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 172.25.254.20
                  Master_User: repl
                  Master_Port: 3306
相关推荐
代码中の快捷键4 分钟前
MySQL数据库存储引擎
数据库·mysql
只因在人海中多看了你一眼4 分钟前
数据库体系
数据库
尘浮生26 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君40 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队1 小时前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
inventecsh1 小时前
mongodb基础操作
数据库·mongodb
白云如幻1 小时前
SQL99版链接查询语法
数据库·sql·mysql
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
The_Ticker3 小时前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程