访问数据库超时问题排障

news2024/11/24 7:58:44

1 排障过程

系统从圣诞节那天晚上开始,每天晚上固定十点多到十一点多这个时段,大概瘫痪1h左右,过这时段系统自动恢复。系统瘫痪时的现象就是,网页和App都打不开,请求超时。系统架构:

img

整个系统托管在公有云,Nginx作为前置网关承接前端所有请求,后端按照业务,划分若干微服务。数据保存在MySQL,部分数据Memcached做前置缓存。数据并没按微服务最佳实践要求,做严格划分和隔离,而是为方便,存放在一起。这对一个业务变化极快的创业公司合理。因为它每个微服务,随时都在随业务改变,若严格数据隔离,反而不利应对需求变化。

听问题描述,第一反应每天晚上十点到十一点这个时段,是绝大多数内容类App的访问量高峰,因为这个时候大家都躺在床上玩儿手机。初步判断和访问量有关

每天访问量图可印证判断:

img

排查重点应放在那些服务于用户访问的功能。如首页、商品列表页、内容推荐。在访问量峰值时,请求全部超时,随访问量减少,系统能自动恢复,基本排除后台服务被大量请求打死的可能性,因为若进程被打死,一般不会自动恢复。

排查问题的重点应该放在MySQL。观察MySQL CPU利用率:

img

故障时段MySQL的CPU利用率一直是100%。MySQL基本处不可用状态,执行所有SQL都会超时。MySQL这种CPU利用率高,绝大多数都是慢SQL导致,优先排查慢SQL。MySQL和各大云厂商提供的RDS都能提供慢SQL日志,分析慢SQL日志,是查找类似问题原因最有效方法。

一般慢SQL日志有信息:SQL、执行次数、执行时长。通过分析慢SQL找问题,并没有什么标准的方法,主要靠经验。

数据库非常忙时,执行任何一个SQL都很慢。所以,不是说慢SQL日志中记录的这些慢SQL都是有问题SQL。大部分导致问题的SQL只是其中一或几条。不能简单依据执行次数和执行时长判断,但单次执行时间特长的SQL,仍是重点排查对象。

找到一个特别慢SQL:红人排行榜,列出粉丝数最多的TOP10红人。

select fo.FollowId as vid, count(fo.id) as vcounts
from follow fo, user_info ui
where fo.userid = ui.userid
and fo.CreateTime between
str_to_date(?, '%Y-%m-%d %H:%i:%s')
and str_to_date(?, '%Y-%m-%d %H:%i:%s')
and fo.IsDel = 0
and ui.UserState = 0
group by vid
order by vcounts desc
limit 0,10

这种排行榜的查询,一定要做缓存。排行榜是新上线功能,可能忘记做缓存,通过增加缓存可有效地解决问题。

给排行榜加缓存后,新版本立即上线。本以为问题解决,当天晚上系统仍一样现象,晚高峰各种请求超时,页面打不开。再分析慢SQL日志,排行榜慢SQL不见了,说明缓存生效。日志中的其他慢SQL,查询次数和查询时长分布的都很均匀,也没看出明显问题SQL。

再看MySQL CPU利用率:

img

放大后的规律:

  1. CPU利用率以20min为周期规律波动
  2. 总体趋势与访问量正相关

猜测对MySQL CPU利用率的“贡献”来自两部分:

  • 红线以下部分,正常处理日常访问请求的部分,和访问量正相关
  • 红线以上部分,来自某20min为周期定时任务,和访问量关系不大

img

排查整个系统,没有发现20min为周期定时任务,继续扩大排查范围,排查周期小于20min定时任务,最终定位问题。

App首页聚合非常多,像精选商品、标题图、排行榜、编辑推荐等。这些内容包含很多数据库查询。当初设计时,给首页做个整体缓存TTL=10min。但需求不断变化,首页要查询内容越来越多,导致查询首页全部内容越来越慢。

