mysql 主从服务-对于主从延迟检测与处理

主从延迟检测

Master 服务器和 Slave 服务器连接时,创建 Binlog dump thread 以发送 bin log 数据:

  1. 一个 Binlog dump thread 对应一个 slave 服务器;
  2. Binlog dump thread 从 bin log 获取数据时会加锁,获取到数据后,立即释放锁;

当 slave 服务器收到 START_SLAVE 命令时,会创建 I/O thread 和 SQL thread:

  1. I/O thread 以拉的方式,从 Master 读取事件,并存储到 slave 服务器的 relay log 中;
  2. SQL thread 从 relay log 中读取事件并执行;
  3. slave 可以按照自己的节奏读取和更新数据,也可以随意操作复制进程(启动和停止)。

pt-heartbeat

要想使用 pt-heartbeat 这个工具,请看这个文章进行安装:https://blog.csdn.net/qq_39408664/article/details/119422712

在 percona toolkit 产品中也提供了可以对于 MySQL 主从延时检查的工具 pt-heartbeat,pt-heartbeat 的工作原理是通过使用时间戳方式在主库上更新特定表,然后在从库上读取被更新的时间戳,然后与本地系统时间对比,来得出其延迟。

具体流程:

  1. 在主上创建一张 heartbeat 表,按照一定的时间频率更新该表的数据。监控操作运行后,heartbeat 表能促使主从同步;
  2. 连接到从库上检查复制的时间记录,和从库的当前系统时间进行比较,得出时间的差异。注意在使用的方式就是需要在主库中创建这个表;

mysql> use mysql;
mysql> create table heartbeat ( 
     > ts varchar(26) NOT NULL,
     > server_id INT UNSIGNED NOT NULL PRIMARY KEY,
     > file varchar (255) DEFAULT NULL,
     > position bigint unsigned DEFAULT NULL,
     > relay_master_log_file varchar(255) DEFAULT NULL,              
     > exec_master_log_pos bigint unsigned DEFAULT NULL
     > );
Query OK, 0 rows affected (0.04 sec)

通过 pt-heartbeat 可以对于 MySQL 中的 heartbeat 表每隔多久更新一次(注意这个启动操作要在主库服务器上执行)


[root@localhost ~]# pt-heartbeat --user=mytest_slave --ask-pass --create-table --database=mytest --interval=1 --interval=1 --update --replace --daemonize
Enter password: 
[root@localhost ~]# ps -ef | grep pt-heartbeat
root      12016      1  0 19:43 ?        00:00:00 perl /usr/bin/pt-heartbeat --user=mytest_slave --ask-pass --create-table --database=mytest --interval=1 --interval=1 --update --replace --daemonize
root      12018  10638  0 19:43 pts/0    00:00:00 grep --color=auto pt-heartbeat

运行监测同步延迟:


[root@localhost ~]# pt-heartbeat --database=mytest --table=heartbeat --monitor --user=mytest_slave --password=root --master-server-id=1
0.02s [  0.00s,  0.00s,  0.00s ]
0.00s [  0.00s,  0.00s,  0.00s ]
0.00s [  0.00s,  0.00s,  0.00s ]
0.00s [  0.00s,  0.00s,  0.00s ]
0.00s [  0.00s,  0.00s,  0.00s ]
0.00s [  0.00s,  0.00s,  0.00s ]

这其中 0.02s 表示延迟了,没有延迟是为 0.00s ;而 [0.00s, 0.00s, 0.00s] 则表示 1m , 5m , 15m 的平均值,而这其中需要注意的是 --master-server-id 为主服务器的服务 id 就是在 my.cnf 中配置的 server_id 的值。


指令解释:

CREATE TABLE heartbeat (
		ts  varchar(26) NOT NULL,
		server_id int unsigned NOT NULL PRIMARY KEY,
		file varchar(255) DEFAULT NULL,    -- SHOW MASTER STATUS
		position bigint unsigned DEFAULT NULL, -- SHOW MASTER STATUS
		relay_master_log_file varchar(255) DEFAULT NULL,    -- SHOW SLAVE STATUS
		exec_master_log_pos bigint unsigned DEFAULT NULL  -- SHOW SLAVE STATUS
	);

heratbeat表一直在更改ts和position,而ts是我们检查复制延迟的关键。

注意:需要指定的参数至少有 --stop,--update,--monitor,--check。
其中--update,--monitor和--check是互斥的,--daemonize和--check也是互斥。

