mysql之主从复制

MySQL主从复制介绍

MySQL的主从复制是其自带的功能,通过逻辑的binlog日志复制到要同步的服务器本地,主服务器(Master),接收来自用户的内容更新,而一个或多个其他的服务器充当从服务器(Slave),接收来自主服务器binlog文件的日志内容,解析出SQL,重新更新到从服务器,使得主从服务器数据达到一致。

MySQL主从复制都是异步的复制方式,既不是严格实时的数据同步,但是正常情况下给用户的体验是真实的。

复制原理介绍

  • MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个MySQL数据库(我们称之为Master)复制到另一个MySQL数据库(我们称之为Slave),在Master与Slave之间实现整个主从复制的过程是由三个线程参与完成的。其中有两个线程(SQL线程和I/O线程)在Slave端,另外一个线程(I/O线程)在Master端。
  • 要实现MySQL的主从复制,首先必须打开Master端的binlog记录功能,否则就无法实现。因为整个复制过程实际上就是Slave从Master端获取binlog日志,然后再在Slave上以相同顺序执行获取的binlog日志中所记录的各种SQL操作。
  • 要打开MySQL的binlog记录功能,可通过在MySQL的配置文件my.cnf中的mysqld模块([mysqld]标识后的参数部分)增加“log-bin”参数选项来实现,

 MySQL主从复制原理过程详细描述

1在slave服务器上执行start slave命令开始主从复制
2.此时slave服务器的io线程会请求链接主服务器,并从指定的binlog文件位置之后开始获取日志内容
3.master服务器接收到slave服务器io线程的请求后,负责复制的io线程会根据收到的信息读取日志文件指定位置之后的日志内容,然后返回给slave端的io线程,
返回信息除了日志内容外,还有新的binlog文件以及新的指定的位置
4.当slave服务器io线程收到master服务器上的日志文件内容以及新的日志文件名和新的位置后,会把日志内容写到slave服务器端自身的relay log(中继日志)的最末端,
并将新的日志文件名和位置记录到master-info文件中,以便下次读取
5.slave服务器的sql线程会实时监测本地的relay log的内容,然后及时把relay log的内容解析成sql语句,按顺序依次执行这些sql语句,
并在relay log info中记录中继日志的文件名与位置

MySQL主从复制重点:

  • 主从复制是异步的逻辑的SQL语句级的复制
  • 复制时,主库有一个I/O线程,从库有两个线程,即I/O和SQL线程
  • 实现主从复制的必要条件是主库要开启记录binlog功能
  • 作为复制的所有MySQL节点的server-id都不能相同。
  • binlog文件只记录对数据库有更改的SQL语句(来自主数据库内容的变更),不记录任何查询(如select,show)语句。

主从复制实战

此处应用为 一台电脑 多实例mysql 主从复制 和单实例多服务器主从复制原理一样

mysql主服务配置

设置server-id值并开启binlog功能参数

vim my.cnf           #修改主库的配置文件  
[mysqld]            #参数要放在my.cnf中的[mysqld]模块下,否则会出错。 
server-id = 1               #用于同步的每台机器或实例server-id都不能相同
log-bin = /data/3306/mysql-bin     #binlog日志的位置 

检查配置参数后的结果

egrep "server-id|log-bin" /data/3306/my.cnf
log-bin = /data/3306/mysql-bin
server-id = 1

重启主库MySQL服务

/data/3306/mysql restart

登陆数据库,检查参数的更改情况

mysql -uroot -p123456 -S /data/3306/mysql.sock

show variables like 'server_id';      #查看MySQL的系统变量(like类似于grep过滤)  
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 1     |           #配置的server_id为1
+---------------+-------+
1 row in set (0.00 sec)

show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |           #binlog功能已开启
+---------------+-------+
1 row in set (0.00 sec)

建立用于从库复制的账号

grant replication slave on *.* to 'wk'@'192.168.50.%' identified by '123456';
#replication slavemysql同步的必须权限,此处不要授权all权限
flush privileges;                #创建完账号并授权后,需要刷新权限,使授权的权限生效

 检查主库创建的wk复制账号命令及结果如下:

