性能分析小案例系列,可以通过下面链接查看哦

https://www.cnblogs.com/poloyy/category/1814570.html

前言

软中断基本原理,可参考这篇博客:https://www.cnblogs.com/poloyy/p/13435519.html

中断

  • 一种异步的事件处理机制,用来提供系统的并发处理能力
  • 当中断事件发生,会触发执行中断处理程序
  • 中断处理程序分为上半部和下半部
  • 上半部:硬中断,快速处理中断
  • 下半部:软中断,用来异步处理上半部未完成的工作

软中断

  • 每个 CPU 都对应一个软中断内核线程,名字是 ksoftirqd/CPU 编号
  • 当软中断事件的频率过高时,内核线程也会因为 CPU 使用率过高而导致软中断处理不及时,进而引发网络收发延迟,调度缓慢等性能问题

软中断频率过高案例

系统配置

Ubuntu 18.04, 2 CPU,2GB 内存,共两台虚拟机

三个工具

  • sar:是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告 历史统计数据。
  • hping3:是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙 测试等。
  • tcpdump:是一个常用的网络抓包工具,常用来分析各种网络问题

虚拟机关系

通过 docker 运行案例

在 VM1 中执行命令

docker run -itd --name=nginx -p : nginx

通过 curl 确认 Nginx 正常启动

在 VM2 中执行命令

curl http://172.20.72.58/

通过 hping3 模拟 Nginx 的客户端请求

在 VM2 中执行命令

hping3 -S -p  -i u100 172.20.72.58
  • -S:参数表示设置 TCP 协议的 SYN(同步序列号)
  • -p:表示目的端口为 80
  • -i:u100 表示每隔 100 微秒发送一个网络帧

回到 VM1

感觉系统响应明显变慢了,即便只 是在终端中敲几个回车,都得很久才能得到响应

分析系统为什么会响应变慢

以下命令均在 VM1 中执行

通过 top 命令查看系统资源使用情况

  1. 系统 CPU 使用率(用户态 us 和内核态 sy )并不高
  2. 平均负载适中,只有 2 个 R 状态的进程,无僵尸进程
  3. 但是软中断进程1号(ksoftirqd/1)的 CPU 使用率偏高,而且处理软中断的 CPU 占比已达到 94
  4. 此外,并无其他异常进程
  5. 可以猜测,软中断就是罪魁祸首

确认是什么类型的软中断

观察 /proc/softirqs 文件的内容,就能知道各种软中断类型的次数

这里的各类软中断次数,又是什么时间段里的次数呢?

  • 它是系统运行以来的累积中断次数
  • 所以直接查看文件内容,得到的只是累积中断次数,对这里的问题并没有直接参考意义
  • 中断次数的变化速率才是我们需要关注的

通过 watch 动态查看命令输出结果

因为我的机器是两核,如果直接读取 /proc/softirqs 会打印 128 核的信息,但对于我来说,只要看前面两核的信息足以,所以需要写提取关键数据

watch -d "/bin/cat /proc/softirqs | /usr/bin/awk 'NR == 1{printf \"%-15s %-15s %-15s\n\",\" \",\$1,\$2}; NR > 1{printf \"%-15s %-15s %-15s\n\",\$1,\$2,\$3}'"

结果分析

  • TIMER(定时中断)、 NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU 锁)等这几个软中断都在不停变化
  • NET_RX,就是网络数据包接收软中断变化速率最快
  • 其他几种类型的软中断,是保证 Linux 调度、时钟、临界区保护这些正常工作所必需的,所以有变化时正常的

通过 sar 查看系统的网络收发情况

上面确认了从网络接收的软中断入手,所以第一步应该要看下系统的网络接收情况

sar 的好处

  • 不仅可以观察网络收发的吞吐量(BPS,每秒收发的字节数)
  • 还可以观察网络收发的 PPS(每秒收发的网络帧数)

执行 sar 命令

sar -n DEV 

  • 第二列:IFACE 表示网卡
  • 第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数【PPS】
  • 第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数【BPS】

结果分析

