• 微信
    咨询
    微信在线咨询 服务时间:9:00-18:00
    纵横数据官方微信 使用微信扫一扫
    马上在线沟通
  • 业务
    咨询

    QQ在线咨询 服务时间:9:00-18:00

    选择下列产品马上在线沟通

    纵横售前-老古
    QQ:519082853 售前电话:18950029581
    纵横售前-江夏
    QQ:576791973 售前电话:19906048602
    纵横售前-小李
    QQ:3494196421 售前电话:19906048601
    纵横售前-小智
    QQ:2732502176 售前电话:17750597339
    纵横售前-燕子
    QQ:609863413 售前电话:17750597993
    纵横值班售后
    QQ:407474592 售后电话:18950029502
    纵横财务
    QQ:568149701 售后电话:18965139141

    售前咨询热线:

    400-188-6560

    业务姚经理:18950029581

  • 关注

    关于纵横数据 更多优惠活动等您来拿!
    纵横数据官方微信 扫一扫关注官方微信
  • 关闭
  • 顶部
  • 您所在的位置 : 首页 > 新闻公告 > 云服务器性能异常分析?从“突然变慢”到“揪出元凶”的完整思路

    云服务器性能异常分析?从“突然变慢”到“揪出元凶”的完整思路

    你有没有遇到过这样的情况?云服务器上的应用平时跑得好好的,响应时间也就几十毫秒,突然有一天,点个按钮要等好几秒,甚至十几秒。用户开始在群里抱怨,老板在旁边盯着你看,可你登录服务器一看,CPU好像也不高,内存也够,磁盘也没满。这时候心里就开始犯嘀咕了:到底哪里出了问题?这就是典型的云服务器性能异常——不是彻底不能用,而是“变慢了”,慢得不正常,慢得让人抓狂。

    性能异常比宕机更折磨人。宕机了,你知道它在哪儿断了,修就是了。但性能异常像是慢性病,一会儿快一会儿慢,有时候重启一下就好了,过几天又犯。我在这个领域摸爬滚打了好几年,总结出了一些分析性能异常的心得。今天就把这些心得掰开揉碎了讲给你听,希望能帮你从“感觉慢”变成“知道为什么慢”。

    先说说我经历过的一个典型案例,这个案例几乎涵盖了我今天要讲的大部分要点。

    去年秋天,一家在线教育公司的技术负责人找到我,说他们的直播预约系统每天下午三点到五点这段时间,响应时间从平时的两百毫秒飙升到四五秒,有时候甚至超过十秒。他们已经排查了一个星期,升级了配置,加了缓存,甚至重写了部分代码,但问题依旧。我接手之后,没有急着看代码,而是先问他们要了这几天的性能监控数据。看了之后发现,CPU和内存使用率在这段时间确实有上升,但远没到瓶颈。磁盘IO也很平稳。网络流量也没有激增。一切都似乎很正常,但响应就是慢。

    我决定自己进行压力测试,在下午三点到四点这个时间段,用一台测试机模拟少量用户访问,同时在这台云主机上运行一系列性能采集工具。我发现一个非常微妙的规律:当响应时间变慢的时候,系统的平均负载数值明显高于CPU核心数,但CPU的使用率却不高。这是一个典型的“IO等待”特征——很多进程在排队等某个资源,但这个资源不是CPU,而是磁盘或者锁。接着我用iostat命令观察磁盘,发现磁盘的每秒读写次数和吞吐量都不高,但每次IO的平均等待时间却长达几十毫秒,正常应该是个位数毫秒。这就有意思了,磁盘看起来不忙,但响应很慢。

    进一步排查,我注意到系统里有一个定时任务,每天下午三点整会执行一次数据库的统计信息收集。这个任务会全表扫描一个上亿条记录的大表,扫描过程中会产生大量离散的磁盘读操作。虽然整体IO量不大,但这些读操作会频繁地抢占磁盘的磁头或者SSD的队列,导致其他正常的读写请求被延迟。就好比一条高速公路,车流量不算大,但每隔几秒钟就有一辆重型卡车从匝道并入,把后面的小车全部堵住几秒钟。从平均流量看路不堵,但从每一辆车的时间看,它确实被堵了。

    找到原因之后,解决方案就很明确了。把这个统计任务的执行时间改到凌晨业务低谷期,并且用采样方式代替全表扫描。第二天下午三点,预约系统的响应时间曲线变成了一条直线,再也没有起伏。这个案例给我的启发非常大,它让我明白,性能异常分析不能只看平均值,要看延迟分布,要看资源之间的微妙关系。

    好了,说完这个有代表性的案例,我把分析性能异常的系统性方法梳理一下。

    第一步,搞清楚“异常”的具体表现是什么。

    很多人描述性能问题就说一句“服务器很慢”。这对排查来说信息量几乎为零。“慢”可以有很多种:是所有的请求都慢,还是只有某些特定功能慢?是从某一个时间点之后一直慢,还是间歇性慢?是响应慢但是CPU低,还是响应慢的同时CPU也高?这些细节直接决定了你要往哪个方向去查。我通常会要求提问者回答几个问题:慢的时候,服务器的平均负载是多少?CPU使用率是用户态高还是系统态高?内存有没有出现大量的swap?磁盘的await和util指标高不高?网络的重传率有没有上升?如果你连这些都不知道,那就先打开监控系统,把图表调出来看。

    第二步,建立性能的“基线”。

    没有基线,你就不知道什么是“异常”。很多性能问题其实是业务增长后的正常现象,只是因为你的感知停留在过去。所以,在一台云服务器正常运行的时候,建议你记录下它的典型性能指标:高峰期的CPU范围、平均响应时间、磁盘IOPS、网络吞吐量等等。你可以用云服务商自带的监控来保存这些历史数据,也可以自己搭建Prometheus之类的监控系统。有了基线,当有人说“慢了”,你就能立刻对比出到底是哪里偏离了基线。比如平时CPU峰值百分之四十,现在百分之七十,虽然还没到百分之百,但确实翻倍了,那就要查是什么导致CPU翻倍。

    第三步,使用“USE”方法进行快速筛查。

    Netflix的工程师曾经提出过一个很经典的USE方法,就是针对每一种资源检查三个指标:使用率、饱和度、错误。对于CPU,看使用率和运行队列长度也就是饱和度;对于内存,看使用率和swap交换量以及OOM事件;对于磁盘,看使用率、IO等待队列、读写错误;对于网络,看带宽使用率、丢包重传率、连接跟踪表饱和度。这个方法的好处是系统全面,不会遗漏重要维度。

    我记得有一个金融公司的交易系统,每天开盘后半小时就会变得异常缓慢。他们之前只盯着CPU和内存,发现都只有百分之三四十,觉得很正常。我按照USE方法逐个检查。检查到网络的时候,发现网络接口的重传率飙升到了百分之五,正常应该低于万分之五。再看丢包,发现云主机每秒会丢掉几百个数据包。原来是他们最近为了节省成本,把多台服务合并到了同一台云主机上,内部通信的流量太大,触发了云平台对这块虚拟网卡的限速策略。后来他们优化了服务之间的通信频率,把一些不必要的广播消息去掉了,重传率降到了正常值,性能也恢复了。如果没有检查重传率这个指标,这个问题可能会一直隐藏下去。

    第四步,善用“top”之外的命令行工具。

    很多人排查性能问题就知道敲一个top,看看谁占CPU高。但top能看到的信息太有限了。我推荐几个非常实用的工具。htop是top的增强版,可以横向显示CPU每个核心的使用率,还能用鼠标点选进程查看详细信息。vmstat可以看系统的进程、内存、swap、IO、系统中断和CPU的完整情况,每几秒输出一行,能直观地看到趋势。iostat专门看磁盘,重点看%util和await两个指标,%util接近百分之百说明磁盘忙不过来了,await异常高说明磁盘响应慢可能存在坏道或者争抢。iftop或者nethogs可以看实时网络流量,按IP或者按进程排序,哪个进程在狂收狂发数据一目了然。perf是一个更高级的性能分析工具,可以采样CPU上正在执行的函数,生成火焰图,当你完全找不到头绪的时候,火焰图往往能给你惊喜。

    还有一个工具叫strace,它可以跟踪进程的系统调用。有一次一个应用突然变得特别慢,CPU和内存都正常,我用strace跟踪了它的主进程,发现它每处理一个请求都要调用一次gettimeofday,本来这没什么,但这个调用被循环了几万次,因为代码里有一个非常低效的时间戳生成逻辑。把这个循环改成一次调用之后,性能提升了上百倍。strace在分析这类“不知道为什么慢”的问题时,非常有效。

    第五步,区分是计算密集型瓶颈还是IO密集型瓶颈。

    这是性能分析里最基本的分类。计算密集型瓶颈的特征是CPU使用率很高,运行队列很长,但是磁盘和网络都很空闲。这种问题通常出在算法效率低下、死循环、或者业务量超过了CPU的承载能力。IO密集型瓶颈的特征是CPU使用率不高,但大量的进程处于睡眠状态,平均负载可能很高,磁盘或者网络的饱和度指标亮红灯。这种问题通常出在慢查询、无缓存的磁盘读写、同步IO、网络拥塞等方面。

    举个例子,一个图片处理服务,原图上传后需要进行缩放和水印添加。如果这个处理过程是同步的,而且没有做任何优化,高并发的时候CPU就会爆满,请求大量排队,这就是计算密集型瓶颈。解决思路包括增加处理进程数量、使用更高效的图像库、或者将同步处理改成异步消息队列。反过来,如果一个日志分析服务,每次查询都要扫描几十GB的日志文件,磁盘IO就会成为瓶颈,CPU反而很闲。解决思路包括建立索引、使用列式存储、或者把频繁查询的数据预热到内存中。分清楚你的系统到底是哪种类型,解决方案才能对症下药。

    第六步,分析和优化慢查询和慢请求。

    对于Web服务和数据库服务,很多性能异常都源自某几个“慢”的请求。这些请求平时调用量很小,不影响整体,但一旦调用量上来,或者它们自己变慢了,就会拖垮整个系统。所以,分析性能异常的时候,一定要拉出来一份“最慢请求”的排行榜。对于Web服务器,可以在Nginx或者Apache的日志里记录请求耗时,然后通过分析日志找出那些平均响应时间最长的URL。对于数据库,打开慢查询日志,设置一个阈值比如两秒,记录所有超过两秒的SQL语句,然后分析它们的执行计划,加上合适的索引,或者改写查询语句。

    有一个真实的电商案例。他们的订单导出功能,每次导出一万条订单,SQL语句里用了四个LEFT JOIN,而且关联的表中有一个没有索引。平时一天只有几次导出,没什么感觉。但有一天运营人员导了上百次,数据库的CPU飙升到了百分之九十以上,影响到所有用户的正常下单。慢查询日志里清清楚楚地记录了这些导出查询的执行时间,都在十几秒到几十秒。DBA通过EXPLAIN分析发现了一个全表扫描,加上索引之后,同样的查询从十几秒降到了零点几秒。这就是慢查询优化的价值。

    第七步,关注锁和并发争用。

    多线程或者多进程的系统里,锁竞争是很常见的性能杀手。有时候你的CPU不高,磁盘不忙,但响应就是慢,因为所有请求都在排队等同一把锁。比如PHP的session文件锁,如果多个请求同时访问同一个用户的session,后边的请求必须等前一个请求释放文件锁才能继续。在高并发下,这会导致请求大量积压。解决办法是使用更快的session存储后端,比如Redis,或者调整代码逻辑,读写session的时机尽量靠后或者提前释放。

    Java应用里,可以用jstack命令打印线程堆栈,看看哪些线程处于BLOCKED状态,它们在等待哪把锁。我曾经碰到过一个Java服务,平时性能很好,某次发版后变得非常慢。用jstack一看,几十个线程全部阻塞在一个同步方法上,原来是一个开发人员把一个原本是实例变量的锁对象改成了静态变量,导致所有线程共享同一把锁,彻底失去了并发能力。改回去之后,性能恢复正常。这类锁问题非常隐蔽,但通过线程堆栈分析就能快速定位。

    第八步,利用云监控的历史数据和告警。

    云服务商提供的监控系统通常会保留几个月甚至一年的历史性能数据。当你发现性能异常时,可以回溯去看这个异常是从什么时间开始的。结合那个时间点附近的操作记录,比如代码发布记录、配置变更记录、云主机迁移记录、安全组变更等,往往能精准定位到引发问题的变更。这一点我深有体会,很多时候性能问题的根源就是“上次改动了一个东西”。如果你能把这个“东西”找出来,问题就解决了一半。

    一个典型的例子是,某公司运维人员在下午两点修改了内核参数net.ipv4.tcp_tw_reuse和tcp_tw_recycle,结果下午三点开始,大量用户的请求出现随机超时。他们在云监控上看到TCP连接建立的成功率大幅下降,时间点正好是配置修改之后。回滚了内核参数,问题立刻消失。如果没有监控数据,他们可能还在纠结代码是不是有bug。

    第九步,不要忽视“邻居干扰”。

    云服务器是运行在共享物理硬件上的,虽然虚拟化技术做了隔离,但某些资源依然存在“吵闹邻居”的问题,尤其是磁盘IO和网络带宽。如果你使用的是共享型实例,和你同在一台物理机上的其他云主机可能会抢占IO资源,导致你的磁盘延迟忽高忽低。这种现象表现为:同一台云主机,有时候响应很快,有时候很慢,而且没有明显的规律。怎么确认是不是邻居干扰?你可以做一个简单的测试,在业务低谷期,连续运行一个简单的读磁盘的测试,看延迟是否有大幅波动。如果确认是这个问题,可以考虑升级到有资源保障的实例类型,这类实例会给你分配固定的资源配额,不受邻居影响。

    还有一个相关的案例。一个做视频转码的团队,每次转码任务开始时性能正常,运行十分钟后突然变慢。他们检查了自己的CPU和内存,发现都没有打满。后来他们联系云服务商支持,对方检查了物理主机的负载情况,发现另一台同样是转码任务的云主机占用了大量的L3缓存,导致他们的CPU频繁缓存未命中,性能下降。云服务商帮他们迁移到了另一台负载较低的物理机上,问题解决。这也提醒我们,有时候问题不在你服务器内部,而在你看不到的外部。

    第十步,做好持续的性能测试和容量规划。

    最好的性能异常分析,是在异常发生之前就发现问题。这就需要有持续的性能测试和容量规划。你可以定期用压力测试工具比如JMeter或者wrk,给云主机施加一定量的压力,观察性能指标是否在预期范围内。当发现某些指标接近阈值时,提前进行优化或者扩容,不要让异常真的影响到用户。同时,要建立一套容量模型,知道你的云主机每秒能处理多少请求,最大支持多少在线用户,随着业务的增长,什么时候需要增加配置或者拆分服务。

    我认识一个创业公司的CTO,他们每个月底都会做一次“全链路压测”。在一次压测中,他们发现当并发量达到某个值的时候,响应时间会突然从200毫秒飙升到3秒。通过分析,原来是Redis的连接数达到了默认的最大客户端数。他们提前调整了Redis的最大连接数配置,并且优化了应用代码里不释放连接的问题。在接下来的双十一活动中,系统平稳度过,而没有经历过这个压测的竞争对手却出现了服务不可用。这就是持续性能测试的价值所在。

    总结一下,云服务器性能异常分析,本质上是一个排除法加上证据链的过程。你需要有一套清晰的思路:从明确异常表现开始,对照性能基线,然后按照USE方法逐个检查CPU、内存、磁盘、网络等资源。用top、vmstat、iostat、iftop等工具获取实时数据,用慢查询日志、线程堆栈、系统调用跟踪等高级手段定位深度问题。同时不要忘记查看云监控的历史数据,结合变更记录找出时间上的关联。处理完问题之后,把整个过程记录下来,形成知识库,并且建立持续的性能测试和容量规划机制,让异常越来越少,直到消失。

    每一次性能异常,其实都是一次深入理解你的系统和业务的机会。你可能会因为一个慢SQL的优化而学会执行计划分析,因为一次锁排查而深入掌握并发编程的细节,因为一次邻居干扰而搞清楚虚拟化的工作原理。这些积累,会让你的技术能力在日常的“救火”中悄然成长。希望这篇文章里的方法和案例,能成为你面对性能异常时的一根拐杖,支撑你稳稳地走过每一次排查和分析。



    最新推荐


    微信公众帐号
    关注我们的微信