如何杀掉空闲事务

作者&投稿:昌筠 (若有异议请与网页底部的电邮联系)
~
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html 我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数




本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://www.penglixun.com/tech/database/how_to_kill_idle_trx.html

我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库,也没有释放线程,但是线上事务锁定等待严重,连接数暴涨,尤其在测试库这种情况很多,线上也偶有发生,于是想为MySQL增加一个杀掉空闲事务的功能。

那么如何实现呢,通过MySQL Server层有很多不确定因素,最保险还是在存储引擎层实现,我们用的几乎都是InnoDB/XtraDB,所以就基于Percona来修改了,Oracle版的MySQL也可以照着修改。

需求:
1. 一个事务启动,如果事务内最后一个语句执行完超过一个时间(innodb_idle_trx_timeout),就应该关闭链接。
2. 如果事务是纯读事务,因为不加锁,所以无害,不需要关闭,保持即可。
虽然这个思路被Percona的指出Alexey Kopytov可能存在“Even though SELECT queries do not place row locks by default (there are exceptions), they can still block undo log records from being purged.”的问题,但是我们确实有场景SELECT是绝对不能kill的,除非之后的INSERT/UPDATE/DELETE发生了,所以我根据我们的业务特点来修改。
跟Percona的Yasufumi Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill,但通过一个参数控制的方案还没有被Alexey Kopytov接受,作为通用处理我提出了用两个变量分别控制纯读事务的空闲超时时间和有锁事务的空闲超时时间,还在等待Percona的回复,因为这个方案还在测试,就先不开放修改了,当然如果你很熟悉MYSQL源码,我提出这个思路你肯定知道怎么分成这两个参数控制了。

根据这两个需求我们来设计方法,首先想到这个功能肯定是放在InnoDB Master Thread最方便,Master Thread每秒调度一次,可以顺便检查空闲事务,然后关闭,因为在事务中操作trx->mysql_thd并不安全,所以一般来说最好在InnoDB层换成Thread ID操作,并且InnoDB中除了ha_innodb.cc,其他地方不能饮用THD,所以Master Thread中需要的线程数值,都需要在ha_innodb中计算好传递整型或布尔型返回值给master thread调用。


首先,我们要增加一个参数:idle_trx_timeout,它表示事务多久没有下一条语句发生就超时关闭。
在storage/innodb_plugin/srv/srv0srv.c的“/* plugin options */”注释下增加如下代码注册idle_trx_timeout变量。

static MYSQL_SYSVAR_LONG(idle_trx_timeout, srv_idle_trx_timeout,
PLUGIN_VAR_RQCMDARG,
"If zero then this function no effect, if no-zero then wait idle_trx_timeout seconds this transaction will be closed",
"Seconds of Idle-Transaction timeout",
NULL, NULL, 0, 0, LONG_MAX, 0);
代码往下找在innobase_system_variables结构体内加上:

MYSQL_SYSVAR(idle_trx_timeout),
有了这个变量,我们需要在Master Thread(storage/innodb_plugin/srv/srv0srv.c )中执行检测函数查找空闲事务。在loop循环的if (sync_array_print_long_waits(&waiter, &sema)判断后加上这段判断

if (srv_idle_trx_timeout && trx_sys) {
trx_t* trx;
time_t now;
rescan_idle:
now = time(NULL);
mutex_enter(&kernel_mutex);
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); # 从当前事务列表里获取第一个事务
while (trx) { # 依次循环每个事务进行检查
if (trx->conc_state == TRX_ACTIVE
&& trx->mysql_thd
&& innobase_thd_is_idle(trx->mysql_thd)) { # 如果事务还活着并且它的状态时空闲的

ib_int64_t start_time = innobase_thd_get_start_time(trx->mysql_thd); # 获取线程最后一个语句的开始时间
ulong thd_id = innobase_thd_get_thread_id(trx->mysql_thd); #获取线程ID,因为存储引擎内直接操作THD不安全

if (trx->last_stmt_start != start_time) { # 如果事务最后语句起始时间不等于线程最后语句起始时间说明事务是新起的
trx->idle_start = now; # 更新事务的空闲起始时间
trx->last_stmt_start = start_time; # 更新事务的最后语句起始时间
} else if (difftime(now, trx->idle_start) # 如果事务不是新起的,已经执行了一部分则判断空闲时间有多长了
> srv_idle_trx_timeout) { # 如果空闲时间超过阈值则杀掉链接
/* kill the session */
mutex_exit(&kernel_mutex);
thd_kill(thd_id); # 杀链接
goto rescan_idle;
}
}
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); # 检查下一个事务
}
mutex_exit(&kernel_mutex);
}
其中trx中的变量是新加的,在storage/innodb_plugin/include/trx0trx.h的trx_truct加上需要的变量:

