Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如果MySQL事务中发生了网络异常?

如果MySQL事务中发生了网络异常?

作者头像
用户1278550
发布于 2020-10-10 03:13:35
发布于 2020-10-10 03:13:35
3.5K00
代码可运行
举报
文章被收录于专栏:idbaidba
运行总次数:0
代码可运行

一 前言

在我们运维MySQL的时候,总会遇到各种情况导致程序和MySQL之间的会话异常中断,比如

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
假如强制关闭应用
假如client机器突然崩溃宕机/断电
假如网络发生抖动/网卡发生故障
机房级别断网

那么此时正在MySQL中执行的事务会何表现?

二 实践

设计一个案例模拟client 在MySQL中执行事务,但是client机器突然down机,导致会话异常中断。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
client 192.168.56.102  
MySQL  192.168.56.101

client 连接db 执行 select for update 动作给记录加上锁,当然实际上 也可以是update,delete 这样的动作给记录加上锁。

然后关闭client机器模拟断电,断网。

此时server端 网络层的连接状态依然是 ESTABLISH 数据库中的事务处于running状态。

再开启另外一个会话,对t1表进行加锁需要等待,说明断网之后的事务依然处于活跃状态。

ok 表演结束 ,我们接下来继续分析网络断开,事务为啥没有退出?

三 分析

3.1 服务端为什么没有退出这个事务呢?

MySQL普通的会话连接没有保活机制,即没有设置socket属性,也没有设置心跳机制。如果网络连接异常断开服务端不能及时探测到该异常。更进一步,我们通过 TCP 关闭的四次握手来看

网络异常的时候,TCP连接的状态还是ESTABLISHED,说明 server 和 client 任何一方都没有主动发送FIN包,服务端还在等待 client端 发送数据,此时的 MySQL 事务无法直接退出。

3.2 事务在网络断开后如何处理
事务正在执行

一个连接进行事务后,如果事务语句正在执行,那么网络断开后会在语句执行完成后回滚掉。因为执行状态包不能送达客户端,因此会感知到这种网络断开的错误。调试堆栈信息参考 堆栈1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
      trans_rollback_stmt(thd);
事务执行完成未提交

如果事务中sql执行完成而没有提交,此时网络断开,那么事务还存在服务端,需要手动kill。client到server端的连接路径:

socket->listen->poll(socketfd)->accept->newthread->poll(newfd,wait_timeout)

一旦有新的数据到来,如果需要读取或者写入由于网络问题依旧使用poll进行等待,直到超时。其中参数 read_timeout/write_timeout 用于读取网络数据的,如果网络不可用,会话保持的时间就是等待网络可用的时间,也就是 wait_timeoutread_timeout/write_timeout 均使用poll的timeout实现。见栈2,可见 vio_io_wait 函数用于处理各种超时,主要用poll来处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
net_write_packet
 ->net_write_raw_loop  一个包大小16M
  ->vio_write
    ->mysql_socket_send 如果发送信息失败 inline_mysql_socket_send调用send命令
    ->如果是SOCKET_EAGAIN那么通过vio_socket_io_wait函数进行判定,需要等待的时间
      /* Wait for the output buffer to become writable.*/
3.3 何时退出呢?

这里需要分情况来讨论。

空闲连接状态时

此时连接的会话时间由 MySQL参数 wait_timeout 决定,默认是8h,也即会话时间空闲超过8h,会被MySQL自动关闭。详细知识可以移步到如下链接:

浅析interactive_timeout和wait_timeout

等待TCP超时

默认情况下会话会保持2小时+11次*75秒,此时服务端为啥没有退出这个事务呢? 。(由TCP属性决定)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/proc/sys/net/ipv4/tcp_keepalive_time = 7200(等待空闲时间秒)
/proc/sys/net/ipv4/tcp_keepalive_intvl = 75(探测间隔秒)
/proc/sys/net/ipv4/tcp_keepalive_probes = 9(探测次数)
主动kill 异常会话

kill $thread_id;

