介绍大家好,我是Leo,目前在常州从事Java后端工程师工作。上一篇我们介绍了读写分离的问题,主要从概念、目的、单对多演进、安全演进和六大解决方案。今天我们就来聊一聊一主多从,挂了怎么快速定位。赠送算法,MySQL书籍,剑指offer思路根据广大读者和用户的反馈,我画了一张写作思路图。通过这张图,可以更好的分析当前文章的写作知识点。可以帮助读者在最短的时间内判断是否为有效文章!外部统计select1正常。先说说select1的用法。这个用法我想大家应该都知道,因为要判断一个库是否还活着,如果库正常,没有问题,就会返回1,因为输出1肯定返回1。如果库宕机了,output1肯定没有响应,因为MySQL已经无法提供服务了。mysql执行select1时,多用于单机服务。让我们举一个非常简单的例子。在cmd控制台输入mysql,执行SQL语句,只知道当前数据库是否正常。无法知道整个数据库的集群是否正常。因此,该方案更常用于单机状态。一旦使用了一些集群规模,一般不会采用这种方案!意外情况首先介绍一下配置并发线程数上限的参数innodb_thread_concurrency。如果设置为3,一旦并发线程数达到这个值,InnoDB就会在收到新的请求时进入等待状态,直到有一个线程退出。这里我们可以模拟最坏的情况,如果有3个线程正常访问数据库,执行一个大数据量的查询操作。如果此时一个select1可以执行成功呢?就会执行成功!但是如果用户在测试之后发送了一个查询表请求,就会被阻塞,因为其他三个线程的用户也在进行查询表操作,那么这些线程就会处于等待状态。问题是select1执行成功了,但是真正的查询语句有问题,那么这个方案可行吗?它一定不起作用。innodb_thread_concurrency这个参数默认为0。代表无限并发线程。这绝对不可能。从整体性能考虑,如果并发线程过多,会影响MySQL的整体性能。所以我们一般推荐64~128。Extension这里的64~128指的是并发查询线程,有些人可能会和并发连接混淆。showprocesslist执行上面的SQL,下面Command一栏的Query是并发查询,并发连接是和数据库的连接,但是没有做任何操作就挂在了那个接口上。并发连接只是浪费了一些内存,而并发查询浪费了MySQL限制的并发线程数。再来说说热更新和死锁检测。如果innodb_thread_concurrency设置为128,在同线热点更新问题出现时,128会不会很快被消耗掉,导致整个系统挂掉?不,MySQL绝对不会允许这样的事情发生的。所以当锁在等待的时候,并发线程会减一。也就是说,128个线程是不会算锁等待的。在特殊情况下,有些锁等待肯定是不会算在并发线程中的,那么像我们上面说的那些耗时查询怎么处理呢?如果真的到了128,用select1岂不是出问题了,所以接下来的方案就诞生了查表判断select1的劣势,逐渐演变成表来判断。那么桌子应该放在哪里呢?千万不能随便放在数据库里!表的位置如下图建立在那个数据库中,我们可以创建一个health_check,里面只有一行数据,然后定时执行。选择*frommysql.health_check;这样确实可以从innodb解决当前数据库状态,那么问题来了,innodb需要写日志,也就是写binlog,所以当磁盘空间占用率达到100%时。事务提交的所有更新语句和提交语句都会被阻塞。但是此时系统仍然可以正常读取数据。上面的查询判断显然是不行的。更新数据就是记录一笔交易。事务的入口是写入binlog日志。磁盘满了怎么写?所以执行不成功,但是读取的数据还是可以提供的。显然,两端不对应是绝对不可能的。更新判断又通过了。既然要更新,就要放一个有意义的字段。一种常见的做法是放置一个时间戳字段来指示上次执行检测的时间。这个更新语句类似于:updatemysql.health_checksett_modified=now();如果所有的主从数据库都涉及更新操作,检测必须处理同步问题的节点可用性应该包括主库和备库。如果更新是用来检测主库的,那么备库也应该更新。备库的检测也需要写入binlog。由于我们一般将A库和B库的主从关系设计成双M结构,所以在备库B上执行的检测命令也必须回传给主库A。如果主库A和备库B都使用相同的更新命令,可能会发生行冲突,从而导致主备库同步停止。所以mysql.health_check表好像不能只有一行数据。如果存储多行,则必须考虑一主多从中server_id的问题。MySQL规定主库和备库的server_id必须不同(否则创建主备关系会报错),这样才能保证主备。库各自的检测命令不冲突。更新判断是一种比较普遍的解决方案,但是也存在一些问题。比如“判断慢”,根据我们之前文章的介绍,当更新操作慢或者失败时。然后就可以切换主从了。为什么还存在判断慢的问题?IO资源分配首先,所有的检测逻辑都需要一个超时时间N。执行一条update语句,如果超过N秒还没有返回,则认为系统不可用。判断慢是IO资源分配问题,场景下日志盘IO利用率已经100%。此时整个系统的响应很慢,需要进行主备倒换。100%的IO利用率意味着系统的IO在工作,每个请求都有机会获取IO资源,执行自己的任务。我们检测中使用的update命令需要的资源很少,所以有可能在获取到IO资源时提交成功,在超时时间N秒之前返回给检测系统。检查系统,update命令没有超时,所以断定系统是正常的。IO问题,SQL执行很慢,但此时系统正常,肯定不行,内部统计和外部统计无法判断满足真正的需求。我们转向了内部统计程序。对于之前的方案更详细的判断,会出现写入binlogIO磁盘的问题。然后优化方案。如果MySQL能够提供这样的数据,岂不是靠谱多了!从performance_schema库中,file_summary_by_event_name表统计了每次IO请求的时间。COUNT_STAR:所有IO的总数SUM_NUMBER_OF_BYTES_READ:总共从redolog中读取了多少字节。简单介绍一下上表中的字段,普及一下最常用的。剩下的自己搜索。找到这张表后,我们只需要event_name="wait/io/file/sql/binlog"这一行就OK了。我们每次操作数据库,performance_schema都需要额外统计这些信息,所以开启这个统计功能是有性能损失的。如果要开启redolog的时间监控,可以执行这条语句:updatesetup_instrumentssetENABLED='YES',Timed='YES'wherenamelike'%wait/io/file/innodb/innodb_log_file%';启用后,实战中可以通过MAX_TIMER值来判断数据库是否有问题。例如,您可以设置一个阈值。单个IO请求超过200毫秒是异常的,然后使用如下语句作为检测逻辑。selectevent_name,MAX_TIMER_WAITFROMperformance_schema.file_summary_by_event_namewhereevent_namein('wait/io/file/innodb/innodb_log_file','wait/io/file/sql/binlog')andMAX_TIMER_WAIT>200*1000000000;找到异常后,得到自己需要的信息,然后通过下面的这条语句:truncatetableperformance_schema.file_summary_by_event_name;清除以前的统计信息。这样,如果在后续监测中再次出现异常,可以添加监测累计值。总结大致介绍了最基本的select1方法。这种方法对于单机MySQL很好用,但是一主多从集群后就不行了。所以在查表判断的时候,当查表判断涉及到innodb写事务日志的时候,如果磁盘满了,写事务写不出来,可以读,导致不一致。然后更新判断。100%IO利用率意味着系统的IO在工作,每个请求都有机会获得IO资源。所以更新不会超时,系统认为是正常情况。因此,在无法响应服务的同时,又判断为正常,造成不一致。最后是内部统计。使用系统库程序。使用event_name和MAX_TIMER字段判断是否有问题