通过检查日志发现,刷新一次缓存的时间竟然要15min。缓存是每隔10min整点刷一次,因为10min内刷不完,所以下次刷新就推迟到20min后,这就导致了上面这个图中,红线以上每20分钟的规律波形。

由于缓存刷新慢,也会很多请求无法命中缓存,请求直接穿透缓存打到DB,这部分请求给上图红线以下部分,做很多“贡献”。

找到了问题原因,做针对性的优化,问题很快解决:

img

2 如何避免悲剧重演

问题原因在于开发犯了错误,编写SQL没有考虑数据量和执行时间,缓存使用也不合理。最终导致在忙时,大量查询打到MySQL,MySQL繁忙无法提供服务。总结经验:

编写SQL要谨慎评估。问自己:

  • 你的SQL涉及到的表,它的数据规模多少
  • 你的SQL可能遍历的数据量多少
  • 尽量避免写慢SQL

能不能利用缓存减少DB查询次数?使用缓存时,还要注意缓存命中率,要尽量避免请求命中不了缓存,穿透到DB。

优秀的系统架构,可以在一定程度上,减轻故障对系统的影响。针对这次事故,我给这个系统在架构层面,提了建议。

上线一个定时监控和杀掉慢SQL的脚本。这个脚本每分钟执行一次,检测上一分钟内,有没有执行时间超过一分钟(这个阈值可以根据实际情况调整)的慢SQL,如果发现,直接杀掉这会话。这有效避免一个慢SQL拖垮整个数据库。即使慢SQL,数据库也可以在至多1分钟内自动恢复,避免数据库长时间不可用。代价是,可能会有些功能,之前运行是正常的,这个脚本上线后,就会出现问题。但是,这个代价还是值得付出的,并且,可以反过来督促开发人员更加小心,避免写慢SQL。

做一个简单的静态页面首页作为降级方案,只要包含商品搜索栏、大的品类和其他顶级功能模块入口的链接。在Nginx做个策略,如果请求首页数据超时的时候,直接返回这个静态的首页作为替代。这样后续即使首页再出现任何的故障,也可以暂时降级,用静态首页替代。至少不会影响到用户使用其他功能。

这两个改进建议都是非常容易实施的,不需要对系统做很大的改造,也立竿见影。

当然,这个系统的存储架构还有很多可以改进的地方,比如说对数据做适当的隔离,改进缓存置换策略,做数据库主从分离,把非业务请求的数据库查询迁移到单独的从库上等等,只是这些改进都需要对系统做比较大的改动升级,需要从长计议,在系统后续的迭代过程中逐步地去实施。

总结

  1. 根据故障时段在系统忙时,推断出故障是跟支持用户访问的功能有关。
  2. 根据系统能在流量峰值过后自动恢复这一现象,排除后台服务被大量请求打死的可能性。
  3. 根据CPU利用率曲线的规律变化,推断出可能和定时任务有关。

在故障复盘阶段,除了对故障问题本身做有针对性的预防和改进以外,更重要的是,在系统架构层面进行改进,让整个系统更加健壮,不至于因为某一个小的失误,就导致全站无法访问。

我给系统提出的第一个自动杀慢SQL的建议,它的思想是:系统的关键部分要有自我保护机制,避免外部的错误影响到系统的关键部分。第二个首页降级的建议,它的思想是:当关键系统出现故障的时候,要有临时的降级方案,尽量减少故障带来的影响。

这些架构上的改进,虽然并不能避免故障,但是可以很大程度上减小故障的影响范围,减轻故障带来的损失,希望你能仔细体会,活学活用。

FAQ

什么样的SQL算是慢SQL?如何才能避免写出慢SQL?