我们之前遇到一次机房级别的断网,应用重连之后遇到大量sql 锁等待,于是乎,我们写了一个脚本定期kill 长时间活跃的事务,仅供大家参考。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 针对系统运维层面
Kill_SQL="select concat('kill ', trx_mysql_thread_id ,' ;') from information_schema.processlist a,information_schema.INNODB_TRX b where a.ID=b.trx_mysql_thread_id and trx_started <=SUBDATE(now(),interval 60 second)  and STATE='' and COMMAND='Sleep' and TIME>=60"
LOGFILE='/data/logs/zandb_agent/kill_long_trx.log'
run_user=`whoami`

ret_log()
{
   msg="$1"
   echo `date +%Y%m%d_%H:%M:%S` "[info]" " $msg" >> ${LOGFILE}
}
if [ $#  -lt 1 ]; then
    ports=`ps -ef |grep mysqld| grep -v mysqld_safe |grep port=|awk -F"port=" '{print $NF}' |awk '{print $1}' | sort `
else
    ports=$1
fi
for port in ${ports};
do
   if [ -f /tmp/long_trx_${port}.lock ];then
      msg="there is a lock file ,so we skip instance ${port}.."
      ret_log "${msg}"
      continue
   fi

   if [ -S /srv/my${port}/run/mysql.sock  ]; then
      SOCKET="/srv/my${port}/run/mysql.sock"
   else
      msg="socket file does not exists,please check ."
      ret_log "${msg}"
   fi
   MYSQL="/opt/mysql/bin/mysql -uroot -S ${SOCKET}  "
   ${MYSQL} --skip-column-names -e "$Kill_SQL" > /tmp/kill_trx_${port}.sql.${run_user} 2>/tmp/kill_trx_${port}.log.${run_user}
   num=`grep kill -c /tmp/kill_trx_${port}.sql.${run_user}`
   if [[ ${num} -gt 0 ]]; then
      msg="${port}  ${num}  long trx was killed "
      ret_log "${msg}"
      ${MYSQL} -e "source /tmp/kill_trx_${port}.sql.${run_user}"
   fi
done

栈1:回滚栈

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(gdb) bt
#0  innobase_rollback (hton=0x2e12440, thd=0x7ffefc000950, rollback_trx=false) at /home/mysql/soft/percona-server-5.7.29-32/storage/innobase/handler/ha_innodb.cc:5452
#1  0x0000000000ea6ab8 in ha_rollback_low (thd=0x7ffefc000950, all=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/handler.cc:2019
#2  0x00000000017f0f23 in MYSQL_BIN_LOG::rollback (this=0x2d668a0 <mysql_bin_log>, thd=0x7ffefc000950, all=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/binlog.cc:2532
#3  0x0000000000ea6d40 in ha_rollback_trans (thd=0x7ffefc000950, all=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/handler.cc:2106
#4  0x00000000015c6a13 in trans_rollback_stmt (thd=0x7ffefc000950) at /home/mysql/soft/percona-server-5.7.29-32/sql/transaction.cc:515
#5  0x00000000014c08de in mysql_execute_command (thd=0x7ffefc000950, first_level=true) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:5325
#6  0x00000000014c2025 in mysql_parse (thd=0x7ffefc000950, parser_state=0x7fffe88824a0, update_userstat=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:5927
#7  0x00000000014b6c5f in dispatch_command (thd=0x7ffefc000950, com_data=0x7fffe8882c90, command=COM_QUERY) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:1539
#8  0x00000000014b5a94 in do_command (thd=0x7ffefc000950) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:1060
#9  0x00000000015e9d32 in handle_connection (arg=0x3c09eb0) at /home/mysql/soft/percona-server-5.7.29-32/sql/conn_handler/connection_handler_per_thread.cc:325
#10 0x00000000018b97f2 in pfs_spawn_thread (arg=0x3b784b0) at /home/mysql/soft/percona-server-5.7.29-32/storage/perfschema/pfs.cc:2198
#11 0x00007ffff7bc6ea5 in start_thread () from /lib64/libpthread.so.0
#12 0x00007ffff5fa08dd in clone () from /lib64/libc.so.6

栈2 写入等待timeout=60000 即默认的write_timeout=60S

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#0  0x00007ffff5f95c3d in poll () from /lib64/libc.so.6
#1  0x0000000001da0e3b in vio_io_wait (vio=0x7ffefc005690, event=VIO_IO_EVENT_WRITE, timeout=60000) at /home/mysql/soft/percona-server-5.7.29-32/vio/viosocket.c:1173
#2  0x0000000001d9f352 in vio_socket_io_wait (vio=0x7ffefc005690, event=VIO_IO_EVENT_WRITE) at /home/mysql/soft/percona-server-5.7.29-32/vio/viosocket.c:127
#3  0x0000000001d9f74a in vio_write (vio=0x7ffefc005690, buf=0x7ffefc013838 "\001\061\001\060\004", size=12872) at /home/mysql/soft/percona-server-5.7.29-32/vio/viosocket.c:260
#4  0x00000000016f92a3 in net_write_raw_loop (net=0x7ffefc002528, buf=0x7ffefc013838 "\001\061\001\060\004", count=12872) at /home/mysql/soft/percona-server-5.7.29-32/sql/net_serv.cc:522
#5  0x00000000016f9588 in net_write_packet (net=0x7ffefc002528, packet=0x7ffefc012a80 "\001\061\001\060\004", length=16384) at /home/mysql/soft/percona-server-5.7.29-32/sql/net_serv.cc:661
#6  0x00000000016f9177 in net_write_buff (net=0x7ffefc002528, packet=0x7ffefc936f70 "\001\061\001\060", len=4) at /home/mysql/soft/percona-server-5.7.29-32/sql/net_serv.cc:474
#7  0x00000000016f8e1c in my_net_write (net=0x7ffefc002528, packet=0x7ffefc936f70 "\001\061\001\060", len=4) at /home/mysql/soft/percona-server-5.7.29-32/sql/net_serv.cc:347
#8  0x0000000001745635 in Protocol_classic::end_row (this=0x7ffefc001c68) at /home/mysql/soft/percona-server-5.7.29-32/sql/protocol_classic.cc:1204
#9  0x00000000014571d7 in Query_result_send::send_data (this=0x7ffefc0097a0, items=...) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_class.cc:2937
#10 0x0000000001477a0d in end_send (join=0x7ffefc009a70, qep_tab=0x7ffefc93b290, end_of_records=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_executor.cc:2946
#11 0x000000000147461b in evaluate_join_record (join=0x7ffefc009a70, qep_tab=0x7ffefc93b118) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_executor.cc:1652
#12 0x0000000001473a5b in sub_select (join=0x7ffefc009a70, qep_tab=0x7ffefc93b118, end_of_records=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_executor.cc:1304
#13 0x00000000014732dc in do_select (join=0x7ffefc009a70) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_executor.cc:957
#14 0x0000000001471243 in JOIN::exec (this=0x7ffefc009a70) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_executor.cc:206
#15 0x000000000150d2d5 in handle_query (thd=0x7ffefc000950, lex=0x7ffefc003000, result=0x7ffefc0097a0, added_options=0, removed_options=0)
    at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_select.cc:192
#16 0x00000000014c1097 in execute_sqlcom_select (thd=0x7ffefc000950, all_tables=0x7ffefc009160) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:5490
#17 0x00000000014ba323 in mysql_execute_command (thd=0x7ffefc000950, first_level=true) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:3016
#18 0x00000000014c2025 in mysql_parse (thd=0x7ffefc000950, parser_state=0x7fffe88824a0, update_userstat=false) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:5927
#19 0x00000000014b6c5f in dispatch_command (thd=0x7ffefc000950, com_data=0x7fffe8882c90, command=COM_QUERY) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:1539
#20 0x00000000014b5a94 in do_command (thd=0x7ffefc000950) at /home/mysql/soft/percona-server-5.7.29-32/sql/sql_parse.cc:1060
#21 0x00000000015e9d32 in handle_connection (arg=0x3c09eb0) at /home/mysql/soft/percona-server-5.7.29-32/sql/conn_handler/connection_handler_per_thread.cc:325
#22 0x00000000018b97f2 in pfs_spawn_thread (arg=0x3b784b0) at /home/mysql/soft/percona-server-5.7.29-32/storage/perfschema/pfs.cc:2198
#23 0x00007ffff7bc6ea5 in start_thread () from /lib64/libpthread.so.0
#24 0x00007ffff5fa08dd in clone () from /lib64/libc.so.6
(gdb) 

参考链接

https://www.jianshu.com/p/735fdf9673e4

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 yangyidba 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL DBA如何利用strace/pstack/gdb来定位问题
strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用。 Strace是一个简单的跟踪系统调用执行的工具。在其最简单的形式中,它可以从开始到结束跟踪二进制的执行,并在进程的生命周期中输出一行具有系统调用名称,每个系统调用的参数和返回值的文本行。
老叶茶馆
2020/06/24
2.3K0
从MySQL源码看其网络IO模型
MySQL是当今最流行的开源数据库,阅读其源码是一件大有裨益的事情(虽然其代码感觉比较凌乱)。而笔者阅读一个Server源码的习惯就是先从其网络IO模型看起。于是,便有了本篇博客。
无毁的湖光-Al
2019/07/01
2.5K0
从MySQL源码看其网络IO模型
从零开始学习MySQL调试跟踪(1)
有时为了跟踪故障需要调试MySQL/GreatSQL源码,本文介绍如何在Linux下构建MySQL/GreatSQL源码调试环境。
GreatSQL社区
2023/08/10
5020
从零开始学习MySQL调试跟踪(1)
show status和set gtid_mode 导致线程死锁案例
我们数据库组今年上半年的计划之一是将所有数据库实例打开GTID特性。在线上进行灰度开启GITD过程中遇到数据库hang。具体表现是执行如下命令时:
用户1278550
2019/05/07
9960
show status和set gtid_mode 导致线程死锁案例
MySQL:ERROR 1286 (42000): Unknown storage engine 'MyISAM'
我们环境中设置enforce_storage_engine为Innodb,sql_mode中设置了NO_ENGINE_SUBSTITUTION。
老叶茶馆
2020/06/24
1.1K0
从MySQL源码看其网络IO模型
MySQL是当今最流行的开源数据库,阅读其源码是一件大有裨益的事情(虽然其代码感觉比较凌乱)。而笔者阅读一个Server源码的习惯就是先从其网络IO模型看起。于是,便有了本篇博客。
码农架构
2020/11/14
6020
从MySQL源码看其网络IO模型
Percona 8.0.30中"show engine innodb status"导致coredump排查及分析
GreatSQL合并Percona-Server 8.0.30的Beta版测试中,QA报了一个crash的bug:
老叶茶馆
2023/09/01
2800
Percona 8.0.30中"show engine innodb status"导致coredump排查及分析
利用GDB调试 MSQL
啃完O'reilly的《高性能mysql》、姜老师的《MySQL技术内幕》,再加上个2,3年的实战经验,就基本可以成为一名能独立处理问题的DBA了。但有些时候遇到些很刁钻的疑难杂症的话,那就束手无策了。
老叶茶馆
2020/09/07
2.9K0
利用GDB调试 MSQL
MySQL Update执行流程解读
一、update跟踪执行配置 使用内部程序堆栈跟踪工具path_viewer,跟踪mysql update 一行数据的执行过程,配置执行脚本:call_update.sh DROP DATABASE IF EXISTS d1; CREATE DATABASE d1; use d1; drop table if exists test; CREATE TABLE test (c0 int NOT NULL AUTO_INCREMENT,c1 date DEFAULT NULL,c2 time DEFA
GreatSQL社区
2022/04/01
2.3K1
mysql5.7.41commit流程源码解读
为了使代码好看, 很多时候 函数返回 True 表示失败, False表示成功. 但还是得看个人习惯, 比如我更习惯在条件前面加个not或者!, 虽然会有额外的转换, 但是代码更易读.
大大刺猬
2023/02/15
6420
MySQL:关于RR模式下insert..select sending data状态说明
其中的sending data是什么意思。隔离级别为RR,语句为insert..select。
老叶茶馆
2020/06/24
8630
从一个案例深入剖析InnoDB隐式锁和可见性判断
出现这个问题的时候只存在一个读写事务,那就是本事务。对这里的红色部分比较感兴趣,但是这里不是所有的内容都和这个问题相关,主要还是围绕可见性判断和隐式锁判定进行,算是我的思考过程。但是对Innodb认知水平有限,如有误导请谅解。使用的源码版本5.7.29。
老叶茶馆
2020/11/11
8070
从一个案例深入剖析InnoDB隐式锁和可见性判断
畅游数据库性能优化过程简析(上)
本文主要介绍了一种基于MySQL数据库的表结构设计,旨在解决大数据量、高并发访问场景下,数据库的查询性能问题。通过合理的表结构设计、索引优化、缓存策略,使得数据库能够在大流量、高并发的情况下,仍然保持较高的查询性能。同时,针对可能出现的性能问题,提供了相应的优化建议。
musazhang
2017/06/19
3.5K0
MySQL源码学习系列(一)-- 环境准备及常用命令
这些答案及解题灵感都藏于源码中! 本系列就准备通过案例结合源码调试来进行学习、解惑。其中源码安装可以参考历史文章MySQL8.0.40编译安装,如有问题可关注我进行交流。
俊才
2025/03/28
460
MySQL源码学习系列(一)-- 环境准备及常用命令
故障分析 | 全局读锁一直没有释放,发生了什么?
爱可生交付服务部团队北京 DBA,主要负责处理 MySQL 的 troubleshooting 和我司自研数据库自动化管理平台 DMP 的日常运维问题,对数据库及周边技术有浓厚的学习兴趣,喜欢看书,追求技术。
爱可生开源社区
2021/01/14
1.2K0
故障分析 | 全局读锁一直没有释放,发生了什么?
畅游数据库性能优化过程简析(下)
该文总结了近期技术社区内出现的一些问题及解决方案,包括数据库选型、引擎优化、事务隔离级别、高可用架构设计等方面。此外,文章还对未来的一些技术方向进行了展望。
musazhang
2017/06/19
1.9K0
MySQL 慢日志 :你想要的这里都有
本文介绍了MySQL慢日志的作用、设置方法、查看方法以及相关的分析工具。慢日志是MySQL性能调优和诊断的重要工具,用于记录在MySQL中响应时间超过阈值的SQL语句。通过设置slow_query_log和long_query_time参数可以开启慢日志。使用mysqldumpslow、pt-query-digest等工具可以对慢日志进行分析。
邹鹏
2017/06/16
2.7K0
MySQL 慢日志 :你想要的这里都有
MySQL:innodb_open_files参数及其周边
这个参数控制的是实际的Iinnodb层同时打开的文件数量(open),当然大于了也不会报错,通过LRU链表淘汰即可。这个一点和open_files_limit是不一样的。
老叶茶馆
2021/07/09
1.8K0
MySQL:innodb_open_files参数及其周边
从零开始学习MySQL调试跟踪(2)
程序运行过程中可能会异常终止或崩溃,OS会把程序挂掉时的内存状态记录下来,写入core文件,这就叫 coredump,通过gdb结合core文件可以方便地进行调试。
GreatSQL社区
2023/08/10
3350
从零开始学习MySQL调试跟踪(2)
OpenSSL与yaSSL性能对比
摘要 MySQL可以使用OpenSSL或yaSSL/wolfSSL进行编译,这两者都支持基于OpenSSL API的加密连接。在5.7版本,我们知道默认情况下MySQL Community Edition用的SSL库是yaSSL,而在8.0版本,MySQL Community Edition用的是OpenSSL。那么SSL加密对性能有什么影响呢?这两个SSL库在性能上又到底有多大差别呢?我们接下来进行一些测试并进行分析。 测试内容 MySQL有两个功能使用到了SSL库,一个是SSL连接,通过在数据库服务器
腾讯数据库技术
2018/11/06
3.1K1
OpenSSL与yaSSL性能对比
相关推荐
MySQL DBA如何利用strace/pstack/gdb来定位问题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验