找回密码
 立即注册
首页 业界区 业界 记一次SSD性能瓶颈排查之路——寿命与性能之间的取舍 ...

记一次SSD性能瓶颈排查之路——寿命与性能之间的取舍

羊舌正清 3 天前
1. 背景

 我就职于一家轨道交通行业公司,负责的产品之一是日志记录板卡配套软件。有一天接到了现场报告,记录软件出现通信异常,将日志数据拉回来以后,发现出现异常时,CPU使用率接近100%,记录相关软件的CPU分配被大幅降低,这说明Linux系统在CPU的调度上,就没有正常将应用软件调度执行。
 记录软件是一个时间敏感型软件。当记录软件运行超时或者没有被正常调度时,就无法记录整个子系统的运行日志,造成了整个系统的可用性降低的问题。
2. 结论

 记录板的 CPU 性能瓶颈本质是 SSD 垃圾回收机制与高 I/O 负载的冲突。通过定时执行trim命令,主动进行垃圾回收操作,可以有效解决高IO负载的问题。
 主动垃圾回收操作,会同时带来SSD寿命降低的负面影响。受到SSD的物理特性影响,过多的垃圾回收操作,会增加硬盘擦写次数,当SSD的擦写次数达到上限时,就会导致硬盘物理损坏。需要评估寿命与IO性能之间的关系,选取合适的trim间隔,在不影响性能的前提下延长SSD使用寿命,降低使用成本。
3. 排查之路

 记录板的CPU是ARM的,性能不高,只有1500Mhz左右,板卡上跑着一个精简板的linux系统。为了最大化利用CPU性能,把资源让给应用,所有很多功能都被裁剪掉了,属于是要啥没啥的状态。所以只能从零开始编译相关的软件用于分析。
3.1 工具准备

3.1.1 sysstat工具准备

 本次用到的工具是sysytat,该工具是 Linux 系统中的常用工具包。它的主要用途是观察服务负载,比如CPU和内存的占用率、网络的使用率以及磁盘写入和读取速度等。

  • sysstat的下载页面是:https://sysstat.github.io/
  • 本次使用的版本是:sysstat-12.7.5
  • 编译环境:Ubuntu 22.04.2 LTS(GNU/Linux 6.2.0-26-generic x86_64)
  • 交叉编译工具链:arm-linux-gnueabihf
 下载完成以后开始解压和配置:
  1. #解压
  2. xz -d sysstat-12.7.5.tar.xz
  3. tar xvvf sysstat-12.7.5.tar
  4. #进入解压后的目录
  5. cd sysstat-12.7.5/
  6. #临时使用CC为交叉编译工具链的GCC
  7. export CC=arm-linux-gnueabihf-gcc
  8. #开始进行编译前的配置工作,使用CFLAGS=-static生成单个文件,不需要依赖库文件。
  9. ./configure --host=armv7-linux-gnueabihf CFLAGS=-static
复制代码
 执行命令以后,信息如下:
  1.    Sysstat version:             12.7.5
  2.    Installation prefix:         /usr/local
  3.    rc directory:                /etc
  4.    Init directory:              /etc/init.d
  5.    Systemd unit dir:
  6.    Systemd sleep dir:
  7.    Configuration file:          /etc/sysconfig/sysstat
  8.    Man pages directory:         ${datarootdir}/man
  9.    Compiler:                    arm-linux-gnueabihf-gcc
  10.    Compiler flags:              -static
  11.    Linker flags:
复制代码
 使用make命令即可完成编译。
  1. make
复制代码
 编译完成以后,可以查看生成了哪些文件:
  1. find . -maxdepth 1 -type f -executable
复制代码
结果如下:
  1. $ find . -maxdepth 1 -type f -executable
  2. ./mpstat
  3. ./sa2
  4. ./sa1
  5. ./sadc
  6. ./config.status
  7. ./iostat
  8. ./iconfig
  9. ./configure
  10. ./tapestat
  11. ./sysstat
  12. ./sadf
  13. ./sar
  14. ./cifsiostat
  15. ./pidstat
  16. ./do_test
