MySQL复制功能

介绍二进制日志及其对复制的影响、GTID的复制等等

mysql复制功能介绍


复制问题解决了什么问题:

  • 实现了不同服务器上的数据分布
  • 利用二进制日志增量进行
  • 不需要太多的带宽
  • 但是使用基于行的复制在进行大批量的更改时会对带宽带来一定的压力,特别是跨IDC环境下进行复制应该分批进行。
  • 实现在不同服务器上的数据分布
  • 实现在数据读取的负载均衡,需要其他组件配合完成比如利用DNS轮询的方式把程序的读连接到不同的备份数据库,使用LVS,haproxy这样的代理方式。
  • 非共享架构,同样的数据分布在多台服务器上,增强了数据的安全性
  • 利用备库的备份来减少主库的复杂,复制并不能代替备份
  • 方便的进行数据库高可用架构的部署,避免MySQL单点失败,实现数据库高可用和故障切换
  • 实现数据库在线升级

mysql 二进制日志


MySQL中有很多类型的日志

  1. 错误日志――MySQL服务启动和关闭过程中的信息以及其它错误和警告信息。默认在数据目录下。
  2. 一般查询日志――用于记录select查询语句的日志。general_log、general_log_file 默认关闭,建议关闭。
  3. 慢查询日志――log-slow-queries记录所有超过long_query_time时间的SQL语句。
  4. 二进制日志――记录任何引起数据变化的操作,用于备份和还原。默认存放在数据目录中,在刷新和服务重启时会滚动二进制日志。
  5. 中继日志――从主服务器的二进制文件中复制的事件,并保存为二进制文件,格式和二进制日志一样。
  6. 事务日志――保证事务的一致性。

可以参考:http://www.php.cn/mysql-tutorials-362068.html

MySQL服务层日志

  • 二进制日志
  • 慢查询日志
  • 通用日志

MySQL存储引擎层日志

  • Innodb (重做日志、回滚日志)

其中MySQL中的二进制日志与存储引擎无关,记录了所有对MySQL数据库的修改事件,包括增删改查时间和对表结构的修改事件。可以通过binlog命令工作对日志进行查看。

二进制日志的格式


基于段的格式


binlog_format=STATEMENT

  • 优点:日志记录量相对较小,节约磁盘以及网络I/O
  • 缺点:必须要记录上下文信息,保证语句自爱从服务器上执行结果和主服务器上相同,但是比如特定的函数UUID(),user()这样的非确定性函数还是无法复制,可能造成MySQL复制的主从服务器数据不一致。

操作示例

>mysql -uroot -proot

mysql> show variables like 'binlog_format'; #查看二进制日志格式,下边显示使用row
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.00 sec)

mysql> set session binlog_format=statement;  #设置成statement格式

mysql> show variables like 'log_bin'; #查询二进制日志是否开启,显示关闭
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | OFF   |
+---------------+-------+

开启二进制日志

打开mysql的配置文件添加log_bin配置

[mysqld]
log_bin = mysql_bin#位置自定义,如/var/lib/mysql/sql_log/mysql_bin

刷新bin_logs;

mysql>flush logs;
mysql>flush binary logs;
+---------------------+-------------+
| Log_name            | File_size   |
+---------------------+-------------+
| mysql-bin.000001    | 201         |
+---------------------+-------------+
| mysql-bin.000002    | 154         |
+---------------------+-------------+

#各种数据库操作,statement日志会记录自行的SQL
>create xx
>select xxx
>update xx
>delete xx

查看二进制日志

$ cd /var/lib/mysql/sql_log/
$ ls 
mysql-bin.000001  mysql-bin.000002  mysql-bin.index  mysql-error.log

$ mysqlbinlog -vv mysql-bin.000002  #查看日志内容,可以清楚的看到执行的SQL语句

基于行的日志格式


binlog_format=ROW

ROW格式可以避免MySQL复制中出现的主从不一致问题,MySQL5.7默认采用的日志格式

基于行的日志会分别记录每一行的数据修改

优点

  • 使MySQL主从复制更加安全
  • 对每一行数据的修改比基于段的复制高效
  • 如果误操作修改了数据库中的数据,同时又么有备份可以恢复时,我们就可以通过分析二进制日志,对日志中的记录的数据修改操作做反向处理的方式达到恢复数据的目的。