struct trx_struct{
...
time_t idle_start;
ib_int64_t last_stmt_start;
...
}
这里有几个函数是自定义的:

ibool innobase_thd_is_idle(const void* thd);
ib_int64_t innobase_thd_get_start_time(const void* thd);
ulong innobase_thd_get_thread_id(const void* thd);
这些函数在ha_innodb.cc中实现,需要在storage/innodb_plugin/srv/srv0srv.c头文件定义下加上这些函数的引用形势。

然后在storage/innodb_plugin/handler/ha_innodb.cc 中定义这些函数的实现:

extern "C"
ibool
innobase_thd_is_idle(
const void* thd) /*!< in: thread handle (THD*) */
{
return(((const THD*)thd)->command == COM_SLEEP);
}
extern "C"
ib_int64_t
innobase_thd_get_start_time(
const void* thd) /*!< in: thread handle (THD*) */
{
return((ib_int64_t)((const THD*)thd)->start_time);
}
extern "C"
ulong
innobase_thd_get_thread_id(
const void* thd)
{
return(thd_get_thread_id((const THD*) thd));
}
还有最重要的thd_kill函数负责杀线程的,在sql/sql_class.cc中,找个地方定义这个函数:

void thd_kill(ulong id)
{
THD *tmp;
VOID(pthread_mutex_lock(&LOCK_thread_count));
I_List_iterator it(threads);
while ((tmp=it++))
{
if (tmp->command == COM_DAEMON || tmp->is_have_lock_thd == 0 ) # 如果是DAEMON线程和不含锁的线程就不要kill了
continue;
if (tmp->thread_id == id)
{
pthread_mutex_lock(&tmp->LOCK_thd_data);
break;
}
}
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{
tmp->awake(THD::KILL_CONNECTION);
pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
}
为了存储引擎能引用到这个函数,我们要把它定义到plugin中:
include/mysql/plugin.h和include/mysql/plugin.h中加上

void thd_kill(unsigned long id);
如何判定线程的is_have_lock_thd值?首先在THD中加上这个变量(sql/sql_class.cc):

class THD :public Statement,
public Open_tables_state
{
....
uint16 is_have_lock_thd;
....
}
然后在SQL的必经之路mysql_execute_command拦上一刀,判断是有锁操作发生了还是事务提交或新起事务。

switch (lex->sql_command) {
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
thd->is_have_lock_thd = 1;
break;
case SQLCOM_COMMIT:
case SQLCOM_ROLLBACK:
case SQLCOM_XA_START:
case SQLCOM_XA_END:
case SQLCOM_XA_PREPARE:
case SQLCOM_XA_COMMIT:
case SQLCOM_XA_ROLLBACK:
case SQLCOM_XA_RECOVER:
thd->is_have_lock_thd = 0;
break;
}
为了尽可能兼容Percona的补丁,能引用的都引用了Percona的操作,有些函数调用是在层次太多看不下去了就简化了。
另外还有一个版本是我自己弄的,在THD中增加了一个last_sql_end_time,在do_command结束后更新last_sql_end_time,然后在事务中拿到THD查看last_sql_end_time就可以得出idle时间,Oracle版我还是建议这么做,不要去改trx_struct结构体了,那个感觉更危险。



空闲什么意思
空闲指的是没有忙碌的状态或时间,可以是工作或事务上的空闲,也可以是精神上的空闲。以下是详细解释:1. 工作或事务上的空闲:当人们完成工作或者没有需要处理的事务时,就会处于空闲状态。例如,在商店的营业时间里,如果没有顾客,店员就可能处于空闲状态。办公室在高峰工作时段之外也可能处于空闲状态。

《旧唐书 李峤传》原文及翻译
当时酷吏来俊臣诬陷狄仁杰、李嗣真、裴宣礼等三家,奏请杀掉他们,武则天令李峤与大理少卿张德裕、侍御史刘宪审理此案。张德裕等人虽然知道他们冤枉,却害怕因此获罪,都曲从来俊臣的诬奏。李峤说:“岂有知道无辜受害却不为他们申明的道理!孔子说: ‘见义不为,是没有勇气。”,便与张德裕等人列叙冤状,由此触犯...

电脑进程数过多怎么办
2. 软件上kill掉,把不必要的进程杀掉(必须知道进程是那个软件的正在用的不能杀),Ctrl+alt+del任务管理器,找到空闲进程杀死! 进程分组 下面都是进程都是无分组状态类别服务,对软件分类(用户组 本地服务 系统服务等都是支持软件运行的,把软件杀掉进程自然没有) 1)首先要干掉的是美化软件类,比如XX桌面啊,XX日历...

