MySQL客户端连接登入hang住原因分析

Wesley13
• 阅读 638

作者:八怪(高鹏) 中亦科技数据库专家

原文:https://www.jianshu.com/p/93b69955344b

一、问题来源

问题来自一位朋友,如下:MySQL客户端连接登入hang住原因分析 mysql客户端无法登陆,查看服务器负载没有发现高负载信息。通过pstack查看线程栈信息,没有发现异常信息。

二、问题诊断和解决

一般来讲出现这种情况,我们会使用pstack看看新建立的线程为在什么函数上卡住了,然后很容易就能找到原因。但是出现这个问题过后,当mysql发起连接后卡住后,使用pstack查看mysqld服务端的进程,发现根本就没有线程与之进行交互,因此mysqld怀疑监听线程是不是出了什么问题,因此对mysql客户端连接进程进行了pstack发现如下:

#0  0x00007f262e7889c0 in __connect_nocancel () from /lib64/libpthread.so.0#1  0x0000000000435123 in inline_mysql_socket_connect (src_file=0x504490 "../../mysql-8.0.20/vio/viosocket.cc", src_line=1054, len=110, addr=0x7fffb38daa20, mysql_socket=...) at ../../mysql-8.0.20/include/mysql/psi/mysql_socket.h:647#2  vio_socket_connect (vio=0x110d2c0, addr=addr@entry=0x7fffb38daa20, len=len@entry=110, nonblocking=<optimized out>, timeout=-1, connect_done=connect_done@entry=0x7fffb38da9ef) at ../../mysql-8.0.20/vio/viosocket.cc:1054#3  0x0000000000422ad6 in csm_begin_connect (ctx=0x7fffb38daad0) at ../../mysql-8.0.20/sql-common/client.cc:250#4  0x000000000041fe99 in mysql_real_connect (mysql=mysql@entry=0xaf16a0 <mysql>, host=host@entry=0x0, user=user@entry=0x10defc0 "root", passwd=passwd@entry=0x10deff0 "xsh0923", db=db@entry=0x0, port=<optimized out>, unix_socket=0x10e0860 "/data/mysql3306/tmp/mysql.sock", client_flag=66560) at ../../mysql-8.0.20/sql-common/client.cc:5600#5  0x000000000040ddb6 in sql_real_connect (silent=0, password=0x10deff0 "xsh0923", user=0x10defc0 "root", database=0x0, host=0x0) at ../../mysql-8.0.20/client/mysql.cc:4515#6  sql_connect (host=0x0, database=0x0, user=0x10defc0 "root", password=0x10deff0 "xsh0923", silent=<optimized out>) at ../../mysql-8.0.20/client/mysql.cc:4670#7  0x000000000040968b in main () at ../../mysql-8.0.20/client/mysql.cc:1326#8  0x00007f262ce3e495 in __libc_start_main () from /lib64/libc.so.6#9  0x000000000040a4e1 in _start () at ../../mysql-8.0.20/include/my_alloc.h:86

实际上mysql卡住connect函数上面如下:

MySQL客户端连接登入hang住原因分析

因此mysql客户端和mysqld服务端都还没有建立好连接,netstat查看如下:

unix  2      [ ACC ]     STREAM     LISTENING     8584712  29676/mysqld         /tmp/mysqlx.sockunix  7      [ ACC ]     STREAM     LISTENING     8584713  29676/mysqld         /data/mysql3306/tmp/mysql.sockunix  2      [ ]         STREAM     CONNECTING    0        -                    /data/mysql3306/tmp/mysql.sockunix  2      [ ]         STREAM     CONNECTING    0        -                    /data/mysql3306/tmp/mysql.sockunix  2      [ ]         STREAM     CONNECTING    0        -                    /data/mysql3306/tmp/mysql.sock大量connectint状态的连接

然后做了strace mysqld的监听线程的操作,得到的结果如下:MySQL客户端连接登入hang住原因分析 正常的情况下这里应该是poll和accept然后开启新的(或者从缓存线程中拿一个)线程来处理交互信息了。但是这里我们可以清晰的看到出现了SIGSTOP信号。随即查看正mysqld线程的状态如下:MySQL客户端连接登入hang住原因分析 所有的线程都处于T状态下,这个状态正是由于信息SIGSTOP引起的。因此我们发一个SIGCONT信号给mysqld进程就好了如下:

kill -18 29676

三、关于信号

下面是我学习信号的时候一些笔记。

