本文正在参加「技术专题19期 漫谈数据库技术」活动
最近工作当中遇到了一个mysql问题,就是上午mysql数据库还在正常的查询,下午突然有小伙伴反应说:数据库访问不了了,所有的请求报错了,于是决定登录mysql看一下,发现登录不上了,有小伙伴使用navcate出于数据库的登录状态,执行sql语句,返回了too many connections,作为一个后端【前端,后端,运维打杂】工程师,自然要负责解决这个问题,所以记录下排查的思路和方法:
问题分析
其实,当执行数据库操作返回的是to many connections 已经不用排查了,肯定是mysql连接池被打满了,啥意思,之前我有博客聊过一条sql语句执行的过程,其中在MySQL服务器上有一个叫做连接器的东西,那么今天的问题涉及到的就是和他相关的连接池,假如:有一万次数据库访问,那么是不是要开启一万个数据库的连接,首先可以肯(坑)定这样做会给服务器带来超级大的压力,那该如何?那么可不可以创建一个存储连接的队列,在当中缓存100个连接,用户访问就从里面获取连接,访问结束也不用不关闭,而是释放连接到队列,这样数据库的连接器就只维护这100个连接,而不是一直创建连接,使用,关闭连接的过程,那么这样的策略和队列,就是连接池,连接池的出现极大的降低了mysql的访问压力,但是如果有用户访问完数据库没有进行连接释放,可能会导致连接池当中所有的连接被占用,那么其他访问自然无法到达数据库,就会报错:to many connections,而这里可以明确的是:mysql默认的连接数是100。
问题解决预防
问题分析
所以当遇到这个问题,就可以考虑以下的情况了:
1、数据库部署时候没有考虑到访问情况,使用了默认的连接数(通常是100),然后业务需求确实大于100导致 too many connections 问题。
2、有使用数据库的小伙伴在操作完数据库后没有编写关闭释放数据库连接的操作,导致连接池被打满,通常是在写并发的语句的时候导致的,这个需要内部沟通和结合业务去分析。
解决方案
那么这个问题的解决方案可以有很多种:
1、最粗糙的方法,重启mysql,没有啥是重启解决不了的,重启mysql,清空连接池,自然可以访问了,但是这种方法治标不治本,连接池可能很快就会再次打满。
2、最直接的方法就是修改连接数,进入mysql配置文件(linux下的/etc/my.conf,windos下安装不了下的my.ini)配置参数:
max_connections=1000
然后重启mysql,增大连接池,自然可以防止连接池打满,但是如果连接池太大,好多连接冗余,其实也不是一件好的事情,所以修改max_connections还是要进行一下业务分析的。
3、在修改连接数的同时,添加几个参数来限制连接,确保连接池当中连接使用合理:
1)添加MySQL关闭连接前等待的秒数配置,这里默认是28800秒,也就是8个小数,这个可以缩小,提前释放连接到连接池:
interactive_timeout MySQL服务器关闭交互式连接前等待的秒数。
wait_timeout :MySQL服务器关闭非交互连接之前等待的秒数。
交互式和非交互连接定义由mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。
通俗的说:
交互式:在本机上打开mysql的客户端,就是那个黑窗口,在黑窗口下进行各种sql操作,当然走的肯定是tcp协议。
非交互式:就是在项目中进行程序调用。比如一边是tomcat web服务器,一边是数据库服务器,两者怎么通信?在java web里,通常会选择hibernate或者是jdbc来连接。那么这时候就是非交互式。
max_connections=1000
wait_timeout = 600
interactive_timeout = 600
2)添加每个用户的最大访问数,限制一个用户使用完所有的连接,这个需要调查业务配置,防止限制到业务的正常访问,但是通常配置的逻辑是,max_user_connections会小于max_connections
max_user_connections=300
后续
ok,问题的分析和解决方案就聊到这里了,至于我遇到的这次问题的具体原因就不聊了,嘿嘿嘿,还是,欢迎大家多多指点。
本文正在参加「技术专题19期 漫谈数据库技术」活动