美文网首页数据库处理过的现网故障部署运维
mysql经典的8小时问题-wait_timeout

mysql经典的8小时问题-wait_timeout

作者: 灼灼2015 | 来源:发表于2016-09-03 10:46 被阅读9668次

    前段时间 现网突然频繁报出 连接不上数据库,偶滴的妖孽,其他地方都是用mysql,也没遇到这个问题呀。

    java.io.EOFExceptionat 
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:1913)
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2304)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2803)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1573)
    

    场景出现的理论依据
    MySQL 的默认设置下,当一个连接的空闲时间超过8小时后,MySQL 就会断开该连接,而 c3p0/dbcp 连接池则以为该被断开的连接依然有效。在这种情况下,如果客户端代码向c3p0/dbcp 连接池请求连接的话,连接池就会把已经失效的连接返回给客户端,客户端在使用该失效连接的时候即抛出异常。

    如果你只是个程序员,你会想着,在去对数据库做操作前,我不是先对数据库连接做个校验或判断什么的,连接是working的,我才干活,那么你得到的解决方案-或许就是这样的

    #c3p0配置
    <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->   
    <property name="maxIdleTime">60</property>  
    <!-- 当连接池连接耗尽时,客户端调用getConnection()后等待获取新连接的时间,
    超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。默认: 0 -->   
    <property name="checkoutTimeout" value="3000"/>  
    <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。
    如果定义了这个参数那么属性preferredTestQuery将被忽略。
    你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。默认值: null -->   
     <property name="automaticTestTable">Test</property>  
    <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的   
      时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable   
      等方法来提升连接测试的性能。Default: false -->   
    <property name="testConnectionOnCheckout">false</property>   
    <!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->   
    <property name="testConnectionOnCheckin">true</property> 
    <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->   
    <property name="idleConnectionTestPeriod">60</property>  
    

    如果你只是个DBA,你会想着,为什么数据库连接自己断了,是不是哪里有配置,我得去看看,那么你得到的解决方案-可能就是这样的

    #my.cnf
    wait_timeout=31536000  
    interactive_timeout=31536000  
    

    加大wait_timeout的时间。

    But 现实环境中需要你考虑的是:

    1. 你设置多久检查一次连接有效的时间 依据是什么?
    2. 默认加大/减小wait_timeout除了解决当前问题,会不会带来其他影响?

    个人当前觉得此题 第一需考虑的是:
    你业务当前高峰期mysql_connection是多少?保留多久connection在高峰期都不会撑爆你数据库连接池?
    如果你知道这个池-那么是改mysql ?还是改c3p0?还是双管齐下都是有据可循且不会带来后遗症的-最佳解决方案

    如我当前有环境,一个现网的后台管理系统,使用人数在50以内,那么我wait_timeout 就是默认8小时,c3p0不用做连接有效性检查等,都是万事ok的。

    而我还有一个EPG前台管理系统,用户量在300万以内,如果我wait_timeout为8小时,那我一到高峰期肯定就是死翘翘的,会有太多的TCP连接没关闭,
    数据库连接数肯定是不够的。
    因EPG的一个访问-一次对数据库操作量不大,查询完数据就完成ok啦,wait_timeout 设置在120s内应该是够用啦,那么相对应的c3p0中 设置小于wait_timeout 的时间有效性检查 -就能确保获取到连接是有效的。

    请根据业务场景,来配置参数,不要解决了A问题,带来了B问题。

    相关文章

      网友评论

      • atfa:看到一半先点赞,觉得我已经看到解决问题的希望了。
        atfa: @清浅2015 对不起,我把话题岔开了,还是讨论timeout的问题吧。我这个项目在调试开发阶段,都是用的默认配置,上线以后首先遇到的问题是睡一晚上以后前台报错:没有连接。很显然是超时了。后来就傻傻地把各种timeout全部加大,问题就变成mysql那边处于sleep的process特别多。我现在就考虑,把timeout设置到2分钟。然后在tomcat那边的代码里改改,如果失去了连接,就重新获取连接。这两天在出差,还没来得及尝试。不知道是否可行。我觉得tomcat的连接池和mysql的配置必须同步考虑才行,正在摸索,还望赐教。
        atfa: @清浅2015 谢谢关心,我也不知道现在的状态是否正常。非常简单的结构,一台tomcat一台mysql,jdbc连接。最开始tomcat老是报锁表的错误。我优化了sql和代码,tomvat那边倒是不报错了。但是mysql那边有很多orocess处于repeatable read状态。对照他们的id我查看了general log,sql语句各不相同,涉及到我业务的很多地方。现在的解决办法是每周重启一次mysql,再重启一次tomcat,访问量不大,倒也应付的过去。但是很担心未来应付不了,毕竟现在数据量才几万条而已,就这样了。您有好的建议吗?
        灼灼2015:@atfa 问题解决了吗?

      本文标题:mysql经典的8小时问题-wait_timeout

      本文链接:https://www.haomeiwen.com/subject/scmkettx.html