select user,host from mysql.user;
+------+--------------+
| user | host         |
+------+--------------+
| root | 127.0.0.1    |
| wk   | 192.168.50.% |
| root | ::1          |
|      | localhost    |
| root | localhost    |
| root | www          |
+------+--------------+
show grants for wk@'192.168.50.%';               #查看授权状况
+--------------------------------------------------------------------------------------------------------------------------+
| Grants for wk@192.168.50.%                                                                                               |
+--------------------------------------------------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'wk'@'192.168.50.%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' |
+--------------------------------------------------------------------------------------------------------------------------+
       #结果显示授权正确

 锁表完全备份主库  (对于快速配置主从复制 不需要锁表)

对主数据库锁表只读(当前窗口不要关掉)的命令如下: 

flush table with read lock;
Query OK, 0 rows affected (0.00 sec)

在引擎不同的情况下,这个锁表命令的时间会受下面参数的控制。锁表时,如果超过设置时间不操作会自动解锁。 
默认情况下自动解锁的时长参数值如下:

show variables like '%timeout%';
+----------------------------+----------+
| Variable_name              | Value    |
+----------------------------+----------+
| connect_timeout            | 10       |
| delayed_insert_timeout     | 300      |
| innodb_lock_wait_timeout   | 120      |
| innodb_rollback_on_timeout | OFF      |
| interactive_timeout        | 28800    |          #自动解锁时间受本参数影响
| lock_wait_timeout          | 31536000 |
| net_read_timeout           | 30       |
| net_write_timeout          | 60       |
| slave_net_timeout          | 3600     |
| wait_timeout               | 28800    |          #自动解锁时间受本参数影响
+----------------------------+----------+

锁表后查看主库状态

show master status;            #根据Position偏移量 确定是否在锁表后的主从复制时 内容有所变动
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |     1193 |              |                  |      
+------------------+----------+--------------+------------------+

锁表后,一定要单开一个新的SSH窗口,导出数据库的所有数据,如果数据量很大(50GB以上),并且允许停机,可以停库直接打包数据文件进行迁移,那样更快。

分之一 快速主从复制 不需要上述锁表
mysqldump -uroot -p123456 -S /data/3306/mysql.sock --events -x --master-data=1 -A -B | gzip >/server/backup/mysql_bak.$(date +%F).sql.gz #-A表示备份所有库;-B表示增加use DB和 drop 等(导库时会直接覆盖原有的) --master-data=1 直接记录日志文件名和偏移量 不需要在change master
里写入日志文件名和偏移量 -x 导出时锁表

分支二
mysqldump -uroot -p123123 -S /data/3306/mysql.sock --events -A -B | gzip >/server/backup/mysql_bak.$(date +%F).sql.gz
#此种配置需要上述锁表同时还需要在change master里写入日志文件名和偏移量
#为了确保导出数据期间,数据库没有数据插入,导库完毕可以再次检查主库状态信息,结果如下:
 mysql -uroot -p123456 -S /data/3306/mysql.sock -e "show master status"
   mysql-bin.000001 | 1193    #确保迁移量没有发生变化

在MySQL从库的配置

设置server-id值并关闭binlog功能参数

vi my.cnf
[mysqld]
server-id = 2       #调整等号后的数值,和任何一个数据库实例都不同
egrep "server-id|log-bin" /data/3307/my.cnf      #检查配置参数后的结果 
server-id = 2

重启从数据库 

/data/3307/mysql restart

 把从主库mysqldump导出的数据恢复到从库

cd /server/backup/
gzip -d mysql_bak.2018-08-06.sql.gz
mysql -uroot -S /data/3307/mysql.sock <mysql_bak.2018-08-06.sql      #这是把数据还原到3307实例的命令

登陆3307从库,配置复制参数

MySQL从库连接主库的配置信息如下:

分之一 快速配置
CHANGE MASTER TO
MASTER_HOST='192.168.50.149',         #这里是主库的IP
MASTER_PORT=3306,                    #这里是主库的端口,从库端口可以和主库不同
MASTER_USER='wk',                 #这里是主库上建立的用于复制的用户wk
MASTER_PASSWORD='123456';          #这里是wk用户的密码
#由于--master-data=1记录了日志文件名和偏移量所以此处不设置MASTER_LOG_FILE和MASTER_LOG_POS
分之二
CHANGE MASTER TO
MASTER_HOST='192.168.50.149',         #这里是主库的IP
MASTER_PORT=3306,                    #这里是主库的端口,从库端口可以和主库不同
MASTER_USER='wk',                 #这里是主库上建立的用于复制的用户wk
MASTER_PASSWORD='123456',          #这里是wk用户的密码
MASTER_LOG_FILE='mysql-bin.000001',  #这里是show master status时查看到的二进制日志文件名称,注意不能多空格
MASTER_LOG_POS=533;                  #这里是show master status时查看到的二进制日志偏移量,注意不能多空格

