mysql 网络异常(为什么网络波动恢复后)
mysql 网络异常(为什么网络波动恢复后)线程池配置代码如下: /** * 核心线程数,默认为1 */ private static final int corePoolSize = 20; /** * 最大线程数,默认为Integer.MAX_VALUE */ private static final int maximumPoolSize = 100; /** * 线程池维护线程所允许的空闲时间,默认为60s */ private static final long keepAliveTime = 30L; /** * 线程池维护线程所允许的空闲时间的单位 */ public static final TimeUnit unit = TimeUnit.SECONDS; /**
22年7月的某一天下午公司网络故障,导致很多应用出现了异常。随着网络的恢复,应用也在恢复,唯独公司的统一登录平台没有恢复,DBA同学监控从监控平台看了一下,发现4台mysql连接池被打满。然后紧急进行应用扩容,结果也没有马上恢复。
网络恢复后mysql连接监控
错误信息:
2022-07-26 15:15:28 [WARN ] [o.h.e.j.s.SqlExceptionHelper][129] -SQL Error: 0 SQLState: null
2022-07-26 15:15:28 [ERROR] [o.h.e.j.s.SqlexceptionHelper][131] -slave1 - Connection is not available request timed out after 30001ms.
2022-07-26 15:15:28 [WARN ] [c.i.b.w.c.BFFMobileController][230] -[96097BC7-CD7C-4A04-B722-CC3BD8207764]- 516029010|login exception
javax.persistence.PersistenceException: org.hibernate.exception.JDBCConnectionException: could not prepare statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:149)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:157)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1423)
at com.idsmanager.micro.commons.repository.AbstractRepositoryHibernate.find(AbstractRepositoryHibernate.java:49)
at com.idsmanager.micro.commons.repository.AbstractRepositoryHibernate.findByUuid(AbstractRepositoryHibernate.java:65)
at com.idsmanager.oauth.infrastructure.hibernate.UserRepositoryHibernate.findByUuid(UserRepositoryHibernate.java:113)
at com.idsmanager.oauth.service.impl.UserServiceImpl.findByUuid(UserServiceImpl.java:91)
at sun.reflect.GeneratedMethodAccessor593.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
这个问题一直没有找到根本原因,上周领导让我们团队进行协助分析。从统一登录团队代码分析发现了造成这个现象的原因,是登录的时候使用了多线程进行用户信息的获取。
线程池配置代码如下:
/**
* 核心线程数,默认为1
*/
private static final int corePoolSize = 20;
/**
* 最大线程数,默认为Integer.MAX_VALUE
*/
private static final int maximumPoolSize = 100;
/**
* 线程池维护线程所允许的空闲时间,默认为60s
*/
private static final long keepAliveTime = 30L;
/**
* 线程池维护线程所允许的空闲时间的单位
*/
public static final TimeUnit unit = TimeUnit.SECONDS;
/**
* 线程池所使用的缓冲队列
*/
private static BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1000);
/**
* 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者
* a.AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常
* b.CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度
* c.DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行
* d.DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行
*/
private static RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
Mysql 连接池配置如下:
#连接超时时间30秒
spring.datasource.hikari.connection-timeout=30000
#最小连接数
spring.datasource.hikari.minimum-idle=20
#最大连接数
spring.datasource.hikari.maximum-pool-size=200
spring.datasource.hikari.leak-detection-threshold=5000
spring.datasource.hikari.validation-timeout=3000
从如上代码分析,根本原因是:在网络波动的时候,应用无法连接到数据库,这时候线程池等待的任务有1000个,活着的线程有100个,六个实例有6600个查询任务。等网络恢复后,一瞬间进行数据库的连接与查询,并且还有很多用户进行登录操作,每个mysql连接池的数据量为200,6个实例的连接数是1.2k,这就是第一个连接高平台,后续进行了扩容操作,扩容到8个节点,连接数变成了1.6k,这就是第二个连接高平台。