慢SQL 我感觉也没有个人标准,个人的标准也要分场景,业务复杂度等;如果作为常规的用户业务系统,超过1秒就是慢SQL;但是如果是类似生成报表的服务,选择在业务低峰期,从库执行等策略,时间长点也不是不能接受。
避免慢SQL:第一点肯定想到的是合适的索引,毕竟SQL执行速度的快慢关键还是语句需要扫描数据的行数,如尽量不要使用 对where 条件列进行计算的做法让MySQL查询优化器不知道怎么选择索引,特定业务 可以设置联合索引让需要查询返回的列都在索引中避免回表操作。
第二:排序也是可能完成慢SQL的因素,尤其是数据量大,需要使用外部排序的时候又可以与磁盘IO性能扯上关系等,常见的问题还有limit m,n m很大又无法使用索引的时候
第三:多表联合查询的时候,尽量使用小表驱动大表。
第四:避免大事务,这也是发生死锁常见的雷区,尽量减小事务粒度,尽量注意不同事务对表操作的顺序一致,大事务其实也包含着批量操作的隐式事务,如一个update 影响100万行数据。

第五:见过的关于架构方面的慢SQL问题 1~数据量到达一定规模后,单机性能容易受限导致数据库响应慢;2~读写分离,从库提供读服务,错误的认为从库只需要提供查询服务采用了达不到性能指标的机器,其实是主库承受的数据更新压力,从库一个不落的都要承受,还要更多的提供查询服务

上面那个小型创业公司的微服务架构,想知道有关 Nginx 的主备是怎么实现的?

我们例子里面当时它采用的就是人肉冷备,主节点出问题的时候人肉切换到备用节点上。

其实更合理的做法是做通过负载均衡器或者域名把流量均匀的打到多个NGINX节点上,配合探活机制,当某个节点有问题的时候,自动摘掉这个节点。

做一个Mysql的本地熔断方案。就是监控对每一个表的操作语句,通过机器数量在配置中心配置每个服务的访问频次、访问时间等。比如Mysql的TPS是4000,我们有10台机器,平均下来每个服务的上限为400/s。碰到超限、或者超慢的情况就熔断、告警。可以整体监控,也可以对热点表进行监控,这种方案是否可行?

必须可行啊。但要注意一下配置中心的高可用。别出现因为配置中心宕机,导致不能熔断了。

当第一个慢查询SQL处理完成后,MySQL的CPU使用率已经降到了20%以下。那么即便会有周期性的SQL执行,但是以这个利用率不足以整体导致服务不可用吧。

20%左右那个是闲时的图,忙时依然是100%。

为什么后台服务被大量请求打死的话无法自动恢复呢?

一般“服务被打死”,比较常见的情况是内存溢出、栈溢出或者进程直接挂掉,这些情况都是不能自动恢复的。

案例中用的什么cache,怎么refresh的?

案例中用的是Memcached,刷新的策略也是根据不同业务有不同的策略。

慢SQL要以业务场景来区分。例如做即时通讯或者消息类等有实时性要求的,可能2秒就算慢查询了,但是读从库做大数据分析的场景,可能跑一个小时也不算慢。另外,对于请数量大的时候,如果存在多个请求会加锁,即使一个查询是毫秒级别的,上百个查询访问一个热数据加锁也会有很大的问题,所以,没有慢查询的具体标准,影响到业务,拖慢了服务的,就算慢查询。

作者文中描述的问题可以理解成就是缓存更新慢,导致的缓存穿透

\1. 缓存热点数据 : 因为使用连表查询等复杂语句在数据量大的时候会产生慢差 。是否该考虑修改查询语句或者上搜索(es / 阿里open search ) 然后再加一道缓存 缓存的读写策略采用旁路策略。

\2. 像这种定时任务应该大部分公司都会有很多,一般都是放到凌晨来执行 ,经常会有人问当数据量大的时候 这种定时任务是否可行。 所以像数据量非常大(京东这种级别数据) 定时任务扫表是否还可行 有没有其他的解决思路

这种大查询,首先肯定是要用缓存,但要根据实际情况选择合适的缓存更新策略。

数据量特别大的统计分析,一般选择放到其它分析型数据库或者数据仓库中去执行,或者使用流计算来解决。

首页缓存过期时间要设置一个随机值,不然会造成缓存雪崩。

重构:用自己的话,重述内容

