首页 > 其他分享 >踩坑DruidDataSource导致的服务频繁重启

踩坑DruidDataSource导致的服务频繁重启

时间:2023-09-11 17:03:34浏览次数:31  
标签:java 08 重启 30 频繁 sql DruidDataSource DataSourceUtils

1.故障简述

8月30日 上午9:30 发现某核心服务开始告警,主动重启,影响线上成交和查看订单。持续影响3分钟

2.故障引入与处理的整个过程

时间

故障处理行动

2023-08-30 09:29:57

收到监控告警某核心 服务自动完成重启

2023-08-30 09:30:33

服务全部启动完成

2023-08-30 09:51:00

排查原因——通过日志看到有数据库关闭

2023-08-30 10:03:00

看到慢sql统计里有昨日上线的sql

2023-08-30 10:20:00

优化sql提交代码打包上线

2023-08-30 10:44:41

上线完成,观察日志已经没发现新产生对应的慢sql

3.故障原因分析

3.1 故障触发

故障根因:由于慢sql增多导致数据库连接池打满,所有dubbo服务涉及数据库操作的都需要等待获取链接,从而把dubbo线程池打满,

服务的健康检查发现dubbo服务不可用,所以发生了重启

3.2 故障排查过程

1.首先发现服务频繁重启,排查原因是因为健康检查没有过,健康接口出错日志是 dubbo线程池满了,目前最大是200

踩坑DruidDataSource导致的服务频繁重启_服务频繁重启

2.同时发现这期间有超过200个慢sql,猜测慢sql阻塞住了请求

3.这期间迅速修复慢sql

对大表进行查询,mysql优化器选择了带函数的检索字段,导致索引失效

4.同时排查慢sql阻塞其余请求的原因,连上服务器,发现服务状态都健康,内存CPU等都很稳定

5.jstack查看线程状态,发现所有容器工作线程都是wait状态,如下:

"XNIO-1 task-5" #178 prio=5 os_prio=0 tid=0x000000002a03e000 nid=0x350c waiting on condition [0x000000004013a000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006c4f36dd0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:2029)
        at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1557)
        at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1337)
        at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1317)
        at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1307)
        at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:109)
        at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:158)
        at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:116)
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:79)
        at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:82)
        at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:68)

我们的数据库连接池是DruidDataSource,配置基本都是默认值,现在最大8个连接,深挖代码发现:

踩坑DruidDataSource导致的服务频繁重启_服务频繁重启_02

踩坑DruidDataSource导致的服务频繁重启_DruidDataSource_03

就算设置了超时等待时间,只能影响等待线程,不能中断被hold住的查询,如果要中断正在执行的查询,可以通过设置这两个参数:

踩坑DruidDataSource导致的服务频繁重启_DruidDataSource_04

那么防止慢sql拖垮整个服务的解决方式也很明了:

1.设置maxWait

2.设置removeAbandoned为true,设置removeAbandonedTimeout(应大于业务运行最长时间)

3.设置合理的最大连接数,默认为8,需根据业务自行调整

4.结论

1.上线之前反复确认sql是否正确命中索引,防止慢sql拖垮服务

2.检查和优化数据库配置:执行超时时间,获取链接超时时间等

5.推荐的配置

初始化大小,最大,最小连接等条件根据实际需要进行配置,以下配置相关参数皆为举例

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        init-method="init" destroy-method="close">
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_user}" />
        <property name="password" value="${jdbc_password}" />

        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="10" />
        <property name="minIdle" value="6" />
        <property name="maxActive" value="50" />
        <!-- 配置从连接池获取连接等待超时的时间 -->
        <property name="maxWait" value="10000" />

        <!-- 配置间隔多久启动一次DestroyThread,对连接池内的连接才进行一次检测,单位是毫秒。
            检测时:1.如果连接空闲并且超过minIdle以外的连接,如果空闲时间超过minEvictableIdleTimeMillis设置的值则直接物理关闭。2.在minIdle以内的不处理。
        -->
        <property name="timeBetweenEvictionRunsMillis" value="600000" />
        <!-- 配置一个连接在池中最大空闲时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <!-- 设置从连接池获取连接时是否检查连接有效性,true时,每次都检查;false时,不检查 -->
        <property name="testOnBorrow" value="false" />
        <!-- 设置往连接池归还连接时是否检查连接有效性,true时,每次都检查;false时,不检查 -->
        <property name="testOnReturn" value="false" />
        <!-- 设置从连接池获取连接时是否检查连接有效性,true时,如果连接空闲时间超过minEvictableIdleTimeMillis进行检查,否则不检查;false时,不检查 -->
        <property name="testWhileIdle" value="true" />
        <!-- 检验连接是否有效的查询语句。如果数据库Driver支持ping()方法,则优先使用ping()方法进行检查,否则使用validationQuery查询进行检查。(Oracle jdbc Driver目前不支持ping方法) -->
        <property name="validationQuery" value="select 1 from dual" />
        <!-- 单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法 -->
        <!-- <property name="validationQueryTimeout" value="1" />  -->

        <!-- 打开后,增强timeBetweenEvictionRunsMillis的周期性连接检查,minIdle内的空闲连接,每次检查强制验证连接有效性. 参考:https://github.com/alibaba/druid/wiki/KeepAlive_cn -->
        <property name="keepAlive" value="true" />  

        <!-- 连接泄露检查,打开removeAbandoned功能 , 连接从连接池借出后,长时间不归还,将触发强制回连接。回收周期随timeBetweenEvictionRunsMillis进行,如果连接为从连接池借出状态,并且未执行任何sql,并且从借出时间起已超过removeAbandonedTimeout时间,则强制归还连接到连接池中。 -->
        <property name="removeAbandoned" value="true" /> 
        <!-- 超时时间,秒 -->
        <property name="removeAbandonedTimeout" value="80"/>
        <!-- 关闭abanded连接时输出错误日志,这样出现连接泄露时可以通过错误日志定位忘记关闭连接的位置 -->
        <property name="logAbandoned" value="true" />

        <!-- 根据自身业务及事务大小来设置 -->
        <property name="connectionProperties"
            value="oracle.net.CONNECT_TIMEOUT=2000;oracle.jdbc.ReadTimeout=10000"></property>

        <!-- 打开PSCache,并且指定每个连接上PSCache的大小,Oracle等支持游标的数据库,打开此开关,会以数量级提升性能,具体查阅PSCache相关资料 -->
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize"
            value="20" />   

        <!-- 配置监控统计拦截的filters -->
        <!-- <property name="filters" value="stat,slf4j" /> -->

        <property name="proxyFilters">
            <list>
                <ref bean="log-filter" />
                <ref bean="stat-filter" />
            </list>
        </property>
        <!-- 配置监控统计日志的输出间隔,单位毫秒,每次输出所有统计数据会重置,酌情开启 -->
        <property name="timeBetweenLogStatsMillis" value="120000" />
    </bean>