坏蛋是怎样炼成的2 第十一卷 黑暗崛起 第150章
原来孔世恒这几日已不在家中居住,而是搬到向问天的别墅里,与向问天,同住,向问天受到什么样的保护,他就受到什么样的保护,别说谢文东现在身边的血杀、暗组兄弟不多,就算吧人手凑齐了,也未必能杀掉孔世恒。 这下又打出了谢文东预交之外,正当他对南洪门的表现吃惊不已,萧芳找上门来。 今天萧芳的心情格外的清爽,笑...

求高手解答可以关掉哪些进程
系统空闲进程 默认它是占用除了当前应用程序所分配的处理器(CPU)百分比之外的所有占用率;;一旦应用程序发出请求,处理器会立刻响应的。在这个进程里出现的CPU占用数值并不是真正的占用而是体现的CPU的空闲率,也就说这个数值越大CPU的空闲率就越高,反之就是CPU的占用率越高 这些都是安全软件进程 杀...

萧何是何许人也???
秦王子婴设计杀了奸相赵高,献出玉玺,向刘邦投降。于是,起义大军浩浩荡荡开进咸阳城。将士们见秦都宫殿巍峨,街市繁华,顿时忘乎所以,纷纷乘乱抢掠金银财物,连沛公也忍不住,趁着空闲,跑到秦宫去东张西望。他看见华丽的宫室,古怪的摆设,成堆的金银珠宝,猎狗骏马,珍奇玩物,还有一群群的美女,不觉眼花缭乱,飘飘然起来...

刘备遗诏翻译
习凿齿(人名,东晋文史学家)也说诸葛亮“作为天下的丞相,想到得到功绩,却不能根据人的才能下达任务,根据人的能力给予责任,导致这些人犯了大错,违背了先主刘备的嘱托,包容责任的时候不公平,杀掉了有用的人材,说不上是聪明人”。李严、马谡对于蜀汉来说,都是不可多得的人才。个人对这些言论保留意见……虽然蜀汉...

进程数太多怎么办
进程数太多解决方法:一、如何查看进程 有英文基础的,同时按“Ctrl Alt Del”这三个键盘,打开“任务管理器”,查看正在运行的进程;不懂英文的,可从网上下载“360安全卫士”,打开360安全卫士-功能大全-选用“电脑优化”中的“进程管理”,在打开“正在运行”窗口,以列表的形式显示正在运行的:软件...

怎样手工杀毒?
危害较大的可执行病毒同样以“进程”形式出现在系统内部(一些病毒可能并不被进程列表显示,如“宏病毒”),那么及时查看并准确杀掉非法进程对于“手工杀毒有起着关键性的作用。由前面的知识介绍可知,Windows 9X和Windows 2000系统只能显示进程的名称,这对判断该进程是否是病毒还不够,如果要准确的断定病毒...

智囊《远犹卷二》译文与赏析
牧养的人说:“从太祖以来,就命令养猪。把它从小养到大,再杀掉,然后换养小的。几代都没有改变,也不知道做什么用。”神宗便命令把这件事取消了。一个多月后,宫内忽然捉到施放妖术的人,仓促间要找猪血来浇他却找不到,神宗这才领悟到祖宗的远虑。 【解评】 人如果没有长远的谋划,就会有即将到来的忧患。

肇源县18983321730: 进程数太多怎么办 -
住雁盐酸: 两种解决方案1. 硬件加强,增加内存条是不错选择,毕竟软件数据运行靠它2. 软件上kill掉,把不必要的进程杀掉(必须知道进程是那个软件的正在用的不能杀),Ctrl+alt+del任务管理器,找到空闲进程杀死!进程分组 下面都是进程都是无分组...

肇源县18983321730: 如何设置关闭服务器前,先关闭mysqld -
住雁盐酸: 安全地关闭MySQL实例 关闭过程:1、发起shutdown,发出 SIGTERM信号2、有必要的话,新建一个关闭线程(shutdown thread) 如果是客户端发起的关闭,则会新建一个专用的关闭线程 如果是直接收到 SIGTERM 信号进行关闭的话,专门负...

肇源县18983321730: 电脑桌面左上角有个广告栏怎么也关不掉..点关闭的符号没反应...急死我了 -
住雁盐酸: 如果重启后,还这样,1开始里面看看,有没有可以卸载的相关图表2开机启动项看看能否杀掉3在空闲时间,开着扫一下病毒和插件4任务管理器杀掉进程5右键广告栏,看看有没有退出6实在不行,重装系统更它掰掰...

肇源县18983321730: 电脑桌面死了,图标都不能点是怎么回事? -
住雁盐酸: 你的系统估计有问题,当然不一定是病毒或者是系统文件丢失.两种情况,两种办法:1、假设,是临时状态,仅仅是一下子出现的情况,而且你又著急用. 那麽:CTRL+ALT+ESC,呼出“任务管理器”,在“进程”标签中找到 EXPLORER;...

肇源县18983321730: 关闭scanfrm.exe进程启动的方法是怎样的?
住雁盐酸: 首先我们运行瑞星杀毒软件,找到瑞星的设置,在设置中选择“详细设置”,然后在界面的左侧“查杀设置”中找到“空闲时段查杀”选项,这样在成查杀任务列表上面能看到“瑞星空闲时段查杀”这个任务项了.然后点击“删除”按钮即可关闭scanfrm.exe启动了. 当然你在服务设置上面找到Rising Scan Service服务关闭该项服务也是可以不让scanfrm.exe进程启动的方法.首先点击“开始-运行”在运行输入框中输入services.msc,找到Rising Scan Service服务,选择“禁止”,然后在“任务管理器”里面结束scanfrm.exe这个进程,最后重启电脑,就OK了.

肇源县18983321730: 电脑变慢,CPU基本没有空闲 -
住雁盐酸: 1,清理系统垃圾,可以去网上下载个bat类型的清理垃圾小程序或者是用360等软件清理~!建议每天进行一次,每天第一次开机或是最后一次关机都行~!2,点开始,运行,键入 msconfig,打开开机启动项,点启动,把里边不需要的启动项关...

肇源县18983321730: 怎样计划每天的生活
住雁盐酸: 学习要安排一个简单可行的计划, 改善学习方法.同时也要适当参加学校的活动,全面发展. 在学习过程中,一定要:多听(听课),多记(记重要的范文,记重要的题型结构,记概念,记公式),多看(看书),多做(做作业),多问(不懂就...

肇源县18983321730: 如何避免 MySQL 修改表结构时导致表无法使用的问题 -
住雁盐酸: 来源:oschina.net 作者:whats_java MySQL 在修改表结构的时候可能会中断产品的正常运行影响用户体验,甚至更坏的结果,丢失数据.不是所有的数据库管理员、程序员、系统管理员都非常了解MySQL能避免这种情况.DBA会经常碰到这...

肇源县18983321730: system进程占用高并非空闲的那个进程,金山毒霸,那个进程总是
住雁盐酸: 强烈建议你使用第一种方法!! 如果你在任务管理器中无法关闭某个可疑进程,可以使用下面的方法强行关闭,注意不要杀掉进程表中的系统核心进程: 1.使用Windows ...

肇源县18983321730: 业务繁忙是什么意思
住雁盐酸: “业务繁忙”字面意思是工作繁重,没有空闲时间.业务指各行业中需要处理的事务,但通常偏向指销售的事务,因为任何公司单位最终仍然是以销售产品、销售服务、销售技术等等为主.“业务”最终的目的是“售出产品,换取利润”.所以通常会把业务员等于销售员.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网