对网卡 ens33 来说

  • 每秒接收的网络帧数比较大,几乎达到 8w,而发送的网络帧数较小,只有接近 4w
  • 每秒接收的千字节数只有 4611 KB,发送的千字节数更小,只有2314 KB

docker0veth04076e3

  • 数据跟 ens33 基本一致只是发送和接收相反,发送的数据较大而接收的数据较小
  • 这是 Linux 内部网桥转发导致的,暂且不用深究,只要知道这是系统把 ens33 收到的包转发给 Nginx 服务即可

异常点

  • 前面说到是网络数据包接收软中断的问题,那就重点看 ens33
  • 接收的 PPS 达到 8w,但接收的 BPS 只有 5k 不到,网络帧看起来是比较小的
  • 4611 * 1024 / 78694 = 64 字节,说明平均每个网络帧只有 60 字节,这显然是很小的网络帧,也就是常说的小包问题

灵魂拷问

如何知道这是一个什么样的网络帧,它又是从哪里发过来的呢?

通过 tcpdump 抓取网络包

已知条件

Nginx 监听在 80 端口, 它所提供的 HTTP 服务是基于 TCP 协议的

执行 tcpdump 命令

tcpdump -i ens33 -n tcp port 
  • -i ens33:只抓取 ens33 网卡
  • -n:不解析协议名和主机名
  • tcp port 80:表示只抓取 tcp 协议并且端口号为 80 的网络帧

172.20.72.59.52195 > 172.20.72.58.80

  • 表示网络帧从 172.20.72.59 的 52195 端口发 送到 172.20.72.58 的 80 端口
  • 也就是从运行 hping3 机器的 52195 端口发送网络帧, 目的为 Nginx 所在机器的 80 端口

Flags [S]

表示这是一个 SYN 包

性能分析结果

结合 sar 命令发现的 PPS 接近 4w 的现象,可以认为这就是从 172.20.72.59 这个地址发送过来的 SYN FLOOD 攻击

解决 SYN FLOOD 问题

从交换机或者硬件防火墙中封掉来源 IP,这样 SYN FLOOD 网络帧就不会发送到服务器中

后续的期待

至于 SYN FLOOD 的原理和更多解决思路在后面会讲到哦

分析的整体思路

  1. 系统出现卡顿,执行命令,响应也会变慢
  2. 通过 top 查看系统资源情况
  3. 发现 CPU 使用率(us 和 sy)均不高,平均负载适中,没有超 CPU 核数的运行状态的进程,也没有僵尸进程
  4. 但是发现处理软中断的 CPU 占比(si)较高,在进程列表也可以看到软中断进程 CPU 使用率偏高,猜测是软中断导致系统变卡顿的主要原因
  5. 通过 /proc/sorfirqs 查看软中断类型和变化频率,发现直接 cat 的话会打印 128 个核的信息,但只想要两个核的信息
  6. 所以结合 awk 进行过滤,再通过 watch 命令可以动态输出查看结果
  7. 发现有多个软中断类型在变化,重点是 NET_RX 变化频率超高,而且幅度也很大,它是网络数据包接收软中断,暂且认为它是问题根源
  8. 既然跟网络有关系,可以先通过 sar 命令查看系统网络接收和发送的整体情况
  9. 然后可以看到接收的 PPS 会比接收的 BPS 大很多,做下运算,发现网络帧会非常小,也就是常说的小包问题
  10. 接下来,通过 tcpdump 抓取 80端口的 tcp 协议网络包,会发现大量来自  VM2 发送的 SYN 包,结合 sar 命令,确认是 SYN FLOOD 攻击

