Day886.MySQL的“饮鸩止渴”提高性能的方法 -MySQL实战

news2024/12/25 13:35:22

MySQL的“饮鸩止渴”提高性能的方法

HI,我是阿昌,今天学习记录的是关于MySQL的“饮鸩止渴”提高性能的方法的内容。

不知道在实际运维过程中有没有碰到这样的情景:

业务高峰期,生产环境的 MySQL 压力太大,没法正常响应,需要短期内、临时性地提升一些性能。以前做业务护航的时候,就偶尔会碰上这种场景。

用户的开发负责人说,不管用什么方案,让业务先跑起来再说。但,如果是无损方案的话,肯定不需要等到这个时候才上场。


一、短连接风暴

正常的短连接模式就是连接到数据库后,执行很少的 SQL 语句就断开,下次需要的时候再重连。

如果使用的是短连接,在业务高峰期的时候,就可能出现连接数突然暴涨的情况。


在基础架构中说过,MySQL 建立连接的过程,成本是很高的

  • 除了正常的网络连接三次握手
  • 还需要做登录权限判断
  • 获得这个连接的数据读写权限

在数据库压力比较小的时候,这些额外的成本并不明显。

但是,短连接模型存在一个风险,就是一旦数据库处理得慢一些,连接数就会暴涨。

max_connections 参数,用来控制一个 MySQL 实例同时存在的连接数的上限,超过这个值,系统就会拒绝接下来的连接请求,并报错提示“Too many connections”。

对于被拒绝连接的请求来说,从业务角度看就是数据库不可用。在机器负载比较高的时候,处理现有请求的时间变长,每个连接保持的时间也更长。这时,再有新建连接的话,就可能会超过 max_connections 的限制。碰到这种情况时,一个比较自然的想法,就是调高 max_connections 的值。但这样做是有风险的。

因为设计 max_connections 这个参数的目的是想保护 MySQL,如果把它改得太大,让更多的连接都可以进来,那么系统的负载可能会进一步加大,大量的资源耗费在权限验证等逻辑上,结果可能是适得其反,已经连接的线程拿不到 CPU 资源去执行业务的 SQL 请求。


那么这种情况下,还有没有别的建议呢?

这里还有两种方法,但要注意,这些方法都是有损的。

第一种方法:先处理掉那些占着连接但是不工作的线程。

max_connections 的计算,不是看谁在 running,是只要连着就占用一个计数位置。

对于那些不需要保持的连接,可以通过 kill connection 主动踢掉。这个行为跟事先设置 wait_timeout 的效果是一样的。

设置 wait_timeout 参数表示的是,一个线程空闲 wait_timeout 这么多秒之后,就会被 MySQL 直接断开连接。但是需要注意,在 show processlist 的结果里,踢掉显示为 sleep 的线程,可能是有损的。

来看下面这个例子。

图 1 sleep 线程的两种状态
在上面这个例子里,如果断开 session A 的连接,因为这时候 session A 还没有提交,所以 MySQL 只能按照回滚事务来处理;而断开 session B 的连接,就没什么大影响。

所以,如果按照优先级来说,你应该优先断开像 session B 这样的事务外空闲的连接。但是,怎么判断哪些是事务外空闲的呢?

session C 在 T 时刻之后的 30 秒执行 show processlist,看到的结果是这样的。

图 2 sleep 线程的两种状态,show processlist 结果

图中 id=4 和 id=5 的两个会话都是 Sleep 状态。

要看事务具体状态的话,可以查 information_schema 库innodb_trx 表

图 3 从 information_schema.innodb_trx 查询事务状态

这个结果里,trx_mysql_thread_id=4,表示 id=4 的线程还处在事务中。

因此,如果是连接数过多,可以优先断开事务外空闲太久的连接;如果这样还不够,再考虑断开事务内空闲太久的连接。

从服务端断开连接使用的是 kill connection + id 的命令, 一个客户端处于 sleep 状态时,它的连接被服务端主动断开后,这个客户端并不会马上知道。