对于一次系统高峰时段出现的问题,从排查分析到解决,到复盘总结,过程的一次演练。
根据出现的时间段,分析出是用户请求超时导致的结果,进而对系统中的慢sql进行分析,分析出慢sql之后进行修复,从数据库cpu使用率上分析出定时任务的存在,并分析出定时任务的周期,至此问题解决。但在复盘的时候从架构的层次进行了更为本质的分析,并给出数据库慢sql的预处理模式,数据库分离的建议以及页面降级预案。

架构上有自我保护机制这点学习了。这个例子中,我觉得应该打开代码层面的数据库模块的日志开关,例如mybatis有拦截器可以记sql语句和数量,应该能根据sql语句看到异常的sql(首页请求没命中缓存),或者选取2个时间段,一个有问题,一个没问题,把同类sql按总数量大小从大到小用表格比一下,应该也能发现问题。日志是非常重要的一环。

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

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

相关文章

图解数据结构:盘点链表与栈和队列的那些血缘(单双链表模拟实现栈和队列)

写在前面 Hello,各位盆友们,我是黄小黄。关于前一段时间为什么拖更这件事,这里给大家说一句抱歉。笔者前段时间忙于ddl和一些比赛相关的事件,当然还有些隐藏任务,所以博文更新就放缓了。  这里还需要做一下对以后博文…

计算机原理一_计算机的组成、进程与线程

目录儿一、计算机组成二、进程与线程2.1 线程的切换2.2 CPU的并发控制2.2.1 关中断2.2.2 缓存一致性协议2.2.2.1 缓存Cache2.2.2.2 缓存行Cache Line2.2.2.3 缓存一致性拓展:超线程2.2.3 内存屏障2.2.3.1 CPU的乱序执行拓展1:java 的 this 溢出问题拓展2…

Linux(一):Linux基本结构

一、Linux系统划分 linux系统分为用户区、内核区 1.1分区目标 保护数据和硬件安全,对系统进行分区也就是进程分区,当处于用户态,只能访问用户区,用户无法修改内核,保证硬件安全,操作系统不易损坏&#…

【Qt】QMainWindow应用程序窗口类简单介绍

QMainWindow介绍 QMainWindow是一个为用户提供主窗口程序的类,是许多应用程序的基础,包含的组件有: 菜单栏QMenuBar,一个主窗口最多只能有一个菜单栏;包含一个下拉菜单项的列表,这些菜单项由QAction动作类…

【git版本控制】| git版本控制操作命令(全)

文章目录一、简介二、工作模式1 集中式(CVS、SVN)2 分布式Git三、Git1 工作模式2 git工作流程3 工作区和版本库4 注意事项5 基本操作5.1 创建本地版本库5.2 初始化本地版本库5.3 .git目录的作用5.4 创建用户5.5 其他操作6 git分支7 常见警告8 免密登录9 …

interface接口--GO面向对象编程思想

一、interface接口 interface 是GO语言的基础特性之一。可以理解为一种类型的规范或者约定。它跟java,C# 不太一样,不需要显示说明实现了某个接口,它没有继承或子类或“implements”关键字,只是通过约定的形式,隐式的…

【C语言进阶】自定义类型:结构体,枚举,联合体

目录 1、结构体的声明 1.1 结构体基础知识 1.2 结构体的声明 1.3 特殊的声明 1.4 结构体的自引用 1.5 结构体变量的定义和初始化 1.6 结构体内存对齐 ​编辑1.7 修改默认对齐数 1.8 结构体传参 2. 位段 2.1 什么是位段 2.2 位段的内存分配 2.3 位段的跨平台问…

【owt-server】代码结构及新增一个agent

owt server 官方 5.0 仓库:代码结构 manage console manage api portal sip portal 与agent 并列 agent又有很多种类。 启动脚本 启动一个新的agent 比如streaming-agent streaming-agent )cd ${OWT_HOME}/s

分布式id

分布式id一 什么是分布式系统唯一ID二 分布式系统唯一ID的特点三 分布式系统唯一ID的实现方案3.1 基于UUID3.2 基于数据库自增id3.3 基于数据库集群模式3.4 基于Redis模式3.5 基于雪花算法(Snowflake)模式3.6 百度(uid-generator)…