--ask-pass:隐式输入MySQL密码
--charset:字符集设置
--check:检查从的延迟,检查一次就退出,除非指定了--recurse会递归的检查所有的从服务器。
--check-``read``-only:如果从服务器开启了只读模式,该工具会跳过任何插入。
--create-table:在主上创建心跳监控的表,如果该表不存在。可以自己建立,建议存储引擎改成memory。通过更新该表知道主从延迟的差距。
--daemonize:执行时,放入到后台执行
--user | -u:连接数据库的帐号
--database | -D:连接数据库的名称
--host|-h:连接的数据库地址
--password | -p:连接数据库的密码
--port | -P:连接数据库的端口
--socket | -S:连接数据库的套接字文件
--file 【--file=output.txt】:打印–monitor最新的记录到指定的文件,很好的防止满屏幕都是数据的烦恼。
--frames 【--frames=1m,2m,3m】:在–monitor里输出的[]里的记录段,默认是1m,5m,15m。可以指定1个,如:–frames=1s,多个用逗号隔开。可用单位有秒(s)、分钟(m)、小时(h)、天(d)。
--interval:检查、更新的间隔时间。默认是见是1s。最小的单位是0.01s,最大精度为小数点后两位,因此0.015将调整至0.02。
--log:开启daemonized模式的所有日志将会被打印到制定的文件中。
--monitor:持续监控从的延迟情况。通过–interval指定的间隔时间,打印出从的延迟信息,通过--file则可以把这些信息打印到指定的文件。
--master-server-id:指定主的server_id,若没有指定则该工具会连到主上查找其server_id。
--print-master-server-id:在--monitor--check 模式下,指定该参数则打印出主的server_id。
--recurse:多级复制的检查深度。模式M-S-S…不是最后的一个从都需要开启log_slave_updates,这样才能检查到。
--recursion-method:指定复制检查的方式,默认为processlist,hosts。
--update:更新主上的心跳表。
--replace:使用--replace代替–update模式更新心跳表里的时间字段,这样的好处是不用管表里是否有行。
--stop:停止运行该工具(--daemonize),在/tmp/目录下创建一个“pt-heartbeat-sentinel” 文件。后面想重新开启则需要把该临时文件删除,才能开启(--daemonize)。
--table:指定心跳表名,默认heartbeat。`



主从延迟处理

对于从库的延时问题最为重要的就是主库与从库之间连接的网络环境,从库的写入和读这两个点 - 其次就是对于主从的架构的优化;

注意:一旦使用了主从必然是会有一定的延时问题,因此我们就需要考虑程序对于延迟的容忍度。如果是 0 容忍的话建议还是不用主从了。


MySQL 从库配置

首先,如果是因为网络造成的延迟,把服务器的带宽即可。

从库的写入主要是指 insert,update,delete 的语句的执行速度,这些语句的执行速度我们就需要考虑MySQL的执行SQL语句的一个特点 -> 对于每一个写的SQL会默认开启事务并提交事务;而事务是会影响到 IO 的消耗的,这和 innodb_flush_log_at_trx_commit 参数有关系。默认为 1 ,我们可以尝试设置为 0 或 2 ;可以提高效率,另一个就是 sync_binlog。

sync_binlog 配置说明:

sync_binlog:这个参数是对于MySQL系统来说是至关重要的,他不仅影响到 Binlog 对 MySQL 所带来的性能损耗,而且还影响到MySQL中数据的完整性。对于 “sync_binlog” 参数的各种设置的说明如下:sync_binlog=0,当事务提交之后,MySQL 不做 fsync 之类的磁盘同步指令刷新 binlog_cache 中的信息到磁盘,而让 Filesystem 自行决定什么时候来做同步,或者 cache 满了之后才同步到磁盘。sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次 fsync 之类的磁盘同步指令来将 binlog_cache 中的数据强制写入磁盘。

在MySQL中系统默认的设置是sync_binlog=0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦系统 Crash ,在 binlog_cache 中的所有 binlog 信息都会被丢失。而当设置为 1 的时候,是最安全但是性能损耗最大的设置。因为当设置为 1 的时候,即使系统 Crash ,最多丢失 binlog_cache 中未完成的一个事务,对实际数据没有任何实质性影响。

从以往经验和相关测试来看,对于高并发事务的系统来说,“sync_binlog” 设置为 0 和设置为 1 的系统写入性能差距可能高达5倍甚至更多。

innodb_flush_log_at_trx_commit 配置说明:默认值 1 的意思是每一次事务提交或事务外的指令都需要把日志写入(flush)硬盘,这是很费时的。特别是使用电池供电缓存(Battery backed up cache)时。设成 2 对于很多运用,特别是从 MyISAM 表转过来的是可以的,它的意思是不写入硬盘而是写入系统缓存。日志仍然会每秒flush到硬盘,所以你一般不会丢失超过 1-2 秒的更新。设成 0 会更快一点,但安全方面比较差,即使MySQL挂了也可能会丢失事务的数据。而值为 2 只会在整个操作系统挂了才可能丢失数据。

innodb_flush_log_at_trx_commit 这个文章也有说明https://blog.csdn.net/qq_39408664/article/details/119039852



硬件方面

只能说升级服务器的配置,对于高并发,服务器的配置一定要好。



架构方面

  1. 可以考虑对于一些库进行单独分离。
  2. 服务的基础架构在业务和MySQL之间加入 memcache 或者 redis 的 cache 层。
  3. 从服务器的配置也尽可能的比主服务器的要好。(因为读写分离,主服务器用于写数据,从服务器用于读;读消耗的资源比较大)




上一篇:Java代码中,如何监控Mysql的binlog?


下一篇:MySQL-binlog2sql:非主从实时同步+恢复误删数据