缺点

  • 记录日志量较大

binlog_row_image=[FULL|MINIMAL|NOBLOB]
FULL 记录所有的列的变化
MINIMAL 只会记录修改的列的变化
NOBLOB 不记录BLOB类型的变化

mysql> set session binlog_format=row;  #设置成row格式
mysql> flush logs;
mysql> show variables like 'binlog_row_image';
+-----------------+--------+
| Variable_name   | Value  |
+-----------------+--------+
| binlog_row_image| FULL   |
+---------------+----------+
#各种数据操作
mysql> create xxx
mysql> update xxx
mysql> insert 
mysql> delete

查看二进制日志

$ cd /var/lib/mysql/sql_log/
$ ls 
mysql-bin.000001  mysql-bin.000002  mysql-bin.000003 mysql-bin.index  mysql-error.log

$ mysqlbinlog -vv mysql-bin.000003  #查看日志内容,可以清楚的看到数据的变化,需要加 -vv 查看

混合日志格式


binlog_format = MIXED

特点

  • 根据SQL语句由系统决定在基于段和基于行的日志格式中进行选择
  • 数据量的大小由所执行的SQL语句决定

如何选择二进制日志的格式,建议:

binlog_format=mixed

binlog_format=row

binlog_row_image=minimal

mysql二进制日志格式对复制的影响


根据二进制的数据格式,复制可以分为

基于SQL语句的复制(SBR)

二进制日志格式使用statement格式

优点

  • 生成的日志量少,节约网络传输I/O
  • 并不强制要求主从数据库的表定义完全相同
  • 相比于基于行的复制方式更加灵活

缺点

  • 对于非确定性时间,无法保证主从复制数据的一致性
  • 对于存储过程,触发器,自定义函数进行的修改也可能造成数据不一致
  • 相比基于行的复制方式在从执行时间上需要更多的执行时间

基于行的复制(RBR)

二进制日志格式使用的是基于行的日志格式

优点

  • 可以应用于任何SQL的复制包括非确定函数,存储过程等
  • 可以减少数据库锁的使用

缺点

  • 要求主从数据库的表结构相同,否则可能会中断复制
  • 无法在从上单独的执行触发器

混合模式

根据实际内容在以上两者间切换

mysql复制工作方式


MySQL复制功能_第1张图片

  1. 主将变更写入二进制日志
  2. 从读取主的二进制日志变更并写入到relay_log中 | 基于日志点的复制 | 基于GTID的复制
  3. 在从上重放relay_log中的日志 | 基于SQL段的日志使在从库上重新执行记录的SQL完成的 | 基于行的日志则使在从库上直接应用对数据库行的修改完成的

基于日志点的复制


如果主从服务器上的MySQL都是最新安装的,为了实现主从复制需要进行如下步骤

  1. DB服务器上建立复制的账号并授权
mysql>create user 'repl'@'IP段' identified by 'PassWord';
mysql>grant replication slave on *.* to 'repl'@'IP段';
  1. 配置数据库服务器

binlog_format二进制格式要设置,前面内容讲解到

my.cnf文件配置

[mysqld]
#启用二进制日志(可自定义存放位置,需要先创建并赋予权限)
log_bin = /var/lib/mysql/sql_log/mysql_bin
# mkdir /var/lib/mysql/sql_log
# chown -R mysql:mysql /var/lib/mysql/sql_log/

#指定主服务器的服务ID,整个服务集群中式唯一的(自定义,集群中不重复即可)
server_id = 100
  1. 配置数据库服务器
    my.cnf文件配置
#启用二进制日志(可自定义存放位置,需要先创建并赋予权限)
log_bin = /var/lib/mysql/sql_log/mysql_bin
# mkdir /var/lib/mysql/sql_log
# chown -R mysql:mysql /var/lib/mysql/sql_log/

#指定从服务器的服务ID,整个服务集群中式唯一的(自定义,集群中不重复即可)
server_id = 101

#启用中继日志(可自定义存放位置)
relay_log = /var/lib/mysql/sql_log/mysql_relay_bin

#可选,建议从服务器只读
read_only = on