上述操作的原理实际上是把用户密码等信息写入从库新的master.info文件中cat /data/3307/data/master.info

分之一
cat /data/3307/data/master.info
18

4
192.168.50.149
wk
123456
3306
60
0
分之二
cat /data/3307/data/master.info
18
mysql-bin.000001
1193
192.168.50.149
wk
123456
3306
60
0

启动从库同步开关,测试主从复制配置情况

mysql -uroot -S /data/3307/mysql.sock -e "start slave"

mysql -uroot -S /data/3308/mysql.sock -e "show slave statusG"

主从同步是否成功,最关键的为下面的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,这个是复制过程中从库比主库延迟的秒数,这个参数极度重要,但企业里更准确地判断主从延迟的方法为:在主库写时间戳,然后从库读取时间戳,和当前数据库时间进行比较,从而认定是否延迟。

此时主从复制配置成功

主从复制配置步骤小结 

  1. 准备两台数据库环境或单台多实例环境,确定能正常启动和登陆
  2. 配置my.cnf文件:主库配置log-bin和server-id参数;从库配置server-id,该值不能和主库及其他从库一样,一般不开启从库log-bin功能。注意,配置参数后要重启才能生效。
  3. 登陆主库,增加从库连接主库同步的账户,例如:yunjisuan,并授权replication slave同步的权限。
  4. 登陆主库,整库锁表flush table with read lock(窗口关闭后即失效,超时参数设置的时间到了,锁表也失效),然后show master status查看binlog的位置状态。
  5. 新开窗口,在Linux命令行备份导出原有的数据库数据,并拷贝到从库所在的服务器目录。如果数据库数据量很大,并且允许停机,可以停机打包,而不用mysqldump。
  6. 导出主库数据后,执行unlock tables解锁主库。
  7. 把主库导出的数据恢复到从库
  8. 根据主库的show master status查看到的binlog的位置状态,在从库执行change master to....语句。
  9. 从库开启复制开关,即执行start slave;。
  10. 从库show slave statusG,检查同步状态,并在主库进行更新测试。

分之一和分之二的区别在于导出主备文件    

 在企业中增加从库 只需要深夜挂定时任务执行

mysqldump -uroot -p123456 -S /data/3306/mysql.sock --events -x --master-data=1 -A -B | gzip >/server/backup/mysql_bak.$(date +%F).sql.gz

第二天把该文件移植到从库 开启主从复制功能即可

MySQL主从复制主库I/O线程状态说明

登陆主数据库查看MySQL线程的同步状态

show processlistG
#红色内容表示上述状态的意思是线程已经从binlog日志读取所有更新,并已经发送到了从数据库服务器。线程目前为空闲状态,等待由主服务器上二进制日志中的新事件更新
*************************** 1. row ***************************        #从库1IO线程 Id: 5 User: wk Host: 192.168.50.149:51932 db: NULL Command: Binlog Dump Time: 4480 State: Master has sent all binlog to slave; waiting for binlog to be updated    Info: NULL *************************** 2. row ***************************        #从库2IO线程 Id: 15 User: wk Host: 192.168.50.149:51933 db: NULL Command: Binlog Dump Time: 557 State: Master has sent all binlog to slave; waiting for binlog to be updated Info: NULL *************************** 3. row *************************** Id: 17 User: root Host: localhost db: NULL Command: Query Time: 0 State: NULL Info: show processlist 3 rows in set (0.00 sec)

下图中列出了主服务器binlog Dump线程中State列的最常见状态。如果你没有在主服务器上看见任何binlog Dump线程,则说明复制没有运行,二进制binlog日志由各种事件组成,事件通常会为更新添加信息。

登陆从数据库查看MySQL线程工作状态 

show processlistG
红1表示线程已连接到服务器,等待二进制日志到达
红2表示已处理完所有日志等待新日志到来
*************************** 1. row ***************************          #IO线程 Id: 5                     User: system user Host: db: NULL Command: Connect Time: 621 State: Waiting for master to send event Info: NULL *************************** 2. row ***************************           #SQL线程 Id: 6 User: system user Host: db: NULL Command: Connect Time: 385 State: Slave has read all relay log; waiting for the slave I/O thread to update it Info: NULL *************************** 3. row *************************** Id: 9 User: root Host: localhost db: NULL Command: Query Time: 0 State: NULL Info: show processlist 3 rows in set (0.00 sec)

  • 通过MySQL线程同步状态可以看到同步是否正常进行,故障的位置是什么,另外还可查看数据库同步是否完成,可用于主库宕机切换数据库或人工数据库主从切换迁移等。
  • 例如:主库宕机,要选择最快的从库将其提升为主库,就需要查看主从库的线程状态,如果主从复制在正常情况下进行角色切换,也需要查看主从库的线程状态,根据复制状态确定更新是否完成。

 mysql主从复制出现问题