复制代码
3.1.2 perf工具准备

 对于perf工具而言,这个工具依赖特定版本的linux源码。我们使用的linux内核版本是4.9.69,所以就需要下载这个版本的源代码。
https://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.9.69.tar.gz
 下载完成以后,就需要解压编译了。
  1. #解压源代码
  2. tar -zxvf linux-4.9.69.tar.gz
  3. #进入目录
  4. cd linux-4.9.69/tools/perf/
  5. #指定架构为arm, 指定交叉编译链,并进行编译
  6. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
  7. #编译完成以后,查看文件类型
  8. file perf
复制代码
 执行file命令以后,可以获取以下信息:
  1. perf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=0ded60dc28cea83b24d83bfb6414da6d082741eb, with debug_info, not stripped
复制代码
 为了查看需要的动态库,执行以下命令:
  1. objdump -p perf | grep NEEDED
复制代码
 其结果如下:
  1.   NEEDED               libpthread.so.0
  2.   NEEDED               librt.so.1
  3.   NEEDED               libm.so.6
  4.   NEEDED               libdl.so.2
  5.   NEEDED               libgcc_s.so.1
  6.   NEEDED               libc.so.6
  7.   NEEDED               ld-linux-armhf.so.3
复制代码
 一般来说,这些库在linux系统内就有,一般不会缺。缺的话,就需要自行去网上找源码进行编译了;
3.2 排查过程

 为了检测CPU波动,使用top命令在后台输出带时间戳的数据:
  1. top -b  | busybox awk 'NR { printf  "%s %s\n",  strftime(), $0 ; fflush(stdout) }' > toplog.txt &
复制代码
1.png

 从产品的运行监测日志中看到,出现了CPU异常升高的情况
2.png

 检查对应时间段的TOP信息,发现此时等待IO完成的时间占比异常升高,即可推断IO设备是引发CPU异常升高的问题点:
3.png

 使用iostat检查对IO设备持续监控:
  1. ./iostat 2 -d /dev/sda -t -x -k -c > iolog.txt &
复制代码
4.png

 继续分析设备的信息,其中

  • r/s: 每秒完成的读次数
  • rkB/s: 每秒读数据量(kB为单位)
  • rrqm/s:  每秒进行 merge 的读操作数目.即 delta(rmerge)/s
  • wrqm/s: 每秒进行 merge 的写操作数目.即 delta(wmerge)/s
  • w/s: 每秒完成的写次数
  • wkB/s: 每秒写数据量(kB为单位)
  • avgrq-sz:平均每次IO操作的数据量(扇区数为单位)
  • avgqu-sz: 平均等待处理的IO请求队列长度
  • await: 平均每次IO请求等待时间(包括等待时间和处理时间,毫秒为单位)
  • svctm: 平均每次IO请求的处理时间(毫秒为单位)
  • %util: 采用周期内用于IO操作的时间比率,即IO队列非空的时间比率,即一秒中有百分之多少的时间用于 I/O
  1. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  2. sda              0.00      0.00     0.00   0.00    0.00     0.00    3.00     26.00     3.50  53.85    1.67     8.67    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
  3. sda              0.00      0.00     0.00   0.00    0.00     0.00    3.00     32.00     4.50  60.00    1.67    10.67    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
  4. sda              2.00      8.00     0.00   0.00   75.00     4.00   25.00   5118.00    34.00  57.63  282.20   204.72    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   23.46  87.50
  5. sda              0.50      2.00     0.00   0.00  420.00     4.00   18.00   5122.00     8.00  30.77 1806.94   284.56    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   17.86 100.00
  6. sda              0.00      0.00     0.00   0.00    0.00     0.00   13.00   4794.00    24.00  64.86 1046.54   368.77    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   15.28 100.00
  7. sda              0.00      0.00     0.00   0.00    0.00     0.00    6.50    872.00     4.50  40.91  507.69   134.15    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.24  12.50
  8. sda              0.00      0.00     0.00   0.00    0.00     0.00    4.50     36.00     4.50  50.00    1.11     8.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
复制代码
3.2.1 推测:数据量过大

 为了确认是否是因日志量过大导致的硬盘IO瓶颈,在记录板中增加获取到的数据日志大小,以及其数据的间隔时间。
