主备切换的两种场景
- 主动切换
- 被动切换:主库出现问题,HA系统发起
如何判断一个主库是否有问题?
- select 1判断
- 查表判断
- 更新判断
- 内部统计
select 1判断
select 1成功返回,只能说明库的进程还存在,不能说明主库没有问题。
代码语言:javascript复制-- 在主库上执行以下命令
set global innodb_thread_concurrency = 2;
innodb_thread_concurrency参数的目的是控制InnoDB并发线程的上限,一旦并发线程数达到此值,InnoDB在收到新请求后,就会进入等待状态,直到有线程退出。
innodb_thread_concurrency限制的是并发查询(当前正在执行的语句),如果一条语句在进入锁等待以后,并发线程数也会减1。
Session A | Session B | Session C |
---|---|---|
select sleep(100) from t; | select sleep(100) from t; | |
select 1;/*查询成功*/select * from t;/*会被阻塞*/) |
Session C的select 1是可以执行成功,但是select表t会被阻塞,因此用select 1检测实例是否正常是检测不出问题的。
查表判断
为了解决select 1的问题,我们可以在系统库(mysql库)里面创建1个表,比如命名为health_check,里面只放一行数据,如下:
代码语言:javascript复制create table health_check (
t_modified timestamp NOT NULL default CURRENT_TIMESTAMP
) engine=InnoDB;
Session A | Session B | Session C |
---|---|---|
select sleep(100) from t; | select sleep(100) from t; | |
select * from mysql.health_check;/*会被阻塞*/) |
使用上述方法可以检测到由于并发线程数过多导致的数据库不可用的情况。
但是假设磁盘空间使用率达100%,由于我们更新需要些日志,因此所有的更新语句都会被阻塞,但是查表还是可以的(正常读数据)。
更新判断
代码语言:javascript复制update mysql.health_check set t_modified = now();
对于主备库我们都需要使用上述语句进行检测,但是如果主备关系为双M结构,说明两个节点会同步彼此的binlog,如果使用上述语句就可能出现行冲突,导致主备停止。为了让主备之间的更新不产生冲突,可以在mysql.health_check放入多行数据,并将两个节点的server_id放入表中,如下:
代码语言:javascript复制create table health_check (
id bigint not null primary key ,
t_modified timestamp NOT NULL default CURRENT_TIMESTAMP
) engine=InnoDB;
/* 检测命令 */
insert into mysql.health_check(id, t_modified) values (@@server_id, now()) on duplicate key update t_modified=now();
由于主备库建立关系需要保证server_id不同,因此可以保证主备库各自检测命令不会发生冲突。
但是上述语句无法判断慢(比如磁盘使用率100%)的问题,但是由于上述检测语句只需要很少的资源,因此有可能在超时前执行成功,无法真正得出系统异常。
内部统计
我们可以根据mysql的performance_schema库里的一些统计信息,从内部检测数据库异常。
比如针对上述的磁盘使用率,在performance_schema库的file_summary_by_event_name表里会有统计信息,比如:
- event_name如果为wait/io/file/innodb/innodb_log_file,记录redo log的一些信息
- event_name如果为wait/io/file/sql/binlog,记录了binlog的一些信息
file_summary_by_event_name表结构如下:
- COUNT_STAR表示所有IO的总次数
- SUM、MIN、AVG、MAX_TIMER_WAIT:单位皮秒,所有IO的耗时求和、最小值、平均值、最大值
- COUNT_READ:读操作的次数
- SUM_NUMBER_OF_BYTES_READ:总共从日志里读取了多少个字节
- COUNT_WRITE:写操作的次数
- SUM_NUMBER_OF_BYTES_WRITE:写日志的字节数
- COUNT_MISC:其他类型的次数,比如对于redo log,可以认为是fsync的次数
关于内部统计信息的开启可以通过setup_instruments表控制。