您当前的位置:首页 > 计算机 > 软件应用 > 数据库 > 其它数据库

分库分表-MAX_CONNECTIONS_SIZE_PER_QUERY设置导致系统崩溃

时间:02-01来源:作者:点击数:

一、问题描述

发生在生产环境的真实案件,加了一张分表之后,导致系统挂掉,此外,分表还未有任何数据记录。分表配置与其他相同分表的配置相同。

二、排查过程

1.刚开始系统挂掉时,以为是系统问题,因此重启系统。重启完成之后,系统正常了几分钟之后,又继续宕机。

2.去除新增的分表之后,系统正常。

三、数据背景

1.一共10张表涉及到分表,根据订单号orderId进行分表,每张表已有4张分表,其中订单表总数量大概在4000万左右,其他表的数量会比订单表的总数量要多一些,其他表的分表逻辑也是依据订单号来分表。

2.数据配置方面,使用的是ShardingSphere分表,采用的是精确分片算法分表,max.connections.size.per.query (该参数表示一次查询时每个数据库所允许使用的最大连接数)= 4;

四、问题解决

1.本地压测线程数10个,循环3次,系统会崩溃。通过阅读ShardingSphere官网,发现一个问题,那就是新增一张表之后,执行引擎的模式发生了改变。先介绍一下分表的执行模式,有两种:内存限制模式和连接限制模式,具体含义如下:

(1)内存限制模式:使用此模式的前提是,ShardingSphere对一次操作所耗费的数据库连接数量不做限制。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,则对每张表创建一个新的数据库连接,并通过多线程的方式并发处理,以达成执行效率最大化。 并且在SQL满足条件情况下,优先选择流式归并,以防止出现内存溢出或避免频繁垃圾回收情况。

这里解释一下什么是流式归并:是指每一次从结果集中获取到的数据,都能够通过逐条获取的方式返回正确的单条数据,它与数据库原生的返回结果集的方式最为契合。遍历、排序以及流式分组都属于流式归并的一种。

(2)连接限制模式:使用此模式的前提是,ShardingSphere严格控制对一次操作所耗费的数据库连接数量。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,那么只会创建唯一的数据库连接,并对其200张表串行处理。 如果一次操作中的分片散落在不同的数据库,仍然采用多线程处理对不同库的操作,但每个库的每次操作仍然只创建一个唯一的数据库连接。 这样即可以防止对一次请求对数据库连接占用过多所带来的问题。该模式始终选择内存归并。

那么上面的两种模式有什么区别呢?

(1)内存限制模式适用于OLAP(OLAP可用于数据提取或挖掘、数据分析、报告以发现数据项之间的关系)操作,可以通过放宽对数据库连接的限制提升系统吞吐量;

(2)连接限制模式适用于OLTP(通常涉及在数据库中插入,更新或删除少量数据,主要是处理大量用户下的大量事务)操作,OLTP通常带有分片键,会路由到单一的分片,因此严格控制数据库连接,以保证在线系统数据库资源能够被更多的应用所使用,是明智的选择。

ShardingSphere如何区分分表的执行模式呢?有个公式:

2.宕机分析

针对我们系统的场景,系统是根据订单号做的分表,分片键即订单号,如果用订单号去查询,那么可以直接定位到某张分表即可,但是实际场景中存在不通过订单号去查询,这种情况下就要全表扫描,那么一次查询就要耗费很长时间了。不通过订单号查询的情况,两种模式有两种不同的执行逻辑,内存限制模式因为不限制连接数,因此其他查询不需要等待此次查询完毕再去查询;连接限制模式在连接数满了之后,需要等待当前查询完毕之后释放连接,其他访问数据库的操作才能继续执行。

之前的情况是有4张分表,max.connections.size.per.query = 4,根据公式可知,“每个数据库连接需执行的SQL数量”=1,走的是内存限制模式。因此即使在大量查询面前,也不会卡死。

新增了一张分表之后,“每个数据库连接需执行的SQL数量”=5/4 > 1了,这时候走的就是连接限制模式,一次查询时每个数据库所允许使用的最大连接数为4,当有大量的不通过分片键(即订单号)查询访问数据库时,因为连接长时间得不到释放,导致系统阻塞宕机。

3.问题解决

将max.connections.size.per.query 设置大一些,让“每个数据库连接需执行的SQL数量”永远小于等于1,走内存限制模式。再次压测,问题解决。

4.考虑过的解决方案

经过这次分表事故之后,我想到了另外一个解决方案:将不通过分片键查询的查询字段与分片键单独设置一张表,也包含其分表,非分片查询键和分片键设置为一张表,字段会少很多,因为现在的分表字段最少也要20几个,这种查询效率也是比较低的,如果尽量将每次查询耗时降低的话,这样就可以尽快释放连接,将连接让给其他需要连接的线程,这样就不宕机了。但是没有实施,因为这种在架构上所有涉及到的系统都要改动一遍,改动量有点儿大了。还有个缺点就是:不符合三范式,多了冗余表。此解决方案只是为了解决而想出来的方案,不知道如果在系统设计之初加上这样的设计行不行,有好的建议或者意见欢迎在留言板评论!

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门