5.png
  1. 01/01/70 00:25:39
  2. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  3. sda              0.00      0.00     0.00   0.00    0.00     0.00    4.50     36.00     4.50  50.00    1.11     8.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
  4. sda              0.00      0.00     0.00   0.00    0.00     0.00    6.00     50.00     6.00  50.00    0.83     8.33    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
  5. sda              0.00      0.00     0.00   0.00    0.00     0.00    4.50     38.00     5.00  52.63    1.11     8.44    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.01   0.50
  6. sda              1.00      4.00     0.00   0.00   60.00     4.00    5.50   1296.00     2.50  31.25  101.82   235.64    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    3.01  28.00
  7. sda              3.00     12.00     0.00   0.00  161.67     4.00   15.50   5036.00    21.00  57.53  844.19   324.90    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   16.16 100.00
  8. sda              0.00      0.00     0.00   0.00    0.00     0.00    7.00    936.00     3.50  33.33  797.14   133.71    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.59  19.50
  9. sda              0.50      2.00     0.00   0.00  130.00     4.00    7.00    556.00     5.00  41.67   15.00    79.43    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.56  12.50
  10. sda              2.00      8.00     0.00   0.00  130.00     4.00   14.00   4960.00    14.50  50.88  792.50   354.29    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   21.40 100.00
  11. sda              0.00      0.00     0.00   0.00    0.00     0.00   14.50   2366.00     6.00  29.27  958.28   163.17    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    3.45  48.00
  12. sda              0.00      0.00     0.00   0.00    0.00     0.00    5.00     52.00     4.00  44.44    7.00    10.40    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.04   3.50
  13. sda              0.00      0.00     0.00   0.00    0.00     0.00    4.00     36.00     4.50  52.94    2.50     9.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.04   3.50
  14. sda              0.00      0.00     0.00   0.00    0.00     0.00    5.00     34.00     4.00  44.44   11.00     6.80    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.03   3.00
复制代码
6.png

 从数据看,日志收取的大小、间隔稳定,不存在跳变情况。写入到硬盘的数据的等待耗时增加,设备带宽利用率跃至100%。
7.png

 根据以上数据,可以分析出日志记录量不是导致CPU飙升的原因。
3.2.2 推测:硬盘剩余空间不足

 记录板的板卡硬盘空间不是很大,也就58G。但是和普通的消费级SSD不一样的是,工业级的SSD对数据的完整性、安全性、硬盘可靠性等数据要求较高。
 软件内部维持了一个逻辑,保证硬盘剩余2G的空间。软件会不断的删除历史日志,保证硬盘空间足够。
 为了检验是否是因为磁盘剩余空间大小的原因导致CPU异常升高,记录板目前默认保持2G剩余空间,现调整至保持8G剩余空间,再对记录板进行观察。
 此时回过头来看,其实这个调整是有益的,原因是在进行垃圾回收的时候,需要有足够多的空间进行搬运。
 从日志记录看,发生90%占比的概率明显下降,但是依旧存在异常升高的情况。
8.png

 从top上看,此时IO确实存在瓶颈。
9.png

 从iostat上看,此时确实存在IO耗时过长的问题。
10.png

 持续运行72小时观察,对于相同环境下,分别使用2GB与8GB的调整值,对比如下:
比较项目50G56G日志时长72小时72小时CPU在60%以上总数88次104次CPU在60-69之间的次数5657CPU在70-79之间的次数926CPU在80-89之间的次数1612CPU在90-100之间的次数79每小时CPU在60-69之间平均次数0.780.79每小时CPU在70-79之间平均次数0.130.36每小时CPU在80-89之间平均次数0.220.17每小时CPU在90-100之间平均次数0.100.13 根据以上日志,不能否认磁盘空间大小与CPU使用率之间存在必然的关系,从运行日志看,CPU使用率升高的频率确实降低了。
3.2.3 推测:Linux系统缓存同步时机不合适

 根据运行日志,排查CPU异常升高时系统缓冲区是否在同步写入文件。
11.png

12.png

 从日志上看,系统的buff也在增长过程,没有写入文件,无法得出buff和CPU升高存在必然关系。