直到客户端在发起下一个请求的时候,才会收到这样的报错“ERROR 2013 (HY000): Lost connection to MySQL server during query”。

从数据库端 主动断开连接可能是有损的 ,尤其是有的应用端收到这个错误后,不重新连接,而是直接用这个已经不能用的句柄重试查询

这会导致从应用端看上去,“MySQL 一直没恢复”。

可能觉得这是一个冷笑话,但实际上碰到过不下 10 次。

所以,如果是一个支持业务的 DBA,不要假设所有的应用代码都会被正确地处理。

即使只是一个断开连接的操作,也要确保通知到业务开发团队。

第二种方法:减少连接过程的消耗。

有的业务代码会在短时间内先大量申请数据库连接做备用,如果现在数据库确认是被连接行为打挂了,那么一种可能的做法,是让数据库跳过权限验证阶段

跳过权限验证的方法是:重启数据库,并使用–skip-grant-tables 参数启动

这样,整个 MySQL 会跳过所有的权限验证阶段,包括连接过程和语句执行过程在内。但是,这种方法特别符合标题里说的“饮鸩止渴”,风险极高,是特别不建议使用的方案。尤其库外网可访问的话,就更不能这么做了。


MySQL 8.0 版本里,如果启用–skip-grant-tables 参数,MySQL 会默认把 --skip-networking 参数打开,表示这时候数据库只能被本地的客户端连接。可见,MySQL 官方对 skip-grant-tables 这个参数的安全问题也很重视。

除了短连接数暴增可能会带来性能问题外,实际上,在线上碰到更多的是查询或者更新语句导致的性能问题。其中,查询问题比较典型的有两类:

  • 一类是由新出现的慢查询导致的
  • 一类是由 QPS(每秒查询数)突增导致的。

二、慢查询性能问题

在 MySQL 中,会引发性能问题的慢查询,大体有以下三种可能:

  1. 索引没有设计好;
  2. SQL 语句没写好
  3. MySQL 选错了索引

1、索引没有设计好

导致慢查询的第一种可能是,索引没有设计好。

这种场景一般就是通过紧急创建索引来解决。MySQL 5.6 版本以后,创建索引都支持 Online DDL 了,对于那种高峰期数据库已经被这个语句打挂了的情况,最高效的做法就是直接执行 alter table 语句。比较理想的是能够在备库先执行。


假设现在的服务是一主一备,主库 A、备库 B,这个方案的大致流程是这样的:

  1. 在备库 B 上执行 set sql_log_bin=off,也就是不写 binlog,然后执行 alter table 语句加上索引;
  2. 执行主备切换;
  3. 这时候主库是 B,备库是 A。在 A 上执行 set sql_log_bin=off,然后执行 alter table 语句加上索引。

这是一个“古老”的 DDL 方案。平时在做变更的时候,应该考虑类似 gh-ost 这样的方案,更加稳妥。但是在需要紧急处理时,上面这个方案的效率是最高的。

2、语句没写好

导致慢查询的第二种可能是,语句没写好。

比如,犯了在只查一行的语句,也执行这么慢?中提到的那些错误,导致语句没有使用上索引。这时,可以通过改写 SQL 语句来处理。

MySQL 5.7 提供了 query_rewrite 功能,可以把输入的一种语句改写成另外一种模式。

比如,语句被错误地写成了 select * from t where id + 1 = 10000,可以通过下面的方式,增加一个语句改写规则。

mysql> insert into query_rewrite.rewrite_rules(pattern, replacement, pattern_database) values ("select * from t where id + 1 = ?", "select * from t where id = ? - 1", "db1");

call query_rewrite.flush_rewrite_rules();

这里,call query_rewrite.flush_rewrite_rules() 这个存储过程,是让插入的新规则生效,也就是说的“查询重写”。


可以用图 4 中的方法来确认改写规则是否生效。

