29 如何判断一个数据库是不是出了问题

时间:2022-12-11 18:13:36

29 如何判断一个数据库是不是出了问题

在主备环境中,必不可少的是出现主从的切换,一种是主动切换,一种是被动切换,往往是因为主库出了问题,由HA系统发起的。

怎么判断一个主库出现了问题了呢

select 1 判断

实际上,select 1成功返回,只能说明这个库的进程还在,并不能说明主库没问题,下面一个场景

set global innodb_thread_concurrency=3;

CREATE TABLE `t` (

  `id` int(11) NOT NULL,

  `c` int(11) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB;

 insert into t values(1,1)

SESSION A

SESSION B

SESSION C

SESSION D

select sleep(100) from t;

select sleep(100) from t;

select sleep(100) from t;

 

 

 

 

select 1;(query ok)

select *from t;

(blocked)

这里设置innodb_thread_concurrency参数的目的是,控制innodb的并发线程上限,也就是说,一旦并发线程达到这个值,innodb在接收到请请求的时候,就会进入等待状态,直到有线程退出。

这里设置为3,表示innodb只允许3个线程并行执行,前3个都是sleep(100),使得这3个语句都处于”执行状态”,依次来模拟大查询,在session d里面,select 1 是成功的,但是查询表t 却被堵塞了,就是说,这时候用select 1来检测数据库是否正常的话,是检测不出问题的。

innodb中,innodb_thread_concurrency这个参数的值默认是0,表示不限制并发线程数量,但是,不限制是肯定不行的,因为,一个机器的cpu核数有限,线程全冲进来,上下文切换的成本就会太高。

通常我们建议,把这个参数设置为64-128之间,也就是64-128个并发线程,这里区分并发线程和并发连接

show processlist中,看到的是连接,并发连接,”当前正在执行”的语句,才是这里的并发查询

并发连接数达到几千个影响并不大,就是多占一些内存而已,而并发查询高才是cpu的杀手,这就是要限制这个参数的原因。

实际上,在现成计入锁等待以后,并发线程的计数就会减1,也就是说等行锁(包括间隙锁)的线程是不算在这128个线程里面的。

查表判断

为了能够检测innodb并发线程数过多导致的系统不可用情况,我们需要访问innodb的场景,一般做法是在系统库(mysql)里创建一个表,里面只放一行数据,然后定期执行;

select *from mysql.health_check

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

但是又会碰到另外的一个问题,即空间满了以后,当更新事务要写binlog,一旦binlog所在的磁盘的空间占用率达到100%,那么所有的更新语句和事务提交的commit语句就会被堵住,但是,这时候系统时可以正常查询

更新判断

常见做法是放一个timestamp字段,来表示更新执行检测的时间。

update mysql.health_check set t_modified=now();

节点可用性的检测应该包含主库和备库,如果用更新来检查主库,那么备库也要更新检测

 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();

更新判断是一个比较常用的方案,不过依然存在一些问题,其中,判断慢这个问题不好处理,更新语句,如果失败或者超时时,就可以发起主备切换,为什么还要判断慢的问题呢

这里涉及到服务器IO资源分配的问题。

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

当一个日子盘的io利用率已经是100%的场景,这时候,整个系统响应就比较慢,已经需要做主备切换了。

但是要知道,io利用率100%表示系统的io是在工作的,每个请求都有机会获得io资源,执行自己的任务,而我们的检测使用的update命令,需要的资源很少,所以可能在拿到io资源的时候就可以提交成功,并且在超时时间n秒未达到就返回检测系统

检测系统一看,update命令没有超时,就得出系统时正常的结论。

上面说的都是基于外部的检测,随机性。

内部统计

针对磁盘利用率这个问题,如果mysql可以告诉我们,内部每一次io请求时间,就可以判断数据是否出问题的方法就可靠

mysql 5.6版本,提供了performance_schema库,表

performance_schema.file_summary_by_event_name 表里统计了每次io请求的时间

event_name='wait/io/file/innodb/innodb_log_file'

29 如何判断一个数据库是不是出了问题

图中这一行表示统计的是redo log的写入时间,event_name表示统计类型

接下来的三组数据,显示的是redo log操作的时间统计

COUNT_STAR所有io的总次数,单位皮秒,SUM\MIN\AVG\MAX,总和,最小值,平均值,最大值

COUNT_READ 读操作

COUNT_WRITE 写操作

COUNT_MISC 对其他类型数据的统计,在redo log里,可以认为就是对fsync的统计

表里binlog对应的是event_name=’wait/io/file/sql/binlog’这一行

29 如何判断一个数据库是不是出了问题

因为每一次操作数据,performance_schema都需要额外的统计这些信息,所以打开这个功能是有损耗的

如果打开所有的performance_schema选项,性能大概会下降10%左右。

需要打开redo log的时间监控

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

假设已经开启 redo logbinlog的统计信息,可以通过MAX_TIMER的值来判断数据库是否出现了问题,可以设定一个阈值,单次请求超过200毫秒就属于异常

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;

把之前的信息情况。

 

MHA中,默认的方法就是select 1来检查

优先的方案是使用update更新系统表,在配合增加检测performance_schema的信息。