3.2.4 推测:缓存清理存在异常

 记录板会向kernel发送清理cache 的信息,清理cache可能会对IO造成影响。
 停止清理cache以后,对记录板进行监测,从2月15日0点开始,至2月17日20点结束,监测了68小时。
13.png

14.png

 从数据统计分析看,无论是否停止清理cache,其中的差别不大,不能直接确定是cache的影响。
3.2.5 推测:文件查找过程存在高耗时行为

 记录板在进行日志清理的时候,使用了find命令对系统磁盘进行查询,这个过程可能较为耗时,需要测试find命令对系统的影响。
 将记录板硬盘空间清理到35G左右,保证日志记录过程不会有find命令参与。从24小时的运行结果看,CPU升高频率没有下降,故可以排除find命令参与导致的硬盘IO耗时增加。
3.2.6 推测:日志数据由CPU搬运导致IO耗时高

 查询硬盘官网数据发现,硬盘支持SATA III 协议,最高6.0Gbp速率。查询系统初始化日志,发现硬盘只初始化到了3.0Gbps,故本机仅支持SATA II 协议。
  1. # dmesg | grep "ata"
  2. [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache
  3. [    0.000000] Memory policy: Data cache writealloc
  4. [    0.000000] Memory: 1605968K/1893376K available (8192K kernel code, 411K rwdata, 2580K rodata, 2048K init, 331K bss, 98992K reserved, 188416K cma-reserved, 1213440K highmem)
  5. [    0.000000]       .data : 0xc1000000 - 0xc1066e08   ( 412 kB)
  6. [    0.323529] omap_hwmod: l3_main_2 using broken dt data from ocp
  7. [    0.632209] omap4_sram_init:Unable to allocate sram needed to handle errata I688
  8. [    0.632219] omap4_sram_init:Unable to get sram pool needed to handle errata I688
  9. [    0.691599] libata version 3.00 loaded.
  10. [    1.855012] ahci 4a140000.sata: SSS flag set, parallel bus scan disabled
  11. [    1.861800] ahci 4a140000.sata: AHCI 0001.0300 32 slots 1 ports 3 Gbps 0x1 impl platform mode
  12. [    1.870408] ahci 4a140000.sata: flags: 64bit ncq sntf stag pm led clo only pmp pio slum part ccc apst
  13. [    1.883880] ata1: SATA max UDMA/133 mmio [mem 0x4a140000-0x4a1410ff] port 0x100 irq 325
  14. [    2.386170] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
  15. [    2.395590] ata1.00: ATA-10: XXXXXXX(保密处理), max UDMA/133
  16. [    2.401731] ata1.00: 125045424 sectors, multi 1: LBA48 NCQ (depth 31/32)
  17. [    2.424278] ata1.00: configured for UDMA/133
  18. [    2.698354] dmm 4e000000.dmm: workaround for errata i878 in use
  19. [    3.547350] EXT4-fs (mmcblk1p2): mounted filesystem with ordered data mode. Opts: (null)
  20. [    3.610946] EXT4-fs (mmcblk1p2): re-mounted. Opts: data=ordered
  21. [    4.348450] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
复制代码
 使用hdparm命令查看硬盘信息,发现已启用了UDMA6。
  1. # hdparm -I /dev/sda
  2. /dev/sda:
  3. ATA device, with non-removable media
  4.         Model Number:        XXXXXXX(保密处理)
  5.         Serial Number:
  6.         Firmware Revision:
  7.         Media Serial Num:
  8.         Media Manufacturer:
  9. Standards:
  10.         Supported: 10 9 8 7
  11.         Likely used: 10
  12. Configuration:
  13.         Logical         max     current
  14.         cylinders       16383   16383
  15.         heads           16      16
  16.         sectors/track   63      63
  17.         --
  18.         CHS current addressable sectors:   16514064
  19.         LBA    user addressable sectors:  125045424
  20.         LBA48  user addressable sectors:  125045424
  21.         device size with M = 1024*1024:       61057 MBytes
  22.         device size with M = 1000*1000:       64023 MBytes (64 GB)
  23. Capabilities:
  24.         LBA, IORDY(can be disabled)
  25.         Queue depth: 32
  26.         Standby timer values: spec'd by standard, no device specific minimum
  27.         R/W multiple sector transfer: Max = 1   Current = 1
  28.         DMA: mdma0 mdma1 mdma2 udma0 udma1 udma2 udma3 udma4 udma5 *udma6
  29.                 Cycle time: min=120ns recommended=120ns
  30.         PIO: pio0 pio1 pio2 pio3 pio4
  31.                 Cycle time: no flow control=120ns  IORDY flow control=120ns
  32. Commands/features:
  33.         Enabled Supported:
  34.            *    NOP cmd
  35.            *    READ BUFFER cmd
  36.            *    WRITE BUFFER cmd
  37.            *    Look-ahead
  38.            *    Write cache
  39.                 Power Management feature set
  40.                 Security Mode feature set
  41.            *    SMART feature set
  42.            *    FLUSH CACHE EXT cmd
  43.            *    Mandatory FLUSH CACHE cmd
  44.            *    48-bit Address feature set
  45.            *    DOWNLOAD MICROCODE cmd
  46.            *    General Purpose Logging feature set
  47. Security:
  48.         Master password revision code = 65534
  49.                 supported
  50.         not     enabled
  51.         not     locked
  52.         not     frozen
  53.         not     expired: security count
  54.                 supported: enhanced erase
  55.         10min for SECURITY ERASE UNIT. 10min for ENHANCED SECURITY ERASE UNIT.
  56. Checksum: correct
复制代码
 从结果看,已经启用了DMA搬运数据,故在硬件上已达到最优性能。
3.2.7 推测:写文件过程导致IO性能瓶颈

 推测IO性能是因为写入文件的操作导致的。为验证是否是因为写入文件导致的IO过高,我将记录板的数据清空,修改记录板软件代码,仅接收数据,不写入文件。连续运行17小时,发现记录磁盘IO不存在异常升高的问题。
 CPU升高到60及以上的情况仅在创建各类文件、目录时存在,创建完毕以后立即下降。
15.png

回过头看这里,其实对文件系统的操作,本身就是一个较为耗时的操作。在这种情况下,软件内部的各种线程锁,反而在等待文件系统的反馈,这进一步加剧了软件性能损耗。
 根据测试情况而言,可以确认IO瓶颈是因文件系统操作导致的。
软件内部、外部的环境因素就暂时排查到这里,还有还有一部分排查思路与这里相差的特别大,就不放出来了。
3.2.8 sched分析

 之前的分析中,发现记录板存在看门狗重启现象,说明记录板软件进程未能被系统调度,为排查未被调度原因,使用技术手段对异常调时候进行sched record,分析系统当时的调度延迟原因。
自此以后,就是对linux内核相关的参数进行推测排查。
 在抓取数据时,发现存在某个线程长时间阻塞的情况。
16.png

 在wsl上使用perf sched -i perf.data -v script | grep -C 100 "472.578711"命令,筛选出对应时间节点的信息。
17.png

 为探寻异常时的进程状态,使用相关的命令进行抓取性能数据处理:
  1. #使用TOP进行整体观测
  2. top -b  | busybox awk 'NR { printf  "%s %s\n",  strftime(), $0 ; fflush(stdout) }' > toplog
  3. .txt &
  4. #对IO进行整体观测
  5. ./iostat 2 -d /dev/sda -t -x -k -c > iolog.txt &
  6. #使用perf对内核各项进程、cpu进行观测
  7. ./perf top -a | tee perfTmp.txt | cat -n  | busybox awk 'NR { printf  "%s %s\n",  strftime(), $0 ; fflush(stdout) }
  8. ' > PerfTopLog.txt
复制代码
 抓取一段时间以后,观察异常的故障时间点,针对IO进行观察。
  1. 03/07/25 12:08:36
  2. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  3.           21.05    0.00   33.24    1.11    0.00   44.60
  4. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  5. sda              0.00      0.00     0.00   0.00    0.00     0.00   61.50    354.00    26.50  30.11    0.98     5.76    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.06   6.00
  6. 03/07/25 12:08:38
  7. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  8.           12.65    0.00   27.65   29.12    0.00   30.59
  9. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  10. sda              0.00      0.00     0.00   0.00    0.00     0.00   29.50   8624.00    20.50  41.00  202.71   292.34    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   16.75  75.50
  11. 03/07/25 12:08:40
  12. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  13.           18.52    0.00   36.18   27.35    0.00   17.95
  14. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  15. sda              0.00      0.00     0.00   0.00    0.00     0.00   32.00   3214.00    14.50  31.18  473.12   100.44    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    4.37  68.00
  16. 03/07/25 12:08:42
  17. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  18.           20.39    0.00   34.71    2.20    0.00   42.70
  19. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  20. sda              0.00      0.00     0.00   0.00    0.00     0.00   61.50   2602.00    38.00  38.19    5.12    42.31    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.32  12.50
复制代码
观察到以下信息:

  • 在 12:08:38 和 12:08:40,写操作的等待时间(w_await)分别达到 202.71ms 和 473.12ms,远高于其他时间点的 1-23ms。
  • 在 12:08:38,%util 达到 75.50%,且平均队列长度(aqu-sz)飙升至 16.75。其中,%util 超过 60% 表明磁盘接近饱和。aqu-sz 表示排队中的I/O请求数,超过 1 表示请求开始堆积。磁盘无法及时处理请求,导致I/O瓶颈。
  • 在 12:08:38 和 12:08:28,写入带宽(wkB/s)分别达到 8,624KB/s 和 8,808KB/s,远超其他时间点的 300-3,000KB/s。单次写请求大小(wareq-sz)也显著增大(292.34KB vs 通常的 5-100KB)。
  • 在磁盘高负载时段(如 12:08:38),系统CPU使用率(%system)达到 27.65%,表明内核在处理I/O时消耗较多资源。进一步加剧系统整体负载。
3.2.9 推测:IO调度器设置

 对于硬盘的数据调度而言,使用cat /sys/block/sda/queue/scheduler命令查看调度器,其结果如下
  1. # cat /sys/block/sda/queue/scheduler
  2. noop deadline [cfq]
复制代码
 说明当前使用的是绝对公平的调度器CFQ。尝试修改调度器为电梯式调度器noop
  1. #echo noop > /sys/block/sda/queue/scheduler
复制代码
 运行以后,效果反而更差了。
  1. 03/10/25 12:03:04
  2. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  3.            6.27    0.00   49.37   12.03    0.00   32.33
  4. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  5. sda              0.00      0.00     0.00   0.00    0.00     0.00   36.50   3564.00    15.50  29.81   59.59    97.64    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    7.83  49.00
  6. 03/10/25 12:03:06
  7. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  8.           15.12    0.00   29.36   43.31    0.00   12.21
  9. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  10. sda              0.50      2.00     0.00   0.00 1680.00     4.00   14.00   5138.00     2.00  12.50  917.86   367.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   29.53 100.00
  11. 03/10/25 12:03:08
  12. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  13.           12.83    0.00   31.49   33.82    0.00   21.87
  14. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  15. sda              0.00      0.00     0.00   0.00    0.00     0.00   11.00   4780.00     0.00   0.00 2065.00   434.55    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00   27.32 100.00
  16. 03/10/25 12:03:10
  17. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  18.           13.60    0.00   36.54    6.80    0.00   43.06
  19. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  20. sda              0.00      0.00     0.00   0.00    0.00     0.00   41.00   1354.00    37.00  47.44  687.68    33.02    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    2.09  27.50
  21. 03/10/25 12:03:12
  22. avg-cpu:  %user   %nice %system %iowait  %steal   %idle
  23.           14.29    0.00   32.65    3.21    0.00   49.85
  24. Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dkB/s   drqm/s  %drqm d_await dareq-sz     f/s f_await  aqu-sz  %util
  25. sda              0.00      0.00     0.00   0.00    0.00     0.00   41.00    254.00    21.50  34.40    4.02     6.20    0.00      0.00     0.00   0.00    0.00     0.00    0.00    0.00    0.17  16.50
复制代码
 尝试更换为截止时间调度器deadline。与目前一样,依旧会造成IO过高问题。
3.2.10 推测:函数内部write函数耗时过高

 记录板软件会使用write函数进行数据记录。对软件的调用进行计时操作。
  1. 行  4907: [2025-03-10 14:28:46.854081][rec] mcpId:18, write time:2145 ms
  2. 行  4908: [2025-03-10 14:28:46.854085][rec] mcpId:19, write time:1785 ms
  3. 行  4906: [2025-03-10 14:28:46.264327][SYS MON] CPU:90%, Mem:10%
  4.         
  5. 行 10012: [2025-03-10 14:30:36.610485][rec] mcpId:240, write time:1030 ms
  6. 行 10013: [2025-03-10 14:30:36.610486][rec] mcpId:241, write time:1038 ms
  7. 行 10011: [2025-03-10 14:30:36.533324][SYS MON] CPU:65%, Mem:10%
  8. 行 10038: [2025-03-10 14:30:38.307138][rec] mcpId:184, write time:1605 ms
  9. 行 10039: [2025-03-10 14:30:38.308734][rec] mcpId:240, write time:1648 ms
  10. 行 10143: [2025-03-10 14:30:38.539680][SYS MON] CPU:97%, Mem:10%
复制代码
 从日志看,确实是write函数上下文耗时过高。write是同步型函数,其操作为阻塞式,若阻塞时间过长,会导致数据堆积。为解决wirte频次高、数据量较小的情况,使用内核缓冲区,将数据存入缓冲内,接收完数据以后即向硬盘写数据。
3.2.11 推测:降低写入频率+异步写入

 为此方向编写了数据缓冲区+libaio的异步缓冲代码,发现依旧存在问题。
18.png

 对系统进行检查:
  1. # cat /sys/block/sda/queue/scheduler
  2. [noop] deadline cfq
  3. # cat /sys/block/sda/queue/nr_requests
  4. 128
  5. # cat /sys/block/sda/device/queue_depth
  6. 31
  7. # cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
  8. cat: can't open '/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor': No such file or directory
  9. # cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
  10. cat: can't open '/sys/devices/system/cpu/cpu1/cpufreq/scaling_governor': No such file or directory
  11. # cat /proc/irq/325/smp_affinity
  12. 3
  13. # dmesg | grep -i 'sata link up'
  14. [    2.386072] ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
  15. # dmesg | grep -i 'DMA: preallocated'
  16. [    0.322195] DMA: preallocated 256 KiB pool for atomic coherent allocations
  17. # cat /sys/kernel/debug/tracing/events/block/enable
  18. cat: can't open '/sys/kernel/debug/tracing/events/block/enable': No such file or directory
  19. # cat /sys/kernel/debug/tracing/trace_pipe
  20. cat: can't open '/sys/kernel/debug/tracing/trace_pipe': No such file or directory
复制代码

  • 当前I/O调度器为noop,适合SSD场景,无需调整。
  • 队列深度nr_requests为128,queue_depth为31,符合SSD的NCQ深度要求,无需调整。
  • CPU频率调节器系统未启用CPU频率调节器(scaling_governor不存在),大概率是由于内核未启用相关功能或硬件不支持动态调频。
  • SATA中断(IRQ 325)已绑定到CPU 0和1(smp_affinity=3),无需调整。
  • SATA链路速度为3.0 Gbps,符合SATA II标准,但未达到SATA III(6.0 Gbps)的峰值性能。
  • DMA内存池已预分配256 KiB,符合常规配置。
3.2.12 推测:异步单次写入

 使用异步批量写入的方式对数据进行写入,对数据进行60小时持续观测。异步写入核运行在A设备,标签核运行在B设备,其运行结果如下:
CPU使用率标签核(单位:次数)异步批量写入(单位:次数)0-59区间101836(89.62%)100986(89.09%)60-79区间11605(10.21%)11965(10.56%)80-100区间192(0.17%)400(0.35%)合计113633113351 从结果看,其实差距并不大。
3.2.13 推测:虚拟内存参数存在异常

 分析到可能存在虚拟内存参数不是最优的情况:
  1. # sysctl -a | grep dirty
  2. vm.dirty_background_bytes = 0
  3. vm.dirty_background_ratio = 10
  4. vm.dirty_bytes = 0
  5. vm.dirty_expire_centisecs = 3000
  6. vm.dirty_ratio = 20
  7. vm.dirty_writeback_centisecs = 500
  8. vm.dirtytime_expire_seconds = 43200
  9. vm.highmem_is_dirtyable = 0
复制代码

  • vm.dirty_background_ratio 是内存可以填充脏数据的百分比。这些脏数据稍后会写入磁盘,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。
  • vm.dirty_ratio是可以用脏数据填充的绝对最大系统内存量,当系统到达此点时,必须将所有脏数据提交到磁盘,同时所有新的I/O块都会被阻塞,直到脏数据被写入磁盘。这通常是长I/O卡顿的原因,但这也是保证内存中不会存在过量脏数据的保护机制。vm.dirty_background_bytes和vm.dirty_bytes是另一种指定这些参数的方法。如果设置_bytes版本,则_ratio版本将变为0,反之亦然。
  • vm.dirty_expire_centisecs 指定脏数据能存活的时间。在这里它的值是30秒。当 pdflush/flush/kdmflush 在运行的时候,他们会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。毕竟数据在内存里待太久也会有丢失风险。
  • vm.dirty_writeback_centisecs 指定多长时间 pdflush/flush/kdmflush 这些进程会唤醒一次,然后检查是否有缓存需要清理
  1. # cat /proc/vmstat | egrep "dirty|writeback"
  2. nr_dirty 3069
  3. nr_writeback 0
  4. nr_writeback_temp 0
  5. nr_dirty_threshold 26435
  6. nr_dirty_background_threshold 13201
复制代码
 从当前情况看,目前的数据量输入稳定,基本不存在数据量快速增长的情况。目前尝试调整虚拟内存参数,减少脏页回写对I/O性能的影响。
  1. echo 20 > /proc/sys/vm/dirty_ratio #由10提升至20
  2. echo 5 > /proc/sys/vm/dirty_background_ratio #由10降低至5
  3. echo 1000 > /proc/sys/vm/dirty_expire_centisecs #由500提升至1000
复制代码

  • 当系统内存中脏页占可用内存的比例达到 20% 时,系统会强制将脏页写入磁盘。较高的值会延迟写入操作,可能提升性能,但会增加数据丢失的风险;较低的值会更快写入磁盘,减少数据丢失风险,但可能降低性能。
  • 当脏页占可用内存的比例达到 5% 时,系统会在后台启动写回操作,将脏页写入磁盘。较低的值会更快启动后台写回,减少脏页积累,但可能增加 I/O 负载;较高的值会延迟写回,可能提升性能,但会增加脏页积累。
  • 脏页在内存中停留超过 1000 厘秒(10 秒)后,会被标记为需要写回磁盘。较长的值会延迟写回,可能提升性能,但会增加数据丢失风险;较短的值会更快写回,减少数据丢失风险,但可能降低性能。
执行以下参数:

  • 日志记录时进行批量异步IO提交
  • 降低dirty_background_ratio与dirty_expire_centisecs的参数:
    1. dirty_background_ratio 由10降低至5
    2. dirty_expire_centisecs 由500降低至200
    19.png

执行以下参数:

  • 日志记录时进行批量异步IO提交
  • 降低dirty_background_ratio与dirty_expire_centisecs的参数:
    1. dirty_background_ratio 由10降低至2
    2. dirty_expire_centisecs 由500降低至200
    20.png

执行以下参数:

  • 日志记录时进行批量异步IO提交
  • 降低dirty_background_ratio与dirty_expire_centisecs的参数:
    1. dirty_background_ratio 由10降低至5
    2. dirty_expire_centisecs 由500降低至250
    21.png

其他的参数就不再此处体现。
3.2.14 推测:日志压缩程序CPU占用过高

 日志压缩程序使用7z方案中的LZMA算法。测日志压缩程序占用CPU较高,尝试对核心参数做调整。
[code]typedef struct{  int level;       /* 0
您需要登录后才可以回帖 登录 | 立即注册