性能分析(5)- 软中断导致 CPU 使用率过高的案例的更多相关文章

  1. 空循环导致CPU使用率很高

    业务背景 业务背景就是需要将多张业务表中的数据增量同步到一张大宽表中,后台系统基于这张大宽表开展业务,所以就开发了一个数据同步工具,由中间件采集binlog消息到kafka里,然后我去消费,实现增量同 ...

  2. 性能分析(4)- iowait 使用率过高案例

    性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 前言 前面两个案例讲的都是上下文切换导致的 CPU ...

  3. Oracle查询语句导致CPU使用率过高问题处理

    解决此问题的关键在于如何找到造成CPU使用率过高的SQL语句.步骤如下: 1.使用Process Explorer工具查看到Oracle进程,双击Oracle进程,在弹出的属性窗口的Threads选项 ...

  4. 代码死循环导致cpu使用率过高

    1. top命令查看进程pid  27081 2. ps -mp pid -o THREAD,tid,time  (tid:31128) 3.printf “%x\n” number  #将tid转换 ...

  5. 性能分析(1)- Java 进程导致 CPU 使用率升高,问题怎么定位?

    性能分析小案例系列,可以通过下面链接查看哦 ps:这些分析小案例不能保证百分比正确,是博主学习过程中的总结,仅做参考 前提 本机有一个很占用 CPU 的项目,放在了 Tomcat 下启动着 如何定位 ...

  6. 性能分析(3)- 短时进程导致用户 CPU 使用率过高案例

    性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 系统架构背景 VM1:用作 Web 服务器,来模拟 ...

  7. 性能分析(2)- 应用程序 CPU 使用率过高案例

    性能分析小案例系列,可以通过下面链接查看哦 https://www.cnblogs.com/poloyy/category/1814570.html 系统架构背景 其中一台用作 Web 服务器,来模拟 ...

  8. epoll 性能分析(解决占用CPU 过高问题)

    针对自己写的一个服务器网络引擎Engine 文章后面附上源码 使用epoll  刚刚开始时候发现占用CPU 特别高,但是网络引擎里面基本没干什么事,不应该有这么高的CPU,一直不解, 于是自己慢慢的分 ...

  9. 性能测试分析过程(二)cpu 使用率过高的分析方法

    Linux 系统下 cpu 使用率过高的分析方法 1.通过 top 命令可以很明显查看出哪个进程耗cpu比较高 2. ps -mp 25147-o THREAD,tid,time\top -Hp pi ...

随机推荐

  1. Java中多线程的使用(超级超级详细)线程安全原理解析 4

    Java中多线程的使用(超级超级详细)线程安全 4 什么是线程安全? 有多个线程在同时运行,这些线程可能会运行相同的代码,程序运行的每次结果和单线程运行的结果是一样的,而且其他变量的值也和预期的值一样 ...

  2. Python Hacking Tools - Web Scraper

    Preparation: Python Libray in the following programming: 1. Requests Document: https://2.python-requ ...

  3. 关于ES6的let和const

    变量 var存在的问题 可以重复声明 无法限制修改 没有块级作用域 (在全局范围内有效) 存在变量提升 const/let 不可以重复声明 let a = 1; let a = 2; var b = ...

  4. C++头文件居然可以这么打!!!! 长见识了!!!

    返回主页 longdie 这人,生于天,立于地,为的就是顶天立地. 未来的答案早已被宇宙计算好了,人类自出现,答案就在那里,人类灭亡了,答案也在那里,,但是人活着,不就是为了看看未来发生了什么吗?如果 ...

  5. 路径总和(leetcode 113)

    题目描述如下所示: 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径.(https://leetcode-cn.com/problems/path-sum-ii/) ...

  6. Spring Boot 集成 WebSocket 实现服务端推送消息到客户端

    假设有这样一个场景:服务端的资源经常在更新,客户端需要尽量及时地了解到这些更新发生后展示给用户,如果是 HTTP 1.1,通常会开启 ajax 请求询问服务端是否有更新,通过定时器反复轮询服务端响应的 ...

  7. setTimeout、clearTimeout、setInterval

    setTimeout(cb, ms) setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb).:setTimeout() 只执行一次指定函数. 返回一个代表定时器的 ...

  8. 解决SyntaxError: Non-UTF-8 code starting with '\xbb'问题

    在第一行加入 # coding=utf-8 2020-06-13

  9. Python while 中简单的语句组

    Python while 中简单的语句组: 只使用 while: # 简单的语句组 a = 4 b = 8 num = 0 while a < b: print("a 比 b 小&qu ...

  10. PHP bin2hex() 函数

    实例 把 "Hello World!" 转换为十六进制值: <?php 高佣联盟 www.cgewang.com$str = bin2hex("Hello Worl ...