极客时间已完结课程限时免费阅读

春节特别策划 | 高并发下如何发现和排查问题?

春节特别策划 | 高并发下如何发现和排查问题?-极客时间

春节特别策划 | 高并发下如何发现和排查问题?

讲述:唐扬

时长11:01大小8.83M

你好,我是唐扬,新年快乐!
过年嘛,都要吃好玩好,给自己一年的辛苦付出“加餐”,那咱们的课程也不例外,在新的一年里,我为你策划了两期加餐,今天先来聊聊在高并发下,我们如何发现和排查问题。
为什么要讲这个问题呢?是因为我在课程结束之后,发现有同学反馈说:
虽然课程里几乎涵盖了高并发系统设计的全部方面(比如数据库、缓存和队列的使用、分布式系统主要组件的原理,以及系统运维方面需要关注的重点),但自己按照课程中提供的方式正确使用了组件,在实际工作中仍然会发现系统中各种各样的问题,比如服务性能衰减、依赖资源的抖动甚至是服务整体故障。
尤其在高并发环境下,由于并发请求更多,对于资源和服务的压力更大,所以原本隐藏在冰山下的问题又都会在某一时间突然浮出水面。
这其实就像墨菲定律说的那样: 如果事情有变坏的可能,不管这种可能性有多小,它总会发生。这不是一个数据概率问题,也不是一个心理学效应,而是一种必然的法则。
在高并发场景下,一些细微的问题可能会迅速恶化,并且对系统中多个模块的 SLA 带来巨大的影响。比如,业务仅仅缓存的平均响应时间增加 1ms 或者缓存命中率下降 1 个百分点,都会带来灾难性的影响。这不仅增加了问题排查的难度,也对问题排查的及时性提出了更高的要求。
那么作为团队核心开发成员的你,在系统存在隐患的时候,如何快速发现问题?在出现问题的时候又要如何排查呢?接下来,我就结合课程中讲到的一些知识,通过一些实际案例,再带你深入了解一下。

如何及时发现问题

这一点我们在课程中已经有过介绍了,在我看来,主要有两个手段:监控和压测。在这期加餐中,我再用几个实际的案例强调一些你容易忽视的点。
首先,你需要格外重视客户端的监控(也就是我在31 讲中提到的监控),因为这一级的监控是最靠近用户的,也最能真实反映用户的使用体验,有时候你发现后端的监控一切正常,但其实在用户这一侧已经存在比较严重的问题了。我分享一下这几天在项目中发生的事情。
我的项目最近在做上云的迁移,在迁移到云上之后,我们会使用某公有云的外网负载均衡服务。在这个负载均衡服务上,我们购买了一定量的外网带宽包,这样就可以让内网应用和外网通信了。但是,当流量超过了这个带宽包中提供的带宽总量,就会产生丢包的现象。而在元旦节日的高峰期时,这个带宽包就达到了瓶颈,但是从服务端监控来看,所有的性能指标都显示正常,但是在客户端这边已经有用户感觉到接口响应时间缓慢了。
从客户端监控来看,在带宽被打满的那段时间里,客户端请求服务接口会有大量 504 的响应码,如果我们可以针对客户端监控做一些及时的报警,就会很容易发现这个问题了。
另一方面,压测也是一种常规的发现系统问题和隐患的手段(在课程中我也介绍了应该如何实现全链路压测系统,以及在实现中需要注意的点)。而在最近的迁移上云项目中,我也着重对云上部署的服务做了一次完善的全链路压测,在压测的过程中确实发现了很多云上服务和组件隐藏的问题,下面我就分享一个真实的案例。
在我现在维护的项目中,会重度依赖 Redis 缓存作为提升数据读取速率的手段,而在我们做全链路压测过程中,当我们的压测流量到达一定的量级,会出现访问某一个或者几个 Redis 组件时,平均响应时间有比较大波动的情况,有比较多的慢请求,影响了请求的响应时间。
发现这个问题之后,我们首先看了一下 Redis 的监控,发现在波动期间,Redis 的 CPU 使用率会有大幅度的上升,接近 100%,同时观察到 Redis 会逐出大量的 Key,所以推断逐出 Key 时会消耗大量的 CPU 时间,从而导致 CPU 负载升高。进一步通过观察监控发现,在逐出大量的 Key 之前,Redis 的连接数会有比较大的上涨。
我们和公有云维护同学讨论后确认了原因:由于我们的 Redis 内存使用率接近 100%,那么当连接数大量上涨的时候,Redis 需要逐出 Key,释放出内存资源,从而保存连接信息,那么为什么 Redis 的连接数会大涨呢? 进一步观察业务错误日志,同时排查 Redis 客户端代码之后我们发现,在连接数上涨之前,业务服务在访问 Redis 的时候会有一些慢请求,这些慢请求会导致业务认为与 Redis 的连接出现问题,会重新建立新的连接,并且异步关闭现有连接,从而导致连接会在短时间之内有大幅度的上升。
而我们通过使用 tcpdump 抓取网络包发现,在这一段时间,Redis 的响应时间确实有比较大幅度的升高。通过进一步排查 Redis 的实现逻辑我们发现,在 Redis3.0 版本中使用的 jemalloc 在释放内存时,会存在偶发的卡顿情况,会导致短时间内,访问 Redis 的所有请求全部阻塞,从而导致响应时间升高,这样我们就找到了这个问题的根本原因。
而在云厂商解决了这个问题之后,我们再次压测发现问题不再复现。你看,在这个案例中,我们正是通过全链路的压力测试发现了问题,并且压测也能够帮助我们验证优化方案是否可行。

