服务器突然变得卡顿,怎么办?(1)综述
本文章系列未来计划持续更新,把我在学习/实习/工作中遇到的相关实际案例记录在这里
系列目录:
- 综述:本文章
- Java GC 导致的卡顿:https://alrisha.cn/2024/04/bd9408a6.html
这是一道经典的面试场景题,但也可以说是实际开发过程中最经常遇到的问题之一。实际上,这个问题问的是当服务器出现不可用情况时,应当如何快速排查、定位问题并解决问题。
可能的卡顿原因
对于卡顿原因,一般来说可以从以下几个大方考虑:
CPU : 当 CPU 占用过高时,服务器自然会发生卡顿。
- CPU 密集型任务 :如果运行的服务是 CPU 密集型的任务,那么 CPU 资源占用是不可避免的,此时为了确保服务器自身的可用性,可以对这个 CPU 密集型任务做一定的 CPU 资源隔离(限制核数、限制抢占的时间片等)
- 并发竞争 :如果发生比较严重的多线程竞争行为,线程频繁切换上下文也会导致 CPU 占用过高
- 持续占用 :忙等待、死循环、JVM Full GC 等操作,会导致线程长时间占用并浪费 CPU 资源,具体也体现为 CPU 占用过高
- 恶意软件 :(小概率)
- 硬件问题 :(如过热降频,小概率)
内存 : 内存占用过高也会产生卡顿
- 内存泄漏 :这是最常见的原因。当程序的代码中存在错误,使得它无法释放不再使用的内存时,就会发生内存泄漏。随着时间的推移,这些未释放的内存会越来越多,最终可能耗尽所有的内存。
- 缓存占用 :有些程序会使用内存作为缓存,以提高数据访问的速度。如果缓存的大小没有得到有效的控制,可能会占用大量的内存。
- 大数据量处理 :如果程序需要处理大量的数据,例如大型数据库操作、大文件读写等,可能会占用大量的内存。
- 多进程或多线程 :每个进程或线程都会占用一定的内存。如果启动了大量的进程或线程,可能会占用大量的内存。
- 恶意软件 :(小概率)
网络 : 网络问题也会使得服务器出现卡顿
- 网络带宽不足 :如果服务器的网络带宽不足,无法满足应用的需求,那么可能会导致服务器响应变慢,甚至出现卡顿。
- 网络延迟高 :如果服务器与客户端之间的网络延迟(latency)过高,那么客户端可能会感觉到服务器响应慢,这也可能被误认为是服务器卡顿。
- 网络丢包 :如果网络中出现丢包,那么 TCP 协议会尝试重新发送丢失的数据包,这会增加网络延迟,降低网络吞吐量,可能导致服务器卡顿。
- 网络攻击 :例如 DDoS 攻击(分布式拒绝服务攻击)可能会消耗大量的网络带宽,导致正常的网络请求无法得到响应,从而使服务器卡顿。
- 网络设备故障 :例如路由器、交换机等网络设备的故障,也可能导致网络连接不稳定,从而影响服务器的性能(请注意,在网络问题中,设备故障 往往不是 小概率事件)。
其它 :
- 应用业务链路上的问题也会导致服务器卡顿,例如数据库慢查询、全表扫描/索引未命中等
- 硬件设备的问题,如磁盘 I/O 瓶颈、磁盘空间不足,但这些情况有时无法通过软件手段解决
- …
案例:Java 线程阻塞导致的高 CPU 占用
示例代码如下:
1 | import java.util.concurrent.CountDownLatch; |
在该示例代码中,三个等待线程将永远不会被唤醒,因为工作线程一直在死循环中。这会导致 CPU 占用过高,从而使得服务器出现卡顿。
定位问题
当服务器卡顿时,首先通过 top
指令查看高 CPU 占用的进程
1 | top - 16:10:59 up 2:15, 0 users, load average: 1.10, 1.03, 1.01 |
此时,进程 10136
占用的最多的 CPU 资源。
接下来,通过 top -H -p 10136
查看该进程的线程情况。其中,-H
参数表示显示线程信息,-p
参数表示指定进程号。
1 | top - 16:13:13 up 2:17, 0 users, load average: 1.02, 1.02, 1.00 |
注意此时 top
显示的 进程号 实际上代表的是 线程 ID ,因此可以看到 Thread-0
占用了大量的 CPU 资源,其线程号为 10155
,16 进制表示为 0x27ab
。
接下来,通过 jstack
命令查看线程 10155
的堆栈,然后找到线程 10155
有关的前 10 行堆栈信息。
1 | jstack 10136 | grep -A 10 0x27ab |
如果希望把全部堆栈信息输入一个 log 文件,可以使用
jstack 10136 > jstack.log
命令。
终端输出如下:
1 | alrisha@Aquarius:~$ jstack 10136 | grep -A 10 0x27ab |
可以看到,在示例代码的第 20 行,Thread-0
正在执行一个死循环。至此,定位完毕。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Alrisha!