在Linux中信号是一种由内核处理的一种软中断机制,他满足简单、不能携带大量信息、并且要满足一定条件才会发送等特征。信号会经历如下过程:

  • 产生-->阻塞信号集-->未决信号集-->信号递达-->信号处理方式

首先信号的产生可以有多种方式比如我们经常用的kill命令就是发起信号的一种手段如下:

[root@mgr4 8277]# kill -l 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR111) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+338) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+843) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-758) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-263) SIGRTMAX-1  64) SIGRTMAX

我们经常的按键也可以产生

  • Ctrl+c 2)SIGINT

  • Ctrl+\ 3)SIGQUIT

  • Ctrl+z 4)SIGTSTP

当然还有很多其他触发方式比如硬件异常,raise函数,abort函数,alarm函数等等。其次是阻塞信号集,阻塞信号集能够对想除(9/19号信号以外)的信号进行屏蔽,如果屏蔽后信号自然不会到达 递达 状态,也就谈不上处理了。通过sigprocmask函数进行阻塞信号集的设置,但之前必须要设置sigset_t 集合,通过sigaddset、sigdelset、sigemptyset、sigfillset等函数设置。

未决信号集是不能被操作的,只能被获取通过sigpending函数获取,但是他和阻塞信号集一起可以控制信号的递达。

信号递达后就需要处理信号,默认的行为上面都列举了,但是信号(9/19号信号以外)是可以被捕获改变其处理方式的,我们可以自定义函数作为某个信号的处理方式,这可以通过signal函数和sigaction函数进行捕获和处理,sigaction函数相对复杂需要有一个struct sigaction的结构体变量,其中包含了sa_handler\sa_mask\sa_flags\sa_siaction 成员,这里不做解释可以自行查看Linux man page。

上面是单进程下的信号处理方式,在多线程下,线程之间公用处理方式,但是可以有不同的信号屏蔽集,在多线程下一般采用设置统一的信号屏蔽字和信号处理方式使用pthread_mask函数继承到各个线程,同时使用sigwait/sigwaitinfo等函数设置一个单独的信号处理线程来进行统一处理,MySQL就是这样处理的。MySQL实际上有一个信号处理线程,

|     36 |         1927 | sql/signal_handler              |    NULL | BACKGROUND | NULL   | NULL         |

如果需要了解可以参考如下文章: MySQL中对信号的处理(SIGTERM,SIGQUIT,SIGHUP等), http://blog.itpub.net/7728585/viewspace-2142060/

四、pstack和SIGSTOP

这里简单提一下pstack抓取线程栈的时候会触发一个SIGSTOP信号,因为pstack实际上调用的就是gdb的如下命令:

/usr/bin/gdb --quiet -nx /proc/8277/exe 8277thread apply all bt输出所有线程信息

gdb通常会发起SIGSTOP信号来停止进程的运行,因此我们在线上执行pstack命令的时候一定要小心,pstack可能导致你的MySQL停止运行一小会,特别是高压力线程很多负载很高的情况下,可能需要很长的时候,pstack应该作为线上重要数据库最后不得已而为之的诊断方式

如下我们使用pstack 来获取mysqld的栈,运行一开始就关闭窗口,此时我们的mysqld已经处于停止状态如下:MySQL客户端连接登入hang住原因分析

因此使用pstack一定要格外小心。一般来讲从库线程不多压力不大重要性不高可以使用pstack进行信息采集。当然也可以手动发起SIGSTOP信号来达到测试效果。

MySQL客户端连接登入hang住原因分析

五、捕获所有的信号

下面一个小代码可以捕获所有的信号供测试:

#include <signal.h>#include <stdio.h>#include <stdlib.h>#include "unistd.h"void handler(int sig){  printf("get signal %d\n",sig);}void test(){ ;}int main(void){  struct sigaction s;  int* a=NULL;  int  i=0;    a=(int*)calloc(32,sizeof(int));  for(i=0;i<32;i++)  {    *(a+i) = (i+1);  }    s.sa_handler=handler;  for(i=0;i<32;i++)  {   sigaction(*(a+i),&s,NULL);   }   while(1)  {    test();    sleep(1);  }  return 0;}

全文完。

Enjoy MySQL :)

扫码添加作者微信

MySQL客户端连接登入hang住原因分析

叶老师的「MySQL核心优化」大课已升级到MySQL 8.0,扫码开启MySQL 8.0修行之旅吧

MySQL客户端连接登入hang住原因分析

本文分享自微信公众号 - 老叶茶馆(iMySQL_WX)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这