排查问题的方法是怎样的

那么,发现了问题之后,有哪些排查问题的方法呢?
其实问题(尤其是性能问题),比较难排查的原因在于:我们通常看到的是问题的外在表象,比如,接口响应时间长了、系统的 SLA 下降了、消息队列堆积了等等,而我们想要从表象推理出根本原因就需要分析能力、归纳总结能力以及一些经验的积累了。这就好比你可以从表情和语气推断出女朋友生气了,但要花费很多的精力再加上之前的一些经验总结,才能够推断出女朋友为什么生气。
当然,监控和日志依然是我们排查问题的主要手段,大部分的问题我们都可以通过监控和日志来找到根本原因。比如我在刚刚维护现在的项目时,发现每天凌晨 2 点的时候,系统的 SLA 会有一个抖动,于是我追查系统的错误日志,发现那段时间访问 Redis 会有少量的慢请求,进一步与 DBA 确认那段时间 Redis 在做 BGSAVE,Redis Server 会有短暂时间的阻塞,这就解释了 Redis 的慢请求以及 SLA 的下降。
而有些问题需要我们做一些归纳总结,针对性地分析问题发生的一些共性特点。比如,是不是只有某几台服务器存在这个问题,或者出现问题的间隔时间是不是固定的等等。
我在之前维护一套注册中心的时候,遇到过这么一个问题: 注册中心总是在每天晚上的时候,出现大量节点被标记为不可用,并且很快又被标记可用的情况,直到过了凌晨 0 点才会恢复。
拿到这个问题之后,我首先考虑的就是,如何找到问题每次发生的共性特点,于是我查看了注册中心服务标记节点的时间,发现只有一台服务器是在标记节点不可用,并且节点被标记之后,其他的服务器又很快地将它们恢复。我们在24 讲,讲注册中心时曾经提到,注册中心是通过心跳机制来检测节点是否可用的,注册中心服务会比较上次心跳的时间,以及服务器本地时间,如果两者相差超过一定阈值,就标记服务节点不可用。
于是,我在确认了心跳时间正确的前提下,判断是服务器本地时间的问题。经过进一步排查,我们发现,标记节点不可用的注册中心服务器的系统时间是错误的,而它的系统时钟对时间隔是一天,而其它服务器是一个小时,这也解释了为什么过了凌晨之后就恢复了(时钟重新对时后系统时间就正确了)。于是我们修改了时钟对时的间隔,问题果然就不再出现了。
除了监控和日志以外,一些常见的工具也是问题排查的重要手段,当我们通过监控找不到思路的时候,我们不妨看一看系统的 CPU、内存、磁盘和网络等等是否存在错误,饱和度如何,也许可以给我们的问题排查提供一些线索。这就需要你在实际工作中不断地积累,熟悉常见工具的使用方法和场景了。
比如,我们想要查看 CPU 的负载情况,我们都知道可以使用 top 命令;而如果你是 Java 应用,你还可以结合 jstack 命令来查看 CPU 使用率比较高的线程正在执行什么操作。但这些并不够,你还可以使用 pidstat、vmstat、mpstat 来查看 CPU 的运行队列、阻塞进程数、上下文切换的数量,这些都会给你的问题排查提供线索。同时,Perf 也是一个常见的工具,可以帮助你排查哪些系统调用或者操作消耗了更多的 CPU 时间,这样你就可以有针对性地做调整和优化了。
再比如,我在面试的时候经常会问面试者如何来排查内存泄漏的问题,大部分的 Java 面试者可以回答使用 jmap 命令 dump 出内存信息,然后使用类似 MAT 的工具来分析。
这种分析方法只对 java 堆有效,如果是堆外内存的泄漏我们要如何排查呢?也许你可以使用 pmap 和 GDB 来查看堆外内存都有哪些数据,这样也可以给我们的排查提供思路。