#可选(如果需要将从服务器作为其他服务器的主服务器时必须设置,否则不设置)
log_slave_updates = on
  1. 初始化服务器数据,导出主库中的数据到从库

如果是新服务器 或 数据都是一致的跳过此步骤

两种导出方式

  • mysqldump --master-data -single-transaction#会对表造成大量阻塞

  • xtrabackup --slave-info#对全部都是innodb的表最好的选择,不会阻塞

  1. 服务器查看日志
mysql> SHOW MASTER STATUS \G;
*************************** 1. row ***************************
             File: mysql_bin.000007
         Position: 5856
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
  1. 服务器启动复制链路
mysql>CHANGE MASTER TO
	->MASTER_HOST='master_host_ip',#主DB服务器IP
	->MASTER_USER='repl',#主DB复制用户
	->MASTER_PASSWORD='PassWord',#主DB复制用户密码
	->MASTER_LOG_FILE='mysql_bin.000007',#在主DB查看日志文件
	->MASTER_LOG_POS=5856;#在主DB查看节点

mysql>show slave status \G;#查看复制链路是否启动
mysql>start slave;#启动复制链路
mysql>show processlist; #可以看到从服务器上建立的进程
  1. 服务器检查复制链路状态

检查以下两个参数是否为Yes

  • Slave_IO_Running
  • Slave_SQL_Running
mysql>show slave status \G;
*************************** 1. row ***************************
             Slave_IO_Running: Yes					#YES表示成功
            Slave_SQL_Running: Yes					#YES表示成功
                Last_IO_Errno: 0					#IO错误代码
                Last_IO_Error:						#IO错误提示
               Last_SQL_Errno: 0					#SQL错误代码
               Last_SQL_Error:						#SQL错误提示
  1. 服务器查看正在运行的进程

可以看到Command:Binlog Dump

mysql> SHOW PROCESSLIST \G;
*************************** 2. row ***************************
     Id: 143
   User: repl
   Host: 192.168.10.1:55402
     db: NULL
Command: Binlog Dump
   Time: 9527
  State: Master has sent all binlog to slave; waiting for more updates
   Info: NULL
*************************** 3. row ***************************

基于日志点的复制的

优点

  • 是MySQL最早的复制技术,Bug相对较少
  • 对SQL查询没有任何权限
  • 故障处理比较容易

缺点

  • 故障转移时重新获取新的住的日志点信息比较困难

mysql 二进制日志


MySQL5.6 时支持的模式

基于GTID的复制与基于日志的的复制有很大的区别
MySQL复制功能_第2张图片
MySQL复制功能_第3张图片
什么是GTID即全局事务ID,其保证为每一个在主上提交的事务在复制集群中可以生成一个唯一的ID

GTID=source_id:transaction_id

使用了GTID后不可使用如下操作

  • create table …select

  • 在事务中使用create temporary table 建立临时表使用关联更新事务表和事非事务表

操作步骤

  1. 在主DB服务器上建立服务制账号
mysql>create user 'repl' @ 'IP段' identified by 'PassWord';
mysql>grant replication slave on *.* to 'repl' @ 'IP段';
  1. 配置主数据库服务器
    my.cnf
log_bin = /usr/local/mysql/log/mysql-bin
server_id = 100
gtid_mode = on  #启动gtid
enforce-gtid-consiste #强制gtid一致性,保证事务安全
log-slave-updates = on # mysql5.7可以不用这个参数
  1. 配置从数据库服务器
server_id = 101
relay_log = /usr/local/mysql/log/relay_log
gtid_mode = on
enforce-gtid-consistency
log-slave-updates = on # mysql5.7可以不用这个参数
read_only = on  #建议
master_info_repository = TABLE #建议
realy_log_info_repository = TABLE #建议
  1. 初始化从服务器数据
mysqldump --single-transaction --master-data --triggers --routines --all-database -uroot -p >> all2.sql;
 #会对表进行加锁
xtrabackup --slave-info 

#scp all2.sql [email protected]:/root #拷贝备份文件到从库

# mysql -uroot -p < all2.sql #初始化从服务器,导入后主从数据库初始化是一致的。
  1. 启动基于GTID的复制(记录备份时最后的事务的GTID值)
