19 MySQL 主库监测
怎么判断一个主库是否出了问题?
1. 主库监测
在一主一备的双 M 架构里,主备切换只需要把客户端流量切到备库;而在一主多从架构里,主备切换除了要把客户端流量切到备库外,还需要把从库接到新主库上。
主备切换有两种场景,一种是主动切换,一种是被动切换。而其中被动切换,往往是因为主库出问题了,由 HA 系统发起的。那怎么判断主库是否出了问题,有以下几种方案:
- select 1 判断
1.1 select 1 判断
select 1 成功返回,只能说明这个库的进程还在,并不能说明主库没问题。
innodb_thread_concurrency 参数的目的是,控制 InnoDB 的并发线程上限。也就是说,一旦并发线程数达到这个值,InnoDB 在接收到新请求的时候,就会进入等待状态,直到有线程退出。此时select 1 是能执行成功的,但是查询表 t 的语句会被堵住,系统已经处于不可用状态。
innodb_thread_concurrency
innodb_thread_concurrency 这个参数的默认值是 0,表示不限制并发线程数量。但是,不限制并发线程数肯定是不行的。因为,一个机器的 CPU 核数有限,线程全冲进来,上下文切换的成本就会太高。
通常情况下,我们建议把 innodb_thread_concurrency 设置为 64~128 之间的值。
需要注意的是
- 线程处于空闲状态,不算在并发线程里面。
- 在线程进入锁等待以后,也就是说等行锁(也包括间隙锁)的线程也不算在并发线程内
- 对于真正执行的查询,比如
select sleep(100) from t
,还是要算进并发线程内
并发连接与并发查询
show processlist 的结果指的就是并发连接。而“当前正在执行”的语句,才是我们所说的并发查询。
- 并发连接数达到几千个影响并不大,就是多占一些内存而已
- 并发查询太高才是 CPU 杀手。这也是为什么我们需要设置 innodb_thread_concurrency 参数的原因
1.2 更新判断
为了能够检测 InnoDB 并发线程数过多导致的系统不可用情况,我们需要找一个访问 InnoDB 的场景。
同时更新事务要写 binlog,而一旦 binlog 所在磁盘的空间占用率达到 100%,那么所有的更新语句和事务提交的 commit 语句就都会被堵住。但是,系统这时候还是可以正常读数据的。因此我们应该使用更新语句,而不是查询语句作为监控语句。更新语句类似于:
|
|
timestamp 字段,用来表示最后一次执行检测的时间。
对于双主模型,如果主库 A 和备库 B 都用相同的更新命令进行监测,就可能出现行冲突。我们可以在 mysql.health_check 表上存入多行数据,并用 A、B 的 server_id 做主键:
|
|
更新判断是一个相对比较常用的方案了,不过依然存在一些问题。其中,“判定慢”一直是让 DBA 头疼的问题。这里涉及到的是服务器 IO 资源分配的问题。检测使用的 update 命令,需要的IO资源很少,大概率可以执行成功。但可能此时系统的 IO 利用率已经达到 100%,正常的 SQL 已经执行的很慢了。
根本原因是我们上面说的所有方法,都是基于外部检测的。外部检测天然有一个问题,就是随机性。因为,外部检测都需要定时轮询,所以系统可能已经出问题了,但是却需要等到下一个检测发起执行语句的时候,我们才有可能发现问题。
1.3 内部统计
MySQL 5.6 版本以后提供的 performance_schema 库,就在 file_summary_by_event_name 表里统计了每次 IO 请求的时间。
|
|
启用 performance_schema
打开所有的 performance_schema 项,性能大概会下降 10% 左右。所以,我建议你只打开自己需要的项进行统计。你可以通过下面的方法打开或者关闭某个具体项的统计。
|
|
异常检测
比如,你可以设定阈值,单次 IO 请求时间超过 200 毫秒属于异常,然后使用类似下面这条语句作为检测逻辑。
|
|
1.4 方案总结
建议是优先考虑 update 系统表,然后再配合增加检测 performance_schema 的信息。