课程小结

以上就是本节课的全部内容了。本节课我带你了解了发现和排查问题的方式和手段,这里你需要了解的几个重点是:
监控和压测是发现系统性能问题的两个最重要的手段,尤其我们不能忽略客户端监控,否则我们可能会错过一些问题;
利用监控和日志,总结出问题的共性特点,是我们排查问题的主要手段;
熟悉常见的分析工具会让我们的问题排查过程事半功倍。
问题的排查过程虽然痛苦,但是你每一次的排查经历都是在为你的下一次排查积累经验,同时也能让你更加熟悉工具的使用,慢慢地你就会发现,问题的排查关键在于你是否熟练,“无他,唯手熟尔”。

一课一思

在你开发和维护项目的过程中,你都遇到过哪些诡异的问题呢?你又是通过什么样的方法来发现和排查的呢?欢迎在留言区和我一起讨论,或者将你的实战经验分享给更多的人。
最后,感谢你的阅读,我们下期见。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 9

提建议

上一篇
结课问卷获奖用户名单
下一篇
春节特别策划 | 我们如何准备抵抗流量峰值?
 写留言

精选留言(6)

  • 每天晒白牙
    2020-01-24
    感谢老师春节更新,我在工作中排查过几次cpu占用高,频繁fgc的问题 https://mp.weixin.qq.com/s/ji_8NhN4NnEHrfAlA9X_ag https://mp.weixin.qq.com/s/IPi3xiordGh-zcSSRie6nA https://mp.weixin.qq.com/s/fWsy26VeUvb8yPKON3OTmA
    展开

    作者回复: 赞 总结很赞~

    32
  • 2020-05-10
    各种各样的业务问题排查过不少,还分门别类的整理起来写了一个问题排查手册,性能调优、网络超时、连接池超时这些问题也排查过,不过特别诡异的好像没有。 业务问题看对系统及业务的了解程度,系统问题看自己的基础知识,个人感觉日志太关键了,尤其对于不好复现的问题,公司如果基础设施好,排查问题的工具都是界面化傻瓜式操作能提高不少排查问题的效率,否则就看自己对各种工具的熟练程度了。 前几天还排查了一下使用Gosn和HikariCP的问题,Gosn是识别数据全部转换为Double在转Long会存在丢失数据精度,HikariCP的参数设置不对会出现连接不可用的问题,马上又要开始排查一下系统老报连接超时的问题了。 排查问题其实挺有意思的,尤其是大家觉得不好弄就这样吧!然后绞尽脑汁能把问题解决,即使没人点赞也很开心。
    展开
    共 3 条评论
    13
  • Lane
    2020-02-08
    遇到过几次诡异问题。 明天零晨两点,服务器报警,看监控每天都这个点,以为crontab占用资源,后来发现,这个机器ping别的机器丢包严重,换网线好了。 重启服务报端口被占用,发现ffpemg的组件ffprobe也listen端口(是被服务用exec启的ffmpeg)。 有台新机器,基本上每天有十秒钟没有请求(nginx没有access.log),换网线网卡重装系统升级了内核,就是找不到原因,dmesg也没报错。 真叫人头秃
    展开

    作者回复: 👍,经验丰富~

    3
  • helloworld
    2020-08-05
    确实是,遇到问题,解决问题是提升自己的最快的方式,并且如何在遇到问题时不恐慌耐得住性子来排查问题也是需要好好学习锻炼

    作者回复: 排查问题就是一场修行,技术和性格的双重修行。

    2
  • 小胡
    2021-09-05
    感觉提供的案例问题很好解决,比如那个服务器系统时间的问题,正常人都会想到的
  • ちよくん
    2020-01-27
    消费重复消费