图 4 查询重写效果

3、选错了索引

在MySQL 为什么有时候会选错索引中提到的情况,MySQL 选错了索引

这时候,应急方案就是给这个语句加上 force index。同样地,使用查询重写功能,给原来的语句加上 force index,也可以解决这个问题。


由慢查询导致性能问题的三种可能情况,实际上出现最多的是前两种,即:索引没设计好和语句没写好。而这两种情况,恰恰是完全可以避免的。

比如,通过下面这个过程,可以预先发现问题

  1. 上线前,在测试环境,把慢查询日志(slow log)打开,并且把 long_query_time 设置成 0,确保每个语句都会被记录入慢查询日志;
  2. 在测试表里插入模拟线上的数据,做一遍回归测试
  3. 观察慢查询日志里每类语句的输出,特别留意 Rows_examined 字段是否与预期一致

不要吝啬这段花在上线前的“额外”时间,因为这会帮你省下很多故障复盘的时间。如果新增的 SQL 语句不多,手动跑一下就可以。而如果是新项目的话,或者是修改了原有项目的 表结构设计,全量回归测试都是必要的。这时候,需要工具帮你检查所有的 SQL 语句的返回结果。比如,可以使用开源工具 pt-query-digest


三、QPS 突增问题

有时候由于业务突然出现高峰,或者应用程序 bug,导致某个语句的 QPS 突然暴涨,也可能导致 MySQL 压力过大,影响服务。一类情况,是由一个新功能的 bug 导致的。

当然,最理想的情况是让业务把这个功能下掉,服务自然就会恢复。而下掉一个功能,如果从数据库端处理的话,对应于不同的背景,有不同的方法可用。

  1. 一种是由全新业务的 bug 导致的。假设 DB 运维是比较规范的,也就是说白名单是一个个加的。这种情况下,如果能够确定业务方会下掉这个功能,只是时间上没那么快,那么就可以从数据库端直接把白名单去掉。
  2. 如果这个新功能使用的是单独的数据库用户,可以用管理员账号把这个用户删掉,然后断开现有连接。这样,这个新功能的连接不成功,由它引发的 QPS 就会变成 0。
  3. 如果这个新增的功能跟主体功能是部署在一起的,那么只能通过处理语句来限制。这时,我们可以使用上面提到的查询重写功能,把压力最大的 SQL 语句直接重写成"select 1"返回。当然,这个操作的风险很高,需要特别细致。

它可能存在两个副作用:

  1. 如果别的功能里面也用到了这个 SQL 语句模板,会有误伤
  2. 很多业务并不是靠这一个语句就能完成逻辑的,所以如果单独把这一个语句以 select 1 的结果返回的话,可能会导致后面的业务逻辑一起失败

所以,方案 3 是用于止血的,跟前面提到的去掉权限验证一样,应该是所有选项里优先级最低的一个方案。同时你会发现,其实方案 1 和 2 都要依赖于规范的运维体系:虚拟化、白名单机制、业务账号分离。由此可见,更多的准备,往往意味着更稳定的系统。


四、总结

以业务高峰期的性能问题为背景,介绍了一些紧急处理的手段

这些处理手段中,既包括了粗暴地拒绝连接和断开连接,也有通过重写语句来绕过一些坑的方法;既有临时的高危方案,也有未雨绸缪的、相对安全的预案。

在实际开发中,也要尽量避免一些低效的方法,比如避免大量地使用短连接

同时,如果做业务开发的话,要知道,连接异常断开是常有的事,代码里要有正确地重连并重试的机制。

DBA 虽然可以通过语句重写来暂时处理问题,但是这本身是一个风险高的操作,做好 SQL 审计可以减少需要这类操作的机会。

其实,可以看得出来,在文章中提到的解决方法主要集中在 server 层


是否碰到过,在业务高峰期需要临时救火的场景?又是怎么处理的呢?

