TR2021_0000偶发数据库连接异常问题排查
【问题描述】
数据库连接异常是很难排查的一类问题。因为它牵涉到应用端,网络层和服务器端。任何一个组件异常,都会导致数据库连接失败。开发遇到数据库连接不上的问题,都会第一时间找DBA来协助查看,DBA除了需要懂得数据库以外,还需要对应用,对网络有所了解,知道在哪里看应用程序的日志,以及看网络交换机性能指标,才能清晰的定位问题。下面是一个数据库偶发连接不上的例子:
| 步骤 | 分析 |
|---|---|
| S(主观) | 某应用程序,有40台左右应用服务器,时不时的会报数据库连接异常。报错后迅速自愈。报错内容为: Communications link failure. The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. 报错频率大概每天有四五次左右。应用是新上的。 |
| O(客观) | MySQL版本为5.7.23, 服务端操作系统版本为7.6.1810. 瞬间有20多台应用服务器都报这个错误。马上自愈。应用部署在同城两个机房,每个机房都有报错。每天总会出现四五次。 |
| A(评估) | 同时有20多台应用服务器报错,而且分布在两个机房。问题应该出在服务端。 |
| P(计划) | 建议在服务端抓网络包,进一步定位问题。并进一步查看服务端的性能计数器。 |
【问题分析】
通过问题的初步评估,故障应该是出现在服务端,也有可能是服务端的网络。我们随之查看了服务端MySQL的各项性能指标,在故障期间,性能指标都是正常的。在服务器端单边抓包,抓到的内容如下:
| 时间戳 | 源 | 目标 | Info |
|---|---|---|---|
| 2021-01-08 17:15:05.667331 | 应用 | DB | 48184 -> 3309 [SYN] |
| 2021-01-08 17:15:06.717752 | 应用 | DB | [TCP Retransmission] 48144 -> 3309 [SYN] |
| 2021-01-08 17:15:06.717762 | DB | 应用 | 3309 -> 48184 [SYN, ACK] |
| 2021-01-08 17:15:06.719101 | 应用 | DB | 48144 -> 3309 [RST] |
上述网络包解读如下:
- 17:15:05.66 应用服务器(端口号48184)向DB服务器(端口号3309) 发送一个SYN请求。
- 过了1.05秒左右,应用服务器再次向DB服务器发送SYN请求
- 在17:15:06.71的时候,DB服务器响应了客户端的请求,发送了确认包ACK
- 在17:15:06.71的时候,应用服务器发送了连接重置的请求,要求中止连接。
从上述的特征来看,连接重置是客户端发起的。但这个情有可原,因为DB端超过1.05秒还没有响应客户端的SYN请求,客户端不耐烦,直接中止了连接。而这个1.05秒,恰好是开发在客户端的Tomcat JDBC connect Timeout连接超时设定。所以问题进一步缩小到服务端的TCP/IP连接层面。
我们用下面的命令,来监控服务端丢包情况:
# netstat -s | egrep "listen|LISTEN"
5268 times the listen queue of a socket overflowed
5268 SYNs to LISTEN sockets dropped
发现确实在服务端丢包,而且出现的频率和客户端报错的时间吻合。每次应用程序报错,服务端的drop数也会随之增加。
对于Linux服务器端,server端建连过程需要两个队列,一个是SYN queue,一个是accept queue。前者叫半开连接(或者半连接)队列,后者叫全连接队列。从服务器角度看,建立TCP连接的过程如下图:

