0
点赞
收藏
分享

微信扫一扫

《MySQL——外部检测与内部统计 判断 主库是否出现问题》


目录

  • ​​select1判断​​
  • ​​查表判断​​
  • ​​更新判断​​
  • ​​外部检测弊端​​
  • ​​内部统计​​


一主一备的双M架构里,主备切换只需要把客户端流量切换到备库。

在一主多从的架构里,主备切换要把客户端流量切换到备库,也需要把从库接到新主库上。

切换有两种场景:1、主动切换 2、被动切换。

被动切换是由于主库出问题了,下面是几种判断主库出问题的方法:

select1判断

select 1 成功返回,说明这个库的进程孩子啊,但是不能说明主库没问题。

如果在执行语句超过了设置的​​innodb_thread_concurrency​​,此时select 1语句是成功的,但是CPU不能满足线程查询要求了,新的查询要求进来只会阻塞。

查表判断

在系统库(mysql库)里创建一个表,命名为health_check,里面只放一行数据,然后定期执行语句:

select * from mysql.headlth_check;

使用这个方法,可以检测出由于并发线程过多导致的数据库不可用的情况。

但是这个方法也会有一个问题:空间满了,失效

更新事务要写binlog,一旦binlog所在的磁盘空间占用率达到100%,那么所有的更新语句和事务提交commit语句就会堵住。但是系统此时是可以正常读数据的。

更新判断

放一个timestamp字段,用来表示最后一次执行检测的时间:

update mysql.health_check set t_modified = now();

这种节点可用性检测应该包含主库和备库。

备库检测也要写binlog, 一般只能主库写,备库不能写。这里是为了检测备库,所以才能写,但是binlog是双M结构,所以会互相同步这一个检测sql,那么有可能会造成主从数据不一致(t_modified内容不同)

如果主库A和备库B都用相同的更新命令,就可能出现行冲突,从而导致主备同步停止。

我们可以在表上存入多行数据,用A,B的server_id做主键:

create table 'health_check' (
'id' int(11) not null,
't_modified' timestamp not null default current_timestamp,
PRIMARY KEY ('id')
) engine = InnoDB;

检测命令如下:

insert into mysql.health_check(id,t_modified) values(@@server_id, now()) on duplicate key update t_modified=now();

MySQL规定了主库和备库的server_id必须不同,就可以保证主、备库各自的检测命令不会发生冲突

这种方法仍然存在问题:判定慢

所有的检测逻辑都需要一个超时时间N。即执行一条update语句,超过N秒后还不返回就认为系统不可用。

如果一个日志盘的IO利用率已经是100%的场景,此时系统响应非常慢,已经需要做主备切换了。

我们检测使用的update命令由于需要的资源比较少,很可能在拿到IO资源的时候就可以提交成功,并且在超时时间N秒未到达之前就返回给检测系统。所以update命令没有超时,然后得到系统正常的错误结论。

外部检测弊端

上面的三种方法都是基于外部检测的。外部检测天然有个问题,就是随机性。

外部检测都需要定时轮询,所以系统可能已经出现问题了,但是却要等到下一个检测语句执行的时候才能发现问题。运气不好,第一次轮询还不能发现。

内部统计

MySQL5.6版本后提供了​​performance_schema​​​库,在​​file_summary_by_event_name​​​表里统计每次IO请求的时间。
《MySQL——外部检测与内部统计 判断 主库是否出现问题》_数据库

该行数据统计的是redo log的写入时间。

COUNT_STAR是所有IO总次数。

前缀SUM、MIN、AVG、MAX,指统计项的总和、最小值、平均值、最大值。

SUM_NUMBER_OF_BYTES_READ 统计总共从redo log里读了多少字节

需要注意的是,每进行一次统计,是由性能损耗的,所以建议只打开自己需要的项进行统计。

如打开 redo log 的时间监控:

mysql> update setup_instruments set ENABLED='YES', Timed='YES' where name like '%wait/io/file/innodb/innodb_log_file%';

然后通过MAX_TIMER值来判断数据库是否出现问题。可以设定阈值,单次IO请求时间超过200ms属于异常,然后使用类似于下面的语句检测:

mysql> select event_name,MAX_TIMER_WAIT  FROM performance_schema.file_summary_by_event_name where event_name in ('wait/io/file/innodb/innodb_log_file','wait/io/file/sql/binlog') and MAX_TIMER_WAIT>200*1000000000;

发生异常后,取得需要数据后再:

mysql> truncate table performance_schema.file_summary_by_event_name;

把之前的统计信息清空。


举报

相关推荐

0 条评论