复制故障

Slave_IO_Running: Yes

Slave_SQL_Running: No     表示复制故障

Master_Server_Id: 1      主从同步状态:关闭

stop slave;                 #关闭主从同步
Query OK, 0 rows affected, 1 warning (0.00 sec)

set global sql_slave_skip_counter
=1; #将sql线程同步指针向下移动一个,如果多次不同步,可以重复操作 Query OK, 0 rows affected (0.00 sec)
start slave;                #开启主从同步 Query OK,
0 rows affected (0.00 sec)  

解决方法2

根据可以忽略的错误号事先在配置文件中配置,跳过指定的不影响业务数据的错误,例如:

vim my.cnf
[mysqld] slave
-skip-errors = 1032,1062,1007    

让MySQL从库记录binlog日志的方法

如果从库下边还有从库需要开启从库1的binlog功能

[mysqld]
log-slave-updates #必须要有这个参数 log-bin = /data/3307/mysql-bin expire_logs_days = 7 #相当于find /data/3307/ -type f -name "mysql-bin.000*" -mtime +7 | xargs rm -f 删除7天以上的日志文件

MySQL主从复制延迟问题的原因及解决方案

问题一:主库的从库太多,导致复制延迟

从库数量以3~5个为宜,要复制的从节点数量过多,会导致复制延迟。

问题二:从库硬件比主库差,导致复制延迟。

查看Master和Slave的系统配置,可能会因为机器配置不当,包括磁盘I/O,CPU,内存等各方面因素造成复制的延迟。这一般发生在高并发大数据量写入场景中。

问题三:慢SQL语句太多

假如一条SQL语句执行时间是20秒,那么从执行完毕到从库上能查到数据至少需要20秒,这样就延迟20秒了。 
一般要把SQL语句的优化作为常规工作,不断的进行监控和优化,如果单个SQL的写入时间长,可以修改后分多次写入。通过查看慢查询日志或show full processlist命令,找出执行时间长的查询语句或大的事务。

问题四:主从复制的设计问题

例如,主从复制单线程,如果主库写并发太大,来不及传送到从库,就会导致延迟。 
更高版本的MySQL可以支持多线程复制,门户网站则会自己开发多线程同步功能。

问题五:主从库之间的网络延迟

主从库的网卡,网线,连接的交换机等网络设备都可能成为复制的瓶颈,导致复制延迟,另外,跨公网主从复制很容易导致主从复制延迟。

问题六:主库读写压力大,导致复制延迟。

主库硬件要搞好一点,架构的前端要加buffer及缓存层。

 通过read-only参数让从库只读访问

read-only参数选项可以让从服务器只允许来自从服务器线程或具有SUPER权限的数据库用户进行更新,确保从服务器不接受来自用户端的非法用户更新。 
read-only参数允许数据库更新的条件为:

    • 具有SUPER权限的用户可以更新,不受read-only参数影响,例如:管理员root。
    • 来自从服务器线程可以更新,不受read-only参数影响,例如:前文的yunjisuan用户。
    • 再生产环境中,可以在从库Slave中使用read-only参数,确保从库数据不被非法更新。

在my.cnf里[mysqld]模块下加read-only参数重启数据库,配置如下:

[mysqld]
read-only

主从同步时设置单个或多个库不做同步

生产环境中一般会采取忽略授权表方式的同步, 然后对从服务器(slave)上的用户仅授权select 读权限。不同步mysql库,这样我们就保证主库和从库相同的用户可以授权不同的权限。。

忽略mysql库和information_ schema 库的主从同步。

  [mysqld]
 replicate- ignore -db=mysql4 binlog-do-db = testdh. binlog- ignore-db = mysql↔ binlog-ignore-db = per formance_ schemar binlog-ignore-db = informat ion_ schemat 提示:忽略记录binlog日志的参数binlog-ignore-db一般用于系统的库和表。。
原文地址:https://www.cnblogs.com/ywrj/p/9425988.html