主从切换时遇到的问题,主从切换前主库要改为只读,设置只读后,show master status发现binlog一直在变化,当时应用没断开。
主库并不是其他库的从库,怎么搞的呢?
检查业务用户权限发现拥有super权限,查看授权语句原来是grant all on . to user,这里要说的是*.* 权限就太大了,而且这个也很容易被误解,需要特别注意。

对的,readonly对super无效;
一方面是尽量不要给业务super
一方面你做完readonly还会去确认binlog有没有变,这个意识很好哦


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/338186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣SQL刷题8

目录1212. 查询球队积分1270. 向公司CEO汇报工作的所有人1285. 找到连续区间的开始和结束数字1321. 餐馆营业额变化增长--重要窗口函数知识点补充1212. 查询球队积分 题型:读题 解答:先考虑做主方时,再考虑客方时 SELECT t.team_id, t.te…

人工智能轨道交通行业周刊-第33期(2023.2.6-2.12)

本期关键词:高铁激光清洗、高铁确认列车、无线通信系统、推理服务优化、量子信息技术 1 整理涉及公众号名单 1.1 行业类 RT轨道交通中关村轨道交通产业服务平台人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟V…

大数据系列之:安装pulsar详细步骤

大数据系列之:安装pulsar详细步骤一、Pulsar版本和jdk对应关系二、安装JDK三、设置和激活jdk环境变量四、下载和解压Pulsar五、查看Pulsar目录六、启动Pulsar standalone cluster七、创建Kafka Topic八、往Topic写入数据九、消费pulsar的Topic一、Pulsar版本和jdk对…

c#小笔记本-基础

c#基本知识一.基础操作1.打印-writeline,write2.输入-readline,readkey二.变量1.折叠代码-#region,#endregion2.变量类型(在c语言变量类型上新增的)三.常量-const四.转义字符五.显示转换1.括号强转-低精度装高精度2.parse法-作用于字符串3.co…

实践指南|如何在 Jina 中使用 OpenTelemetry 进行应用程序的监控和跟踪

随着软件和云技术的普及,越来越多的企业开始采用微服务架构、容器化、多云部署和持续部署模式,这增加了因系统失败而给运维/ SRE / DevOps 团队带来的压力,从而增加了开发团队和他们之间的摩擦,因为开发团队总是想尽快部署新功能&…

28岁才转行软件测试,目前32了,我的一些经历跟感受

我是92年的,算是最早的90后,现在跟你介绍的时候还恬不知耻的说我是90后,哈哈,计算机专业普通本科毕业。在一个二线城市,毕业后因为自身能力问题、认知水平问题,再加上运气不好,换过多份工作&…

关于@hide的理解

在上一篇文章《学习HandlerThread》我们提到虽然HandlerThread类里有getThreadHandler()方法得到Handler,但是我们不可能调用到它。因为这个方法用hide注释了 /*** return a shared {link Handler} associated with this thread* hide*/NonNullpublic Handler getT…

数据一致性

目录一、AOP 动态代理切入方法(1) Aspect Oriented Programming(2) 切入点表达式二、SpringBoot 项目扫描类(1) ResourceLoader 扫描类(2) Map 的 computeIfAbsent 方法(3) 反射几个常用 api① 创建一个测试注解② 创建测试 PO 类③ 反射 api 获取指定类的指定注解信息(4) 返回…

基于Golang哈希算法监控配置文件变化

SHA(secure hashing algorithm)表示安全哈希算法.SHA是MD5的修正版本,用于数据摘要和认证。哈希和加密类似,唯一区别是哈希是单项的,即哈希后的数据无法解密。SHA有不同的算法,主要包括SHA-1, SHA-2, SHA-256, SHA-512, SHA-224, …

1.2.6存储结构-磁盘管理:单缓冲区与双缓冲区读取、流水线周期、计算流水线执行时间