mysql>CHANGE MASTER TO MASTER_HOST = 'master_host_ip'
					MASTER_USER = 'repl'
					MASTER_PASSWORD = 'PassWord'
					MASTER_AUTO_POSITION = 1;

基于GTID复制的优缺点

优点

  • 可以很方便的故障转移
  • 从库上不会丢失主库上的任何修改

缺点

  • 故障处理比较复杂
  • 对执行SQL有一定的限制

选择复制模式要考虑的问题

  1. 所使用的MySQL版本
  2. 复制架构以及主从切换的方式
  3. 所使用的高可用管理组件
  4. 对应用的支持程度

MySQL复制拓扑


MySQL复制功能_第4张图片

下边来了解一下MySQL常见的拓扑结构

  1. 一主多从的复制拓扑
    MySQL复制功能_第5张图片
    优点
  • 配置简单
  • 可以用多个从库分担读负载

用途

  • 为不同业务使用不同的从库
  • 将一台从库放到远程的IDC,用于灾备恢复
  • 分担主库的读负载
  1. 主-主复制
    MySQL复制功能_第6张图片
    主备模式的主主复制模式:

有一台主服务器对外提供服务,一台服务器处于只读状态,并且只作为热备使用。

在对外提供服务的主库出现故障或者是计划性的维护时才会进行切换,使原来的备库成为主库,而原来的主库会成为新的备库,并处理只读或者是下线状态,维护完成后重新上线。

主备模式下的主-主复制的配置注意事项

  • 确保两台服务器上的初始化数据相同
  • 确保两台服务器上已经启动logbin并且有不同的server_id
  • 两台服务器上启动log_slave_updates参数
  • 在初始化备库上启用read_only

主主模式的主主复制模式
两个主同时对外提供服务,并不能分担写负载

主主模式下的主主复制缺点:

  • 产生数据冲突而造成复制链路中断,耗费大量的时间排查问题
  • 容易造成数据丢失

如果一定要使用主主复制模式,应该注意一下事项:

  • 两个主中所操作的表最好能够分开
  • 使用下边两个参数控制自增ID的生成

auto_increment_increment = 2
auto_increment_offset = 1 | 2

  1. 拥有备库的主-主复制拓扑
    MySQL复制功能_第7张图片

  2. 级联复制
    可以避免分发主库连接从库过多而占用主库过多的带宽,使用分发主库可以解决这个问题。
    MySQL复制功能_第8张图片

MySQL复制性能优化


影响主从延迟的原因

  • 主库写入二进制的日志时间
  • 控制主库的事务大小,分割事务
  • 二进制日志传输时间
  • 使用MIXED日志格式,设置set binlog_row_image=minimal
  • 默认情况下只有一个SQL线程,主上并发的修改在从上变成了串行
  • 使用多线程复制(MySQL5.6),在MySQL5.7中可以按照逻辑时钟的方式来分配线程

MySQL5.7上使用多线程复制

mysql>stop slave
mysql>set global slave_parallel_type = 'logical_clock'; #使用逻辑时钟的方式复制
mysql>set global slave_parallel_workers=4; #设置多线程复制的数量
mysql>start slave;#启动复制
mysql>show processlist; #查看进程的数量
mysql>show variables like 'slave_parallel_type'; #查看并发类型配置
mysql>show variables like 'slave_parallel_workers'; #查看并发线程数量

MySQL复制常见问题处理


由于数据损坏或丢失所引起的主从复制错误

  • 主库或从库意外宕机引起的错误,可以使用跳过二进制日志事件或者注入空事务的方式恢复中断的复制链路再使用其他方法来对比主从服务器上的数据。
  • 主库上的二进制的日志损坏,只能通过从库中使用change master命令来重新指定
  • 备库上的中继日志的损坏
  • 在从库上进行数据修改造成的主从复制错误,应该设置从库时read_only
  • 不唯一的server_id或server_uuid(记录在数据目录中的auto.cnf文件中)
  • max_allow_packet设置引起的主从复制错误

MySQL复制无法解决的问题

  • 分担主数据库的写负载
  • 自动的故障转移以及主从切换
  • 提供读写分离

参考文章
https://github.com/caojx-git/learn/blob/master/notes/mysql/打造扛得住的MySQL.md

你可能感兴趣的:(mysql)