什么是 MySQL 的主从复制
- Mysql内建的复制功能是构建大型高性能应用程序的基础, 将Mysql数据分布到多个系统上,这种分布机制是通过将Mysql某一台主机数据复制到其它主机(slaves)上,并重新执行一遍来实现的。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后*并等待主服务器通知新的更新。
为什么需要主从复制
- 1. 数据分布 (Data distribution )
- 2. 负载平衡(load balancing)
- 3. 据备份(Backups) ,保证数据安全
- 4. 高可用性和容错行(High availability and failover)
- 5. 实现读写分离,缓解数据库压力
MySQL复制所带来的优势在于
- 扩展能力:通过复制功能可以将MySQL的性能压力分担到一个或多个slave上。这要求所有 的写操作和修改操作都必须在Master上完成,而读操作可以被分配到一个或多个slave上;将读写分离到不同服务器执行之后, MySQL的读写性能得到提升。
- 数据库备份:由于从实例是同步主实例的数据,所以可以将备份作业部署到从库。
- 数据分析和报表:同样,一些数据分析和报表的实现可以在从实例执行,以减少对主库的性能影响。
- 容灾能力:可以在物理距离较远的另一个数据中心建立一个slave,保证在主实例所在地区遭遇灾难时,在另一个数据中心能快速恢复。
MySQL复制有两种方法:
- 传统方式: 基于主库的bin-log将日志事件和事件位置复制到从库,从库再加以应用来达到主从同步的目的。
- Gtid方式: global transaction identifiers是基于事务来复制数据,因此也就不依赖日志文件,同时又能更好的保证主从库数据一致性。
MySQL复制有多种类型:
- 异步复制:客户端发送DDL/DML语句给master,master执行完毕立即返回成功信息给客户端,而不管slave是否已经开始复制。这样的复制方式导致的问题是,当master写完了binlog,而slave还没有开始复制或者复制还没完成时,slave上和master上的数据暂时不一致,且此时master突然宕机,slave将会丢失一部分数据。如果此时把slave提升为新的master,那么整个数据库就永久丢失这部分数据。
- 同步复制:客户端发送DDL/DML语句给master,master执行完毕后还需要等待所有的slave都写完了relay log才认为此次DDL/DML成功,然后才会返回成功信息给客户端。同步复制的问题是master必须等待,所以延迟较大,在MySQL中不使用这种复制方式。
- 半同步复制:在异步复制的基础上,确保任何一个主库上的事务在提交之前至少有一个从库已经收到该事务并日志记录下来,即客户端发送DDL/DML语句给master,master执行完毕后还要等待一个slave写完relay log并返回确认信息给master,master才认为此次DDL/DML语句是成功的,然后才会发送成功信息给客户端。半同步复制只需等待一个slave的回应,且等待的超时时间可以设置,超时后会自动降级为异步复制,所以在局域网内(网络延迟很小)使用半同步复制是可行的
- 延迟复制:在异步复制的基础上,人为设定主库和从库的数据同步延迟时间,即保证数据延迟至少是这个参数
MySQL复制有三种核心格式:
- 基于语句的复制: 在主服务器执行SQL语句,在从服务器执行同样语句。MySQL默认采用基于语句的复制,效率较高。一旦发现没法精确复制时, 会自动选基于行的复制。
- 基于行的复制: 把改变的内容复制过去,而不是把命令在从服务器上执行一遍. 从mysql5.0开始支持
- 混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。
MySQL 的复制原理
- master 服务器将数据的改变记录二进制 binlog 日志,当 master 上的数据发生改变时,则将其改变写入二进制日志中;
- slave 服务器会在一定时间间隔内对 master 二进制日志进行探测其是否发生改变,如果发生改变,则开始一个 I/OThread 请求 master 二进制事件;
- 同时主节点为每个 I/O 线程启动一个 dump 线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动 SQL 线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后 I/OThread 和 SQLThread 将进入睡眠状态,等待下一次被唤醒。
也就是:
- 从库会生成两个线程,一个 I/O 线程,一个 SQL 线程;
- I/O 线程会去请求主库的 binlog,并将得到的 binlog 写到本地的 relay-log(中继日志)文件中;主库会生成一个 log dump 线程,用来给从库 I/O 线程传 binlog;
- SQL 线程,会读取 relay log 文件中的日志,并解析成sql语句逐一执行。
注意:
- master 将操作语句记录到 binlog 日志中,然后授予 slave 远程连接的权限(master 一定要开启 binlog 二进制日志功能;通常为了数据安全考虑,slave 也开启binlog功能);
- slave 开启两个线程:IO 线程和 SQL 线程。其中:IO 线程负责读取 master 的 binlog 内容到中继日志 relay log 里;SQL 线程负责从 relay log 日志里读出 binlog 内容,并更新到 slave 的数据库里,这样就能保证 slave 数据和 master 数据保持一致了;
- MySQL 复制至少需要两个 MySQL 的服务,当然 MySQL 服务可以分布在不同的服务器上,也可以在一台服务器上启动多个服务;
- MySQL复制最好确保 master 和 slave 服务器上的 MySQL 版本相同(如果不能满足版本一致,那么要保证 master 主节点的版本低于 slave 从节点的版本);
- master 和 slave 两节点间时间需同步。
- 默认情况下,MySQL的复制是异步的。slave可以不用一直连着master,即使中间断开了也能从断开的position处继续进行复制。
- 复制是基于binlog的position进行的,复制之前必须保证position一致。(注:这是传统的复制方式所要求的)
- 二进制日志目的是为了恢复定点数据库和主从复制,所以出于安全和功能考虑,极不建议将二进制日志和datadir放在同一磁盘上。
复制全局:
复制过滤:
具体步骤:
- 第一步、在主服务器上记录二进制日志。在每个更新数据的事务完成之前,主服务器都会将数据更改记录到二进制日志中。即使事务在执行期间是交错的,mysql也会串行地将事务写入到二进制日志中。在把事件写入二进制日志之后,主服务器告诉存储引擎提交事务。
- 第二步、从服务器把主服务器的二进制日志拷贝到自己的硬盘上,进入所谓的“中继日志”中。首先,它启动一个工作线程,叫I/O线程,这个I/O线程开启一个普通的客户端连接,然后启动一个特殊的二进制日志转储进程(它没有相应的SQL命令)。这个转储进程从主服务器的二进制日志中读取数据。它不会对事件进行轮询。如果3跟上了主服务器,就会进入休眠状态并等待有新的事件发生时主服务器发出的信号。I/O线程把数据写入从服务器的中继日志中。
- 第三步、SQL线程读取中继日志,并且重放其中的事件,然后更新从服务器的数据。由于这个线程能跟上I/O线程,中继日志通常在操作系统的缓存中,所以中继日志的开销很低。SQL线程执行事件也可以被写入从服务器自己的二进制日志中,它对于有些场景很实用。
配置主从复制,可以总结为如下的步骤:
- 1.在主服务器上,必须开启二进制日志机制和配置一个独立的ID
- 2.在每一个从服务器上,配置一个唯一的ID,创建一个用来专门复制主服务器数据的账号
- 3.在开始复制进程前,在主服务器上记录二进制文件的位置信息
- 4.如果在开始复制之前,数据库中已经有数据,就必须先创建一个数据快照(可以使用mysqldump导出数据库,或者直接复制数据文件)
- 5.配置从服务器要连接的主服务器的IP地址和登陆授权,二进制日志文件名和位置
官方YUM安装过程:https://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html
如何安装MySQL5.7.34(指定版本),可参考:https://www.cnblogs.com/zhangwencheng/p/15045074.html , MySQL5.7最新版本5.7.35(2021-08)
准备环境:
属性 | mysql 主 | mysql 从 |
节点 | Mysql-Master01 | Mysql-Slave01 |
系统 | CentOS Linux release 7.5.1804 (Minimal) | CentOS Linux release 7.5.1804 (Minimal) |
内核 | 3.10.0-862.el7.x86_64 | 3.10.0-862.el7.x86_64 |
SELinux | setenforce 0 | disabled | setenforce 0 | disabled |
Firewlld | systemctl stop/disable firewalld | systemctl stop/disable firewalld |
IP地址 | 172.16.70.37 | 172.16.70.181 |
MySQL异步复制(过滤)部署过程。
- Master01和Slave01 同样的操作;以Master01为例。
# yum安装MySQL5.7(默认最新版本)
[root@Mysql-Master01 ~]# wget https://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/mysql57-community-release-el7-10.noarch.rpm
[root@Mysql-Master01 ~]# yum localinstall -y mysql57-community-release-el7-10.noarch.rpm
[root@Mysql-Master01 ~]# yum repolist enabled | grep "mysql.*-community.*"
[root@Mysql-Master01 ~]# yum install -y mysql-community-server
--------------------------------------------------------------------------------------------------------------------------
# 安装MySQL5.7.34(指定版本),必须按顺序安装(common-->libs-->client-->server)
# CentOS7版本需要先清理系统默认自带安装了MariaDB。
[root@Mysql-Master01 ~]# ls
mysql-community-client-5.7.34-1.el7.x86_64.rpm mysql-community-libs-5.7.34-1.el7.x86_64.rpm
mysql-community-common-5.7.34-1.el7.x86_64.rpm mysql-community-server-5.7.34-1.el7.x86_64.rpm [root@Mysql-Master01 ~]# rpm -ivh mysql-community-common-5.7.34-1.el7.x86_64.rpm
[root@Mysql-Master01 ~]# rpm -ivh mysql-community-libs-5.7.34-1.el7.x86_64.rpm
[root@Mysql-Master01 ~]# rpm -ivh mysql-community-client-5.7.34-1.el7.x86_64.rpm
[root@Mysql-Master01 ~]# rpm -ivh mysql-community-server-5.7.34-1.el7.x86_64.rpm
==========================================================================================================================
# 启动mysqld
[root@Mysql-Master01 ~]# systemctl start mysqld
[root@Mysql-Master01 ~]# netstat -nutpl | grep mysql
tcp6 0 0 :::3306 :::* LISTEN 5059/mysqld
[root@Mysql-Master01 ~]# ps -ef | grep mysql
mysql 5059 1 0 14:38 ? 00:00:02 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid # mysql安全初始化
[root@Mysql-Master01 ~]# grep 'temporary password' /var/log/mysqld.log
2021-08-12T02:11:09.461541Z 1 [Note] A temporary password is generated for root@localhost: 2ofTdw8ntD>V [root@Mysql-Slave01 ~]# mysql_secure_installation Securing the MySQL server deployment. Enter password for user root: # 输入上面的初始密码 2ofTdw8ntD>V
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root. Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : y # 是否修改root密码 New password: # 输入符合密码策略的root密码 Re-enter new password: # 再次输入 Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y # 是否希望继续使用所提供的密码
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 # 是否禁止root远程登录
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 # 是否删除test库和对test库的访问权限
- 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. All done!
- Master01上操作。
[root@Mysql-Master01 ~]# mysql -V
mysql Ver 14.14 Distrib 5.7.34, for Linux (x86_64) using EditLine wrapper # 设置master01的my.cnf(必须在[mysqld]配置区域)
[root@Mysql-Master01 ~]# cat /etc/my.cnf
[mysqld]
......
# 新增以下内容
server-id = 37
log-bin = master-bin
binlog-do-db = mydb
binlog-ignore-db = mydb1
binlog-format = mixed
sync_binlog = 1
expire_logs_days = 30
skip_name_resolve = ON 参数说明:
server-id master01服务器唯一ID,一般IP最后一段,主从不能重复
log-bin 开启bin-log,并可指定文件文件目录和前缀
binlog-do-db 需要同步的数据库;如需同步多个库写多行即可;如不写此行,默认同步所有库
binlog-ignore-db 无需同步的数据库;如无需同步多个库写多行即可;也可以在一行,各库名用逗号隔开
binlog-format 二进制日志格式,有row、statement、mixed三种格式,
row指的是把改变的内容复制过去,而不是把命令在从服务器上执行一遍,
statement指的是在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。
mixed指的是默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制;可防止主键重复。
sync_binlog 确保binlog日志写入后与硬盘同步
expire_logs_days 自动清理 7 天前的log文件,可根据需要修改
skip_name_resolve 跳过反向域名解析 # 重启MySQL
[root@Mysql-Master01 ~]# systemctl restart mysqld # 测试登录msyql
[root@Mysql-Master01 ~]# mysql -uroot -p
Enter password: # 创建测试库mydb (对应配置文件my.cnfd的binlog-do-db)
mysql> CREATE DATABASE IF NOT EXISTS mydb;
Query OK, 1 row affected (0.00 sec) mysql> use mydb;
Database changed
mysql> CREATE TABLE IF NOT EXISTS tb1 (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.01 sec) mysql> INSERT INTO mydb.tb1 VALUES(1,"zhangsan"),(2,"lisi");
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM mydb.tb1;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | lisi |
+----+----------+
2 rows in set (0.00 sec) # 创建测试库mydb1 (对应配置文件my.cnfd的binlog-ignore-db)
mysql> CREATE DATABASE IF NOT EXISTS mydb1;
Query OK, 1 row affected (0.00 sec) mysql> CREATE TABLE IF NOT EXISTS tb2 (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.03 sec) mysql> INSERT INTO mydb1.tb2 VALUES(1,"wangwu"),(2,"zhaoliu");
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT * FRoM mydb1.tb2;
+----+---------+
| id | name |
+----+---------+
| 1 | wangwu |
| 2 | zhaoliu |
+----+---------+
2 rows in set (0.00 sec) mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mydb |
| mydb1 |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec) mysql> show variables like 'server_id'; # 查看服务器唯一ID
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 37 |
+---------------+-------+
1 row in set (0.00 sec) mysql> show variables like '%log_bin%'; # 查看是否开启log_bin
+---------------------------------+---------------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/master-bin |
| log_bin_index | /var/lib/mysql/master-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+---------------------------------+
6 rows in set (0.00 sec) mysql> show master logs;
+-------------------+-----------+
| Log_name | File_size |
+-------------------+-----------+
| master-bin.000003 | 154 |
+-------------------+-----------+
3 rows in set (0.00 sec) mysql> GRANT REPLICATION SLAVE ON *.* TO 'backup'@'172.16.%.%' IDENTIFIED BY 'Backup@01'; # 建立backup账户并授权slave
Query OK, 0 rows affected, 1 warning (0.00 sec) 语句说明:
(1) replication slave为mysql同步的必须权限,此处不要授权all权限
(2) *.* 表示所有库所有表,也可以指定具体的库和表进行复制。例如mydb.tb1中,mydb为库名,tb1为表名
(3) 'backup'@'172.16.%.%' backup为同步账号。172.16.%.%为授权主机网段,使用了%表示允许整个172.16.0.0网段可以用backup这个用户访问数据库
(4) identified by 'Backup@01'; Backup@01为密码,实际环境下设置复杂密码 mysql> flush privileges; # 刷新权限
Query OK, 0 rows affected (0.01 sec) mysql> select user,host from mysql.user where user='backup'; # 查看是否存在backup用户
+--------+------------+
| user | host |
+--------+------------+
| backup | 172.16.%.% |
+--------+------------+
1 row in set (0.01 sec) mysql> show grants for backup@'172.16.%.%'; # 查看backup用户授权
+---------------------------------------------------------+
| Grants for backup@172.16.%.% |
+---------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'backup'@'172.16.%.%' |
+---------------------------------------------------------+
1 row in set (0.00 sec) mysql> flush table with read lock; # 对主数据库锁表只读,防止导出数据库的时候有数据写入。unlock tables命令解除锁定
Query OK, 0 rows affected (0.00 se mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name | Value |
+-----------------------------+----------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| have_statement_timeout | YES |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 | # 自动解锁时间受本参数影响
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| rpl_stop_slave_timeout | 31536000 |
| slave_net_timeout | 60 |
| wait_timeout | 28800 | # 自动解锁时间受本参数影响
+-----------------------------+----------+
13 rows in set (0.00 sec) mysql> show master status; # 锁表后查看主库状态
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000003 | 154 | mydb | mydb1 | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec) # 锁表后,一定要单开一个新的SSH窗口,导出mydb数据库,发送至slave
[root@Mysql-Master01 ~]# mysqldump -uroot mydb -p > /tmp/mydb.sql
Enter password:
[root@Mysql-Master01 ~]# ls /tmp/mydb.sql
/tmp/mydb.sql
[root@Mysql-Master01 ~]# rsync -avz /tmp/mydb.sql root@172.16.70.181:/tmp/
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '172.16.70.181' (ECDSA) to the list of known hosts.
root@172.16.70.181's password: # slave服务器root密码 #导出数据完毕后,解锁主库
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
- Slave01上的操作。
[root@Mysql-Slave01 ~]# mysql -V
mysql Ver 14.14 Distrib 5.7.34, for Linux (x86_64) using EditLine wrapper # 设置slave01的my.cnf(必须在[mysqld]配置区域)
[mysqld]
......
# 新增以下内容
server-id = 181
log-bin = slave-bin
replicate-do-db = mydb
replicate-ignore-db = mydb1
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index 参数说明:
server-id slave01服务器唯一ID,一般IP最后一段,主从不能重复
log-bin 开启bin-log,并可指定文件文件目录和前缀
replicate-do-db 需要同步的数据库名。如果不指明同步哪些库,就去掉这行,表示所有库的同步(除了ignore忽略的库)
replicate-ignore-db 无需同步的数据库
relay-log 将主服务器上同步日志文件记录到本地
relay-log-index 定义 relay-log 的位置和名称 # 重启MySQL
[root@Mysql-Slave01 ~]# systemctl restart mysqld # 登录mysql
[root@Mysql-Slave01 ~]# mysql -p
Enter password: mysql> show variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 181 |
+---------------+-------+
1 row in set (0.01 sec) mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------+
| Variable_name | Value |
+---------------------------------+--------------------------------+
| log_bin | ON |
| log_bin_basename | /var/lib/mysql/slave-bin |
| log_bin_index | /var/lib/mysql/slave-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+--------------------------------+
6 rows in set (0.00 sec) # slave创建mydb空库,否则下面导入数据时会报错说此库不存在
mysql> CREATE DATABASE IF NOT EXISTS mydb;
Query OK, 1 row affected (0.01 sec) mysql> source /tmp/mydb.sql # 配置主从同步指令
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.01 sec) mysql> change master to master_host='172.16.70.37',master_port=3306,master_user='backup',master_password='Backup@01',master_log_file='master-bin.000003',master_log_pos=154;
Query OK, 0 rows affected, 2 warnings (0.03 sec) 参数说明:(提示:字符串用单引号括起来,数值不用引号,注意内容前后不能有空格。)
change master to
master_host='172.16.70.37' # master主库IP
master_port=3306 # 数据库端口号
master_user='backup' # master上创建用于复制的用户
master_password='Backup@01' # 复制用户的密码
master_log_file='master-bin.000003' # show master status时查看到的二进制日志文件名称,注意不能多空格
master_log_pos=154; # show master status时查看到的二进制日志偏移量,注意不能多空格 # 上述操作的原理实际上是把用户密码等信息写入从库新的master.info文件中
/var/lib/mysql/master.info
[root@Mysql-Slave01 ~]# cat /var/lib/mysql/master.info
25
master-bin.000004
154
172.16.70.37
backup
Backup@01
3306
60
0
..... 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.16.70.37
Master_User: backup
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000004
Read_Master_Log_Pos: 154
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 321
Relay_Master_Log_File: master-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB: mydb
Replicate_Ignore_DB: mydb1
Replicate_Do_Table:
......................
Seconds_Behind_Master: 0
...................... 如上,当IO和SQL线程的状态均为Yes,则表示主从已实现同步了!(主从同步是否成功,最关键的为下面的3项状态参数)
Slave_IO_Running: Yes,这个时I/O线程状态,I/O线程负责从从库到主库读取binlog日志,并写入从库的中继日志,状态为Yes表示I/O线程工作正常。
Slave_SQL_Running: Yes,这个是SQL线程状态,SQL线程负责读取中继日志(relay-log)中的数据并转换为SQL语句应用到从数据库中,状态为Yes表示I/O线程工作正常。
Seconds_Behind_Master:0,这个是复制过程中从库比主库延迟的秒数,这个参数极度重要,但企业里更准确地判断主从延迟的方法为:在主库写时间戳,然后从库读取时间戳,和当前数据库时间进行比较,从而认定是否延迟。 测试mysql主从复制效果。 # 先在mastet01上操作,当配置文件my.cnf存在binlog-do-db参数时,必须进入该库创建
mysql> use mydb;
mysql> select database();
+------------+
| database() |
+------------+
| mydb |
+------------+
1 row in set (0.00 sec) mysql> insert into mydb.tb1 values(11,"chenqi");
mysql> select * from mydb.tb1;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | lisi |
| 11 | chenqi |
+----+----------+
4 rows in set (0.00 sec) #然后slave01上查看是否自动同步
mysql> select database();
+------------+
| database() |
+------------+
| NULL |
+------------+
1 row in set (0.00 sec) mysql> select * from mydb.tb1;
+----+----------+
| id | name |
+----+----------+
| 1 | zhangsan |
| 2 | lisi |
| 11 | chenqi |
+----+----------+
3 rows in set (0.00 sec) 至此,MySQL主从复制(Binlog)已经实现!
以上都是在Mysql-Master主数据库和Mysql-Slave01从数据库之间实现的基于binlog的主从复制,即"一主一从"架构。 现在再把Mysql-Slave02的从节点添加进去,调整为"一主两从"的同步架构。
- Slave02上的操作如下:
# 关闭firewalld及SELinux
[root@Mysql-Slave02 ~]# systemctl stop firewalld && systemctl disable firewalld
[root@Mysql-Slave02 ~]# setenforce 0
[root@Mysql-Slave02 ~]# sed -i '7s/enforcing/disabled/' /etc/selinux/config # 设置相同时区,时间
[root@Mysql-Slave02 ~]# yum install -y ntp
[root@Mysql-Slave02 ~]# systemctl start ntpd && systemctl enable ntpd
[root@Mysql-Slave02 ~]# timedatectl set-timezone Asia/Shanghai [root@Mysql-Slave02 ~]# hostname -I
172.16.70.182 # yum安装mysql5.7
[root@Mysql-Slave02 ~]# yum localinstall -y mysql57-community-release-el7-10.noarch.rpm
[root@Mysql-Slave02 ~]# mysql -V
mysql Ver 14.14 Distrib 5.7.35, for Linux (x86_64) using EditLine wrapper 启动MySQL
[root@Mysql-Slave02 ~]# systemctl start mysqld && systemctl enable mysqld
[root@Mysql-Slave02 ~]# netstat -nutpl | grep mysql
tcp6 0 0 :::3306 :::* LISTEN 2613/mysqld
[root@Mysql-Slave02 ~]# ps -ef | grep mysql
mysql 2613 1 0 15:42 ? 00:00:00 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid # MySQL安全初始化
[root@Mysql-Slave02 ~]# grep 'temporary password' /var/log/mysqld.log
2021-08-18T07:42:42.208560Z 1 [Note] A temporary password is generated for root@localhost: hlu?dn31d)N# [root@Mysql-Slave02 ~]# mysql_secure_installation
......
......跟前面Slave01同样的设置 # Slave02的my.cnf与Slave01的只区别于server-id
[mysqld]
......
server-id = 182
log-bin = slave-bin
replicate-do-db = mydb
replicate-ignore-db = mydb1
relay-log = relay-log-bin
relay-log-index = slave-relay-bin.index # 重启MySQL
[root@Mysql-Slave02 ~]# systemctl restart mysqld # 后面的操作完全与Slave01的一致即可,不再赘述。
- Mysql主从复制延时
1、如何查看主从延迟时间
通过监控 show slave status 命令输出的Seconds_Behind_Master参数的值来判断:
Seconds_Behind_Master=0: 表示主从复制良好;
Seconds_Behind_Master=NULL: 表示io_thread或是sql_thread有任何一个发生故障;
Seconds_Behind_Master=n: 数字越大表示从库延迟越严重。 2、影响延迟因素
这里整理了影响主从复制延迟大致有以下几个原因:
1)主节点如果执行一个很大的事务,那么就会对主从延迟产生较大的影响
2)网络延迟,日志较大,slave数量过多
3)主上多线程写入,从节点只有单线程同步
4)机器性能问题,从节点是否使用了“烂机器”
5)锁冲突问题也可能导致从机的SQL线程执行慢 3、优化主从复制延迟
这个没有说去完全解决,要想解决那么就只能采用同步复制策略。不过,一般不建议使用这种同步模式。显而易见,如果写操作必须等待更新同步完成,肯定会
极大地影响性能,除非你不在乎性能。
1)大事务:将大事务分为小事务,分批更新数据
2)减少Slave的数量,不要超过5个,减少单次事务的大小
3)MySQL 5.7之后,可以使用多线程复制,使用MGR复制架构
4)在磁盘、raid卡、调度策略有问题的情况下可能会出现单个IO延迟很高的情况,可用iostat命令查看DB数据盘的IO情况,再进一步判断
5)针对锁问题可以通过抓去processlist以及查看information_schema下面和锁以及事务相关的表来查看
附:如何重置mysql root密码?
一、 在已知MYSQL数据库的ROOT用户密码的情况下,修改密码的方法:
在SHELL环境下,使用mysqladmin命令设置:
mysqladmin –u root –p password “新密码” 回车后要求输入旧密码 在mysql>环境中,使用update命令,直接更新mysql库user表的数据:
Update mysql.user set password=password(‘新密码’) where user=’root’;
flush privileges;
注意:mysql语句要以分号”;”结束 在mysql>环境中,使用grant命令,修改root用户的授权权限。
grant all on *.* to root@’localhost’ identified by ‘新密码’; 二、 如忘记了mysql数据库的ROOT用户的密码,又如何做呢?方法如下:
关闭当前运行的mysqld服务程序:service mysqld stop(要先将mysqld添加为系统服务)
使用mysqld_safe脚本以安全模式(不加载授权表)启动mysqld 服务
/usr/local/mysql/bin/mysqld_safe --skip-grant-table & 使用空密码的root用户登录数据库,重新设置ROOT用户的密码
#mysql -u root
Mysql> Update mysql.user set password=password(‘新密码’) where user=’root’;
Mysql> flush privileges;