1.2.6存储结构-磁盘管理:单缓冲区与双缓冲区读取、流水线周期、计算流水线执行时间流水线周期计算流水线执行时间微秒,时间单位,符号μs(英语:microsecond ),1微秒等于百万分之一秒(…

SpringSecurity的使用与步骤

1、SpringSecurity流程图2、导入坐标<!-- spring-boot-starter-security --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- jjwt…

生物素-磺基-活性酯,Sulfo-NHS Biotin科研用试剂简介;CAS:119616-38-5

生物素-磺基-活性酯,Sulfo-NHS Biotin 结构式&#xff1a; ​ 编辑 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 英文名称&#xff1a;Sulfo-NHS-Biotin Sulfosuccinimidyl biotin 中文名称&#xff1a;磺酸基-Biotin-N-琥珀酰亚胺基酯 CAS&…

自己总结优化代码写法

jdk1.7新特性详解 开发期间略知jdk1.7的一些特性&#xff0c;没有真正的一个一个得展开研究&#xff0c;而是需要说明再去查&#xff0c;导致最整个新特性不是特别的清楚&#xff0c;这种情况以后得需要改变了&#xff0c;否则就会变成代码的奴隶。现在正好有时间可以细细的研…

SpringCloud第二讲 Ribbon负载均衡源码分析

前言介绍&#xff1a; 这一讲我们将依据Eureka的负载均衡规则&#xff0c;Eureka的具体服务搭建以及服务注册和服务发现可以参考基于Eureka实现服务注册和服务发现_热爱Java的编程小白的博客-CSDN博客 Eureka的服务搭建之后便可以在这上面进行服务注册&#xff0c;如果存在两个…

产品权限分析与设计

目前我们使用的访问控制授权方案&#xff0c;主要有以下4种&#xff1a;DAC自主访问控制ACL 访问控制列表MAC强制访问控制RBAC 基于角色的访问控制笔者将拆解和分析这4种权限管理方案的逻辑&#xff0c;并告诉你&#xff0c;这4种权限分别可以运用在什么样的场景中&#xff0c;…

不能注册?让小白也能使用【ChatGPT】

ChatGPT介绍最近ChatGPT可谓是非常火爆&#xff0c;使得互联网各界人士都备受关注&#xff0c;如果你还不了解ChatGPT,那你真的有点落后了哈。 简单介绍一下ChatGPTChatGPT是由美国人工智能OpenAI研究开发的一种全新聊天机器人模型&#xff0c;它能够通过学习和理解人类的语言跟…

研一寒假C++复习笔记--左值和右值的理解和使用

目录 1--左值和右值的定义 2--简单理解左值和右值的代码 3--非const引用只能接受左值 1--左值和右值的定义 左值&#xff1a;L-Value&#xff0c;L理解为 Location&#xff0c;表示可寻&#xff1b; 右值&#xff1a;R-Value&#xff0c;R理解为 Read&#xff0c;表示可读&a…

Windows 安装appium环境

1 windows Appium环境 1.1 安装Node.js Node.js的安装相对简单,下载安装包安装&#xff08;安装包node-v19.6.0-x64.msi&#xff09;, nodejs 安装 然后一路狂点下一步就可以了 安装完成后,在终端中输入node -v,显示版本号则表示安装成功 node-v16.13.1 1.2 JDK安装及环境变…

路由器刷固件

前言 我希望可以远程访问我的电脑。但&#xff0c;我不希望电脑总是处于运行状态&#xff0c;因为那样比较费电。所以需要一个方案&#xff0c;能将睡眠/关机中的电脑唤醒。 方案一&#xff1a;选用智能插座&#xff0c;远程给电脑上电。电脑设置上电自启。但&#xff0c;这存…

试题 算法训练 N皇后问题(明确清晰)

试题 算法训练 N皇后问题 提交此题 评测记录 资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;100ms Java时间限制&#xff1a;300ms Python时间限制&#xff1a;500ms 问题描述   在N*N的方格棋盘放置了N个皇后&#xff0c;使得它们不相互攻击&#xff08;即…