SYNs to LISTEN sockets dropped的丢包类型,说明在半连接队列出现了问题。
分析发现,该实例部署的DB数量比较多,且对应的应用服务器数量也比较多,应用会有短时间创建大量连接的情况,导致半连接队列溢出。半连接队列的大小取决于linux的参数tcp_max_syn_backlog、somaxconn和应用程序调用Listen方法时的backlog参数。
关于tcp_max_syn_backlog、somaxconn与半连接队列的分析,网上的资料非常多,这里不展开细节分析,我们可以简单地认为:
全连接队列长度 = min(somaxconn, backlog)
半连接队列长度 = min(应用调用Listen的backlog,somaxconn,tcp_max_syn_backlog)
我们可以用下面的命令,来监控全连接的队列大小,发现值为128,可以说明我们somaxconn值或者mysqld的backlog设置比较小,从而导致半连接队列也比较小。
#ss -ntlp | more
LISTEN 0 128 :::3309 :::*
对于这次的案例,我们先调大了linux操作系统的两个参数。
#echo 'net.ipv4.tcp_max_syn_backlog=65535' >> /etc/sysctl.conf
#echo 'net.core.somaxconn=65535' >> /etc/sysctl.conf
#sysctl –p
接下来,我们分析下mysqld调用Listen方法时,backlog相关的代码。
MYSQLD在启动时会调用network_init的方法,会传入back_log参数,代码如下:
static bool network_init(void)
{
if (opt_bootstrap)
return false;
set_ports();
if (!opt_disable_networking || unix_sock_name != "")
{
std::string const bind_addr_str(my_bind_addr_str ? my_bind_addr_str : "");
Mysqld_socket_listener *mysqld_socket_listener=
new (std::nothrow) Mysqld_socket_listener(bind_addr_str,
mysqld_port, back_log,
mysqld_port_timeout,
unix_sock_name);
if (mysqld_socket_listener == NULL)
return true;
mysqld_socket_acceptor=
new (std::nothrow) Connection_acceptor(mysqld_socket_listener);
}
创建出mysqld_socket_listener对象后,传递给Connection_acceptor后,最终会调用操作系统的Listen方法,代码如下:
static inline int inline_mysql_socket_listen
(
MYSQL_SOCKET mysql_socket, int backlog)
{
int result;
if (mysql_socket.m_psi != NULL)
{
/* Instrumentation start */
PSI_socket_locker *locker;
PSI_socket_locker_state state;
locker= PSI_SOCKET_CALL(start_socket_wait)
(&state, mysql_socket.m_psi, PSI_SOCKET_CONNECT, (size_t)0, src_file, src_line);
/* Instrumented code */
result= listen(mysql_socket.fd, backlog);
对于back_log值的确定,mysql有2种处理方式。
一种是情况默认情况,会设置50 + (max_connections / 5)且不超过900。具体的代码如下:
int init_common_variables()
{
umask(((~my_umask) & 0666));
my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
/* Fix back_log */
if (back_log == 0 && (back_log= 50 + max_connections / 5) > 900)
back_log= 900;
}
另外一种情况,也可以手动设置mysqld的启动参数。
static Sys_var_ulong Sys_back_log(
"back_log", "The number of outstanding connection requests "
"MySQL can have. This comes into play when the main MySQL thread "
"gets very many connection requests in a very short time",
READ_ONLY GLOBAL_VAR(back_log), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, 65535), DEFAULT(0), BLOCK_SIZE(1));
为了保持服务器配置的统一化,我们这次调整了mysqld的启动back-log=2048,调整完成后,重启mysql服务,观察了2天,再未发生半连接丢包的问题。
【问题总结】
全连接队列、半连接队列溢出这种问题很容易发生,但可能报错具有偶然性,很容易被忽视,linux版本的不断进化,TCP的设计也越来越复杂,作为一名合格的DBA,也需要对网络有所了解,才能更好地定位和处理日常的运维问题。
TR2021_0000偶发数据库连接异常问题排查的更多相关文章
- mysql数据库连接异常问题(总结)
mysql数据库连接异常问题(总结) 1.1 前言 最近项目由1个数据源增加至了3个数据源(连接池使用C3P0),结果各种奇葩的数据库连接问题接踵而至,为防止将来再次遇到同样的问题不犯同样错误,现 ...
- CentOS服务器上搭建Gitlab安装步骤、中文汉化详细步骤、日常管理以及异常故障排查
一, 服务器快速搭建gitlab方法 可以参考gitlab中文社区 的教程centos7安装gitlab:https://www.gitlab.cc/downloads/#centos7centos6 ...
- tcp_tw_recycle参数引发的数据库连接异常
[问题描述] 开发反馈有个应用在后端数据库某次计划性重启后经常会出现数据库连接异常问题,通过监控系统的埋点数据,发现应用连接数据库异常有两类表现: 其一:连接超时 131148.00ms To ...
- 【MySql】数据库连接异常:Thelastpacketsentsuccessfullytotheserverwas0millisecondsago
参考链接:http://blog.sina.com.cn/s/blog_7540bf5f0102xjpk.html 最近新入职,用了新版的mysql8数据库,结果连接数据库时出现了问题,报了几个异常, ...
- 一则线上MySql连接异常的排查过程
Mysql作为一个常用数据库,在互联网系统应用很多.有些故障是其自身的bug,有些则不是,这里以前段时间遇到的问题举例. 问题 当时遇到的症状是这样的,我们的应用在线上测试环境,JMeter测试过程中 ...
- 基于TBDS的flume异常问题排查过程
版权声明:本文由王亮原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/214 来源:腾云阁 https://www.qclou ...
- 连接池你用对了吗?一次Unexpected end of stream异常的排查
能收获什么? 更加了解TCP协议 Redis与客户端关闭连接的机制 基于Apache Common连接池的参数调优 Linux网络抓包 情况简介 近期迁移了部分应用到K8s中,业务开发人员反馈说,会发 ...
- 记录一次Flink作业异常的排查过程
最近2周开始接手apache flink全链路监控数据的作业,包括指标统计,业务规则匹配等逻辑,计算结果实时写入elasticsearch. 昨天遇到生产环境有作业无法正常重启的问题,我负责对这个问题 ...
- Hadoop部署启动异常问题排查
hadoop的日志目录(/home/hadoop/app/hadoop-2.6.4/logs) 1.hadoop启动不正常用浏览器访问namenode的50070端口,不正常,需要诊断问题出在哪里: ...
随机推荐
- 【Dotnet9-01】从0开始搭建开源项目-lqclass.com
行文目录 一. 前言 1.1 我的现有网站 1.2 想法:新开发一个网站 1.3 目前开发计划 二. 行动了 2.1 Github创建项目 2.2 使用 WTM 搭建后台框架 2.3 项目演示 2.4 ...
- 【APIO2018】选圆圈(平面分块 | CDQ分治 | KDT)
Description 给定平面上的 \(n\) 个圆,用三个参数 \((x, y, R)\) 表示圆心坐标和半径. 每次选取最大的一个尚未被删除的圆删除,并同时删除所有与其相切或相交的圆. 最后输出 ...
- mybatis逆向工程运行
命令: mvn mybatis-generator:generate 项目结构: generatorConfig.xml内容示例 <?xml version="1.0" en ...
- MVC-采用Bundles方式引入css和js文件
优点:修改js或css时会自动生成hash版本号. 缺点:需要在BundleConfig中先添加对应的文件,然后在html中再引用对应的bundle,多操作了一步. web.config中 <c ...
- Spring Boot 的2020最后一击:2.4.1、2.3.7、2.2.12 发布
近日,Spring Boot官方发布了本年度最后一次版本更新,主要针对目前维护的三个版本: 2.4.x:第一个bug修复版本 2.4.1 2.3.x:常规维护版本 2.3.7 2.2.x:常规维护版本 ...
- 【Unity】Unity中AR Foundation的使用
前段时间通过Unity 3d打包测试对比ARCore与ARKit环境探针的效果的过程中,在Google AR Core官网下载到了ARCore for Unity SDK,但是在苹果官网却没有找到AR ...
- ThreadLocal使用总结
一.ThreadLocal基本使用 1.1使用场景 不同的线程对全局变量进行修改,使用ThreadLocal后会为每个线程创建一个副本,而不会影响其他线程的副本,确保了线程的安全 private st ...
- 学Python编程能做什么工作?从事什么岗位?——这些问题你知道吗?
前言 学Python编程能做什么工作?随着人工智能发展,学习python语言的人员有更多的岗位机会,python从事的职业广泛,从游戏到AI人工智能能都可以用Python实现.除了编程,各种岗位的人都 ...
- gcc编译阶段打印宏定义的内容
背景 总所周知,代码量稍微大一点的C/C++项目的一些宏定义都会比较复杂,有时候会嵌套多个#if/#else判断分支和一堆#ifdef/#undef让你单看代码的话很难判断出宏定义的具体内容. 如果有 ...
- Redis缓存穿透和缓存雪崩的面试题解析
前段时间去摩拜面试,然后,做笔试的时候,遇到了几道Redis面试题目,今天来做个总结.捋一下思路,顺便温习一下之前的知识,如果对您有帮助,左上角点下关注 ! 谢谢 文章目录 缓存穿透 缓存雪崩 大家都 ...