Python爬虫数据到sqlite实例

参考链接:https://blog.csdn.net/qq_45775027/article/details/115319253最近需要使用到爬虫数据库,原文中作者有些没补齐,略作修改之后跑通了。主要修改:1.调整了数据获取的正则表达式;2. 改了一下数据库的table名和定义名字&…

基于Java+SpringBoot+vue+element实现前后端分离牙科诊所管理系统详细设计

基于JavaSpringBootvueelement实现前后端分离牙科诊所管理系统详细设计 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目…

【Linux】虚拟地址空间 --- 虚拟地址、空间布局、内存描述符、写时拷贝、页表…

该吃吃,该喝喝,遇事儿别往心上隔😎 文章目录一、虚拟地址空间1.虚拟地址的引出(看不到物理地址,只能看看虚拟地址喽)2.虚拟地址空间布局(五个段)3.感性理解一下虚拟地址空间&#xf…

【C++修炼之路】C++入门(上)

👑作者主页:进击的安度因 🏠学习社区:进击的安度因(个人社区) 📖专栏链接:C修炼之路 文章目录一、前言二、第一个 C 程序三、C 关键字(C98)四、命名空间1、命名空间的定义2、命名空间…

C++ Prime课后习题第一章编程

编程一个C程序&#xff0c;它显示您的姓名和地址。#include <iostream>int stonetolb(int); int main() {using namespace std;cout << "zzz ";cout << "闵行"<<endl;return 0; }编写一个程序&#xff0c;要求用户输入一个以long…

3台机器配置hadoop集群_Hadoop+Hbase 分布式集群架构

安装搭建Hadoop1、 配置说明本次集群搭建共三台机器&#xff0c;具体说明下&#xff1a;主机名IP说明nn01192.168.1.51DataNode、NodeManager、ResourceManager、NameNodedn01192.168.1.52DataNode、NodeManager、SecondaryNameNodedn02192.168.1.53DataNode、NodeManager2 、安…

基于浏览器的 PDF 编辑器:RAD PDF for ASP.NET

版本 3.34 改进的 PDF 收藏/投资组合支持和服务器 API 改进 Ω578867473功能更新 为更基本的 PDF 文件损坏/语法错误添加了更正添加了 PdfButtonField.NamedAction 属性添加了 PdfButtonField.IsNamedAction 属性添加 PdfButtonField() 构造函数 - PdfButtonFields 可以由服…

unity-常用组件实操案例

文章目录transform摄像机cameraskybox相机权重&#xff08;depth&#xff09;Audio sourcevideo playertransform 不但控制着组件的旋转、位置、缩放并且还控制着组件间的父子关系 using System; using System.Collections; using System.Collections.Generic; using UnityEn…

不锈钢企业如何利用APS排程软件提升管理效益?

保温杯一般是由陶瓷或不锈钢加上真空层做成的盛水容器&#xff0c;顶部有盖&#xff0c;密封严实&#xff0c;真空绝热层能使装在内部的水等液体延缓散热&#xff0c;以达到保温的目的。保温杯从保温瓶发展而来的&#xff0c;保温原理与保温瓶一样&#xff0c;只是人们为了方便…

Collection

面向对象语言对事物的体现都是以对象的形式&#xff0c;所以为了方便对多个对象的操作&#xff0c;就对对象进行存储&#xff0c;集合就是存储对象最常用的一种方式 数组和集合的不同&#xff1a; 数组长度是固定的&#xff1b;集合长度是可变的。 数组中可以存储基本数据类…

C#在控制台中打印进度条【同步和异步】

使用控制台打印进度条的简单方法。 有现成的IProgress接口进行操作&#xff1a; 实例&#xff1a; var prog new Progress<double>((theV > {Console.WriteLine($"Now the Progress&#xff1a;" COUNT / 10.0 * 100 "%" new string(#, COUN…