第二十七课预习任务
1.MySQL主从介绍
1.1 Mysql的Replication(复制)是一个异步的复制过程,从一个 Mysql instance(我们称之为 Master)复制到另一个Mysql instance(我们称之 Slave)。在 Master 与 Slave之间的实现整个复制过程主要由三个线程来完成,其中两个线程(Sql线程和IO线程)在 Slave 端,另外一个线程(IO线程)在Master端。
1.2 MySQL主从原理
主库上的二进制bin-log中记录主库的所有DML操作,同时在主库上运行有一个IO线程,用于响应从库上的bin-log日志读取请求;在从库上运行有一个IO线程和一个SQL线程,IO线程会实时通过网络请求去从库上读取bin-log日志,然后写入到自身的relay-log日志文件中,同时运行在从库上的SQL线程会去解析并读取relay-log,然后在自身库上执行读取到的SQL,完成主从数据的同步,示意图如下:
a、主库上会开启了二进制bin-log日志记录,同时运行有一个IO线程;
b、主库上对于需要同步的数据库或者表所发生的所有DML操作都会被记录到bin-log二进制日志文件中;
c、从库上开启relay-log日志,同时运行有一个IO线程和一个SQL线程;
d、IO线程负责从主库中读取bin-log二进制日志,并写入到本地的relay-log日志中,同时记录从库所读取到的主库的日志文件位置信息,以便下次从这个位置点再次读取;
e、SQL线程负责从本地的relay-log日志中读取同步到的二进制日志,并解析为数据库可以识别的SQL语句,然后应用到本地数据库,完成同步;
f、执行完relay-log中的操作之后,进入睡眠状态,等待主库产生新的更新;
2.准备工作
1.首先我们需要准备两台虚拟机并装上mysql这个安装方法就不多介绍了。
这是第一台虚拟机我们会把这台做为主,也就是服务器IP地址:192.168.139.168
ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:ec:fc:cf brd ff:ff:ff:ff:ff:ff
inet 192.168.139.168/24 brd 192.168.139.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:feec:fccf/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
[[email protected] ~]# ps aux |grep mysql
root 919 0.0 0.1 115432 1704 ? S Oct10 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=/data/mysql/mysql.pid
mysql 1099 0.0 45.9 1302800 459000 ? Sl Oct10 1:08 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/mysql/error.log --pid-file=/data/mysql/mysql.pid --socket=/tmpmysql.sock
root 4461 0.0 0.0 112704 956 pts/1 R+ 01:34 0:00 grep --color=auto mysql
这是第二台虚拟机也就是从。这个IP地址:192.168.139.112
ens36: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:b1:e4:36 brd ff:ff:ff:ff:ff:ff
inet 192.168.139.112/24 brd 192.168.139.255 scope global noprefixroute dynamic ens36
valid_lft 3119sec preferred_lft 3119sec
[[email protected] ~]# ps aux |grep mysql
root 870 0.0 0.1 115432 1684 ? S Sep14 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/data/mysql --pid-file=/data/mysql/knightlai.pid
mysql 1033 0.0 45.3 1302728 452976 ? Sl Sep14 2:09 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/data/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=knightlai.err --pid-file=/data/mysql/knightlai.pid
root 14268 0.0 0.0 112704 960 pts/0 R+ 06:19 0:00 grep --color=auto mysql
两台虚拟机上安装都是mysql 5.6
主
[[email protected] ~]# mysql --version
/usr/local/mysql/bin/mysql Ver 14.14 Distrib 5.6.39, for linux-glibc2.12 (x86_64) using EditLine wrapp
从
[[email protected] ~]# mysql --version
/usr/local/mysql/bin/mysql Ver 14.14 Distrib 5.6.39, for linux-glibc2.12 (x86_64) using EditLine wrapp
3.配置主
3.1 修改配置文件
[[email protected] ~]# vim /etc/my.cnf
server_id=168
log_bin=master
[[email protected] ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
(1)server-id:用来标识一个唯一的实例,如果是在同一个局域网内,可以使用ip地址的最后一段,要保证唯一
(2)log_bin:二进制日志文件的路径,mysql用户对该路径必须具有读写权限
3.2 备份相关数据库文件
//备份一个zrlog库
[[email protected] ~]# mysqldump -uroot -p123456 zrlog > /tmp/zrlog.sql
Warning: Using a password on the command line interface can be insecure.
//新建一个test2018库用来测试
[[email protected] ~]# mysql -uroot -p123456 -e "create database test2018"
Warning: Using a password on the command line interface can be insecure.
//将zrlog库的数据恢复到test2018中
[[email protected] ~]# mysql -uroot -p123456 test2018 </tmp/zrlog.sql
Warning: Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| test |
| test2018 |
| zrlog |
+--------------------+
3.3 创建同步数据用户
//给从服务器上面的相关用户配置权限
[[email protected] ~]# mysql -uroot -p123456
mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* to 'repl'@'192.168.139.112' IDENTIFIED BY 'repl';
Query OK, 0 rows affected (0.00 sec)
//刷新表并锁表,为了保证数据的一致性
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)
查看主库的二进制日志文件及位置点
mysql> show master status;
+---------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------+----------+--------------+------------------+-------------------+
| master.000007 | 120 | | | |
+---------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
4. 配置从
4.1 修改配置文件
//配置server-id需要和主上不一样
[[email protected] ~]# vim /etc/my.cnf
server-id=169
[[email protected] ~]# /etc/init.d/mysqld restart
Shutting down MySQL.... SUCCESS!
Starting MySQL........... SUCCESS!
4.2 将主上的数据库导入从中
//将主上的数据库文件同步从上
[[email protected] ~]# scp 192.168.139.168:/tmp/*.sql /tmp/
The authenticity of host '192.168.139.168 (192.168.139.168)' can't be established.
ECDSA key fingerprint is SHA256:JEmKUtRSqXMbbymFgNEWnDQEgCUTjzFYFays6NrK58c.
ECDSA key fingerprint is MD5:2c:c4:cf:bc:1a:b8:f5:e2:03:2c:22:c3:0f:53:5c:be.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.139.168' (ECDSA) to the list of known hosts.
[email protected]'s password:
test2018.sql 100% 16KB 777.8KB/s 00:00
zrlog.sql 100% 16KB 2.9MB/s 00:00
//登录数据库创建数据库并恢复数据
[[email protected] ~]# mysql -uroot
mysql> create database zrlog;
Query OK, 1 row affected (0.00 sec)
mysql> create database test2018;
Query OK, 1 row affected (0.00 sec)
//将数据恢复到数据库中
[[email protected] ~]# mysqldump -uroot zrlog</tmp/zrlog.sql
-- MySQL dump 10.13 Distrib 5.6.39, for linux-glibc2.12 (x86_64)
--
-- Host: localhost Database: zrlog
-- ------------------------------------------------------
-- Server version 5.6.39
/*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */;
/*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;
[[email protected] ~]# mysqldump -uroot test2018</tmp/test2018.sql
-- MySQL dump 10.13 Distrib 5.6.39, for linux-glibc2.12 (x86_64)
--
-- Host: localhost Database: test2018
-- ------------------------------------------------------
-- Server version 5.6.39
/*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */;
/*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;
/*!40101 SET @[email protected]@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
4.3 启动主从同步
修改从库上的master指向,使其指向主库,并且从主库上最新的二进制日志和位置点开始同步,然后启动主从同步
mysql> CHANGE MASTER TO master_host = '192.168.139.168',master_port = 3306,master_user='repl',master_password='repl',master_log_file='master.000007',master_log_pos = 120;
Query OK, 0 rows affected, 2 warnings (0.07 sec)
master_host:主库的主机名或者IP地址
master_port:主库的端口号,必须为整数,不能加引号,否则会提示错误
master_user:在主库上添加的复制用户名称
master_password:在主库上添加的复制用户密码
master_log_file:主库当前的二进制日志文件名称
master_log_pos:主库当前的二进制文件位置点,整数,不可加引号,否则会提示错误
mysql> start slave;
Query OK, 0 rows affected (0.03 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Connecting to master
Master_Host: 127.0.0.1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master.000007
Read_Master_Log_Pos: 120
Relay_Log_File: knightlai-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: master.000007
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
上述结果中Slave_IO_Running和Slave_SQL_Running都为Yes表示主从同步成功
5.测试主从同步
5.1 在主机器上创建一个库
mysql> create database test1012;
Query OK, 1 row affected (0.04 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| test |
| test1012 |
| test2018 |
| zrlog |
+--------------------+
8 rows in set (0.06 sec)
//删除一个库文件
mysql> drop test2018;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'test2018' at line 1
mysql> drop database test2018;
Query OK, 9 rows affected (1.09 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| test |
| test1012 |
| zrlog |
+--------------------+
7 rows in set (0.00 sec)
5.2 在从机器上查询库
//可以看到我们刚刚在主上面创建的库test1012就表示成功了!
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| test1012 |
| test2018 |
| zrlog |
+--------------------+
7 rows in set (0.06 sec)
//刚刚在主上面删除的test2018在从机器上也被删除了
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| test1012 |
| zrlog |
+--------------------+
6 rows in set (0.00 sec)
5.3 主从同步中常见的问题
(1)从库的IO线程无法连接,通过"show slave status G"可以查看到具体的错误信息
原因1:在主库上创建的用户授权错误,导致从库无法远程连接主库
解决办法1:在主库上通过"show grants for 'user'@'ip';"查看授权是否正确,如果错误,重新授权即可
原因2:如果是独立主机上的两个主从数据库实例,授权正确的情况下,可能是由于主库的防火墙拦截导致从库无法连接主库
解决办法2:关闭主库的防火墙,或者在主库所在服务器添加防火墙规则,允许从库的tcp连接
(2)从库启动的时候提示server-id冲突,导致无法同步主库上的数据
原因:主从库配置文件中的server-id相同了
解决办法:将主库可从库配置文件中的server-id改为不同,重新开启从库上的同步即可
(3)在从库上执行了创建库或者表的操作,然后在主库上又执行了一遍,导致同步错误,如下:
Last_SQL_Error: Error 'Can't create database 'test1'; database exists' on query. Default database: 'test1'. Query: 'create database test1'
原因:从库上创建了库,主库上再次创建,从库会将主库上的创建过程再次应用到从库,导致从库上创建同名的库,发生错误
解决办法:停止从库,然后设置sql_slave_skip_count,使其跳过同步主库创建库的操作,从下一个操作开始同步,如下:
#停止从库
mysql-server-3307> STOP SLAVE;
Query OK, 0 rows affected (0.00 sec)
#向前跳跃一步,从下一个点开始同步
mysql-server-3307> SET GLOBAL sql_slave_skip_counter =1;
Query OK, 0 rows affected (0.00 sec)
#重新开启从库上的同步
mysql-server-3307> START SLAVE ;
Query OK, 0 rows affected (0.03 sec)
#再次查看,发现已经正常
针对直接写从库的操作,可以再从库上创建一个普通用户,授予其部分操作权限,然后设置从库的只读,通过在从库的配置文件中增加"read-only"参数来设置。但是注意,这个参数对而且只对非super用户生效,对root用户没有任何效果。
13、再生产场景下如何保证主库上的用户可以有写权限,从库上的用户只有读权限
方法1:在设置从库同步的时候,排除对mysql系统库的同步,通过在配置文件中指定binlog_ignore_db=mysql来排除不需要同步的库,或者在配置文件中指定binlog_do_db=db_name只来同步需要同步的库,然后分别在主库上创建可以写的用户,在从库上创建只能读的用户;
[mysqld]
binlog_ignore_db=mysql
binlog_do_db=user_db
方法2:在未排除任何库的情况下,先在主库上创建可以读写的用户,然后在从库中从新回收用户的写权限;
方法3:在主库和从库上创建不同的用户,然后分别授予不同的权限,使得主库只能写,从库只能读;