标签:java,08,重启,30,频繁,sql,DruidDataSource,DataSourceUtils
From: https://blog.51cto.com/u_13222507/7436888

相关文章

  • 服务器重启后如何让K8S也自动重启
    在云计算和容器化时代,Kubernetes已经成为主流的容器编排解决方案,能够提供高效、自动化的服务部署和管理。然而,当服务器出现故障或需要进行维护时,我们经常需要重新启动服务器。在这种情况下,如何让Kubernetes服务也自动重启,确保其正常运行呢?以下是几个关键步骤,用于在服务器重启后自动......
  • java频繁的垃圾回收怎么处理
    频繁的垃圾回收可能是由于内存过度使用或存储管理不当引起的。以下是几种处理频繁垃圾回收的方法:1.增加内存分配:通过增加Java虚拟机的堆大小来提供更多的内存空间,可以减少垃圾回收的频率。可以使用-Xmx和-Xms参数来调整堆大小。2.优化对象的创建和销毁:避免过度频繁地创建和销毁对......
  • 算法单元重启啦!
    开始跟着代码随想录重新学算法了,计划是按照它的目录一个专题一个专题地刷。我的文章目录会放在下面,按照自己的进度更新,整理出来一些有价值的基础知识和题解代码。使用语言是python,但知识点部分也会涉及C++。欢迎阅读点赞~目录数组链表......
  • 查看linux系统重启时间历史记录
    1、who-b命令#查看最后一次(上次)系统启动的时间who-bsystembootDec2705:062、who-r命令#查看最后一次(上次)系统启动的时间,及运行级别who-rrun-level5Dec2705:063、lastreboot命令lastrebootrebootsystemboot4.14.35-1902.10.ThuOct2919:49-01:37(......
  • 安防视频监控/视频汇聚平台EasyCVR服务重启,海康SDK设备无法上线的原因排查
    TSINGSEE青犀视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。旭帆科技平台既具备传统安防视频监控的能力,也具备接入AI智能分析的能力,包括对......
  • 重启rc.local没执行解决方法
    背景:在早期的SysVinit系统中,/etc/rc.local是在所有其他init脚本执行完毕后自动执行的一个脚本,为系统管理员提供了一个在系统启动时运行自定义命令的便捷方法。随着systemd成为许多主流Linux发行版的默认init系统,因为systemd使用服务单位(unitfiles)来控制启动进程,而......
  • Shell脚本Kill并重启进程
    #!/bin/bashJAR_PATH=kill.jarPID=$(ps-ef|grep$JAR_PATH|grep-vgrep|awk'{print$2}')if[-z$PID]thenecho"serviceisalreadystopped"elseecho"kill$PID"kill-9$PIDfisleep1nohupjava-jar......
  • 针对jsapi_ticket不能频繁刷新,缓存的几种方式
    正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket。 在.NETCore中,你可以使用内置的缓存系统来管理和操作缓存数......
  • 微服务发布到docker后,一直重启Restarting (1) 2 seconds ago.
     使用dockerlogs加容器的ID命令,就可以查看该容器的启动的具体信息了。dockerlogsc59ba37a2508看一下日志:根据具体的报错信息来处理就可以了。  ......
  • 当重启网络失败时
     来到日志文件查看 把原本的eth0改成ens33 再重启网络 ......