被sleep开了个小玩笑
本案例转载自李大玉老师分享
Ⅰ、问题背景
探活脚本连续8次探测,判断主库异常,触发切换(判断备机是否有延迟,kill原主,VIP飘到备机,设置新主可写)
切换后,业务还是异常,SQL查询没返回,DB连接数耗完,为了恢复业务,重启新主后业务恢复
两个问题
- 主库为什么会切换
- 切换后新主库为什么还是不可用
Ⅱ、问题排查
1、根据系统运行时间、系统日志以及服务器带外日志可排除服务器和数据库OOM
2、从每分钟的线程快照中发现故障时大量线程处于sending data和statistics状态,但前一分钟快照中未看到任何阻塞与锁等待
3、被阻塞的sql都是基于主键或者业务索引访问,理论上没问题,提取sql在从库执行一遍,很快,且当时没有产生慢日志,固排除sql执行效率慢导致阻塞
4、statistics是为sql生成执行计划的,会触发表的统计操作,而统计操作需要对表中page进行采样,会触发io,分析当时磁盘iops、吞吐量、cpu负载等,和前一天基本吻合,排除系统负载导致性能下降
思路中断~~~
复盘,开发反映业务切到新db,业务各个接口耗时变大,询问是否新库服务器性能不如老库
会后上机器发现实例上存在20个处于user sleep状态的sql,大概模型都是where id = '+(select 'rbzd' where 6910=6910 and sleep(300)+)',比较可疑,因为开发不会在程序中调用sleep函数
重点分析此sql
此sql不占用系统资源,但是写法可疑,类似sql注入
经查,sleep操作和innodb_thread_concurrency参数互斥,这样每秒只能处理24个sql
换言之当有24个线程进入引擎并处于sleep状态的话,其他线程是不能进入innodb引擎层,这里的24是和线上MySQL参数innodb_thread_concurrency被设置为24有关
Ⅲ、模拟故障
3.1 准备数据
CREATE TABLE `test` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into test select 1;
3.2 开24个线程访问此表
提前设置innodb_thread_concurrency设置为24模拟线上情况
[root@VM_42_63_centos ~]# for i in `seq 1 24`; do nohup mysql -S /tmp/mysql.sock3306 -e "select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+''" & done
3.3 观察一波
执行上一步脚本后,再开一个session访问test表会发现线程hang住,没返回,状态为sending data,如下:
(root@localhost) [test]> show processlist;
+----+------+-----------------+------+---------+------+--------------+----------------------------------------------------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+------+---------+------+--------------+----------------------------------------------------------------------------------------+
| 2 | root | localhost:38204 | NULL | Sleep | 0 | | NULL |
| 3 | root | localhost | test | Query | 0 | starting | show processlist |
| 4 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 5 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 6 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 7 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 8 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 9 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 10 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 11 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 12 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 13 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 14 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 15 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 16 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 17 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 18 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 19 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 20 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 21 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 22 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 23 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 24 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 25 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 26 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 27 | root | localhost | NULL | Query | 23 | User sleep | select id from test.test where id=''+(select 'rbzd' where 6910=6910 and sleep(300))+'' |
| 28 | root | localhost | NULL | Query | 11 | Sending data | select id from test.test |
+----+------+-----------------+------+---------+------+--------------+----------------------------------------------------------------------------------------+
27 rows in set (0.00 sec)
Ⅳ、故障回顾
1、sql注入,user sleep状态的sql累计到24条之后,其他sql就不能进入innodb进行操作,包括高可用探测程序,由于线程快照中过滤了sleep,导致没抓到注入的sql,加大了后续排查难度
2、主库的存活探测程序检查失败(探测方式为update一个innodb表),连续8次失败后,ha认为实例异常,则kill主,触发切换流程
3、切换到主库后,注入还在继续,所以同样的故障在新主上重演
4、重启主库后,仅有20个注入进入innodb且一直为user sleep,由于没达到24个触发阈值,所以业务表现正常,只是性能不及老主库,原因就是已经有20个线程在innodb层一直没退出,kill掉这些线程,业务恢复正常
Ⅴ、问题解决
- 由于线程快照过滤了sleep关键字,导致排查过程较长,后续要对user sleep状态线程保留在线程快照中
- 开发优化程序,防止sql注入
被sleep开了个小玩笑的更多相关文章
- java 开发面试题小整理(一)
本篇文档将持续更新,有基础滴,也有深层次的,谢谢! 1.看下面的程序是否有问题,如果有问题,请指出并说明理由. * byte b1 = 3; * byte b2 = 4; * byte b3 = b1 ...
- mitmproxy 中间人攻击的小玩笑
import mitmproxy.http from mitmproxy import ctx, http class Joker: def request(self, flow: mitmproxy ...
- java 开发面试题小整理(二)
51.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 答:可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和 ...
- 关于easyui模拟win2012桌面的一个例子系列
最近时间比较充裕,想到之前领导问我,什么界面更适合公司这种屏幕小但是又要求可以同时处理更多的工作. 我感觉 windows是最合适的,毕竟微软已经做了这么多年的系统了,人的操作习惯已经被他们确定了. ...
- 初识pngdrive
初识是第一次认识的意思,类似的词还有初见.初遇.初心.初愿.初恋.初吻……梦里相见如初识,很美好的感觉.同样,今天我们要认识的也是一个比较神奇美妙的东西,至少对于程序员来说. 我曾经尝试过很多文件加密 ...
- 《Python学习手册》读书笔记
之前为了编写一个svm分词的程序而简单学了下Python,觉得Python很好用,想深入并系统学习一下,了解一些机制,因此开始阅读<Python学习手册(第三版)>.如果只是想快速入门,我 ...
- 《Python学习手册》读书笔记【转载】
转载:http://www.cnblogs.com/wuyuegb2312/archive/2013/02/26/2910908.html 之前为了编写一个svm分词的程序而简单学了下Python,觉 ...
- 关于 C 语言,我喜欢和讨厌的十件事
前言:最近有个家伙抱怨道“为什么我还要再用C?”-虽然我不同意他的说法,但至少他随口提到如果你“在一台拇指大小的电脑”上编程,或者为一门语言写引导程序,那么可以用C语言.要我说,写设备驱动,或者特定平 ...
- Microsoft Interview第一轮
上来随意交谈了一小会儿,开了点小玩笑,chat了一些关于他们recruter行程的话题,缓和了一下气氛. 进入正题,问了做的research的方向,我说是DLT,然后大概给他讲解了一下具体是什么, 跟 ...
随机推荐
- centos添加开放端口
Centos 开放 80 端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 重启防火墙 firewall-cmd --reload ...
- Django 上下文处理器
Django 上下文处理器 模板要在上下文中渲染. 上下文是django.template.Context的实例.django.template.RequestContext是Django提供的一个子 ...
- 单模式串匹配----浅谈kmp算法
模式串匹配,顾名思义,就是看一个串是否在另一个串中出现,出现了几次,在哪个位置出现: p.s. 模式串是前者,并且,我们称后一个 (也就是被匹配的串)为文本串: 在这篇博客的代码里,s1均为文本串, ...
- C语言malloc函数为一维,二维,三维数组分配空间
c语言允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放,这些数据存储在堆区.可以根据需要,向系统申请 ...
- XAMPP环境下配置Phalcon框架
目前环境:win7 xampp 从phalcon 官网下载如下包:https://phalconphp.com/en/download/windows phalcon_x86_vc11_php5.6 ...
- how2heap学习笔记
github源代码地址 这里只分析glibc2.25堆分配的特性,为了方便调试编译时使用 gcc -g -no-pie <input_file_name> -o <output_fi ...
- 【原创】大叔问题定位分享(17)spark查orc格式数据偶尔报错NullPointerException
spark查orc格式的数据有时会报这个错 Caused by: java.lang.NullPointerException at org.apache.hadoop.hive.ql.io.orc. ...
- cdh zookeeper 不断拒绝连接
测试hiveserver2高可用的时候,需要登录zookeeper检查hiveserver2是否在zookeeper中注册 执行 zookeeper-client 不断的拒绝连接 -- ::, [my ...
- 网络流24题——分配问题 luogu 4014
题目链接:这里 本题是一个典型的费用流问题,可以作为费用流建图模板使用 首先看到,每个人只能做一件工作,每件工作只能做一次,一个人做某件工作有一定的收益 那么我们建立一个超级源点st和超级终点ed,然 ...
- swiper2 swiper-slide 之间的间距调整
1.在css中调整间距(我的这个是一行显示三个) swiper-slide-active 可以对这个类进行操作 这个类是显示在页面上的第一个元素 2.设置js //热门新闻 swiper var ne ...