Linux 上接口卡顿异常排查(IO 异常)

前提:

客户现场有一台服务器,由于现场断电,导致服务器强制重启了,重启之后web可以访问但接口异常卡顿。

排查故障:

  1. 第一个就怀疑是网络问题,因为服务只是重启了,web也能登录,所以怀疑是企业的路由器故障了,导致web卡顿,但是经过排查、测速,并不是这个原因

  2. 第二个怀疑是系统资源不足,但是排查了内存和磁盘占用之后发现并没有异常

    # 查看内存占用
    top
    # 查看磁盘占用
    df -h
    
  3. 第三个排查业务代码,使用阿里巴巴的Arthas工具

    # 由于我的服务是用docker部署,需要进入容器内进行监控
    docker exec -it my-web bash
    # 下载arthas包
    curl -O https://arthas.aliyun.com/arthas-boot.jar
    # 启动监控,注意如果服务器无法联网,需要下载arthas-bin.zip包解压之后执行 ./install-local.sh 安装所需组件,再启动监控
    java -jar arthas-boot.jar
    # 启动之后根据提示选择对应的java进程 比如 1
    # 使用trace指令监控卡顿的接口函数,这个指令可以记录函数的调用耗时
    trace com.chemcyber.web.myflow.screen.service.impl.FlowManageScreenServiceImpl getOperationTicket
    

    1752198508663_d.png

    经过排查,找到了查询慢的sql,拿到数据库里面直接执行,发现竟然时快时慢。。。真是头大

  4. 第四步,经过不断的网上查找,以及提问AI,建议我排查一下系统IO,于是

    # 监控IO占用
    iostat -x 1
    

    1752199058244_d.png

    可以看到IO占用竟高达99%,到这里总算是找到了大致的方向了,于是继续排查

    iotop -oP
    

    可以看到是mysql占用了大量的IO(这个截图找不到了),经过一顿搜索,卡顿的原因是服务器异常断电重启后,MySQL自动进行崩溃修复,因此占用大量IO,以下是临时缓解办法(记得修改之前先查询当前配置,方便后续恢复回去)。

    -- MySQL临时降低写入压力
    SET GLOBAL innodb_flush_log_at_trx_commit = 2;
    SET GLOBAL sync_binlog = 0;
    
    -- 优化InnoDB配置
    SET GLOBAL innodb_io_capacity = 2000;
    SET GLOBAL innodb_io_capacity_max = 4000;
    
    -- MySQL关键调整(立即生效)
    SET GLOBAL innodb_io_capacity=4000;
    SET GLOBAL innodb_flush_neighbors=0;  -- SSD必须关闭
    SET GLOBAL innodb_adaptive_flushing=ON;
    -- 增加缓冲池
    SET GLOBAL innodb_buffer_pool_size = 12G;  # 建议物理内存的50-70%
    
  5. 再次查看IO状态,发现一顿操作下来,IO占用竟然没有丝毫改善。。。

    # 查询磁盘写入速度(该命令会创建一个名为testfile的1GB文件,并将零值数据写入该文件。通过使用oflag=direct参数,可以绕过操作系统缓存,直接测试磁盘的写入性能)
    dd if=/dev/zero of=testfile bs=1G count=1 oflag=direct
    # 等待命令执行完成。在完成后,dd命令将显示读取的数据量、所用的时间和读取速度等信息。
    

    image.png

    磁盘写入速度只有100MB/S,这里判断可能是磁盘故障了,没办法了,只能等mysql自动修复了,第二天再看看。

  6. 一觉睡醒后,第二天果然恢复正常了(记得把之前改的mysql配置恢复回去)。

  7. 后续处理:排查服务器硬盘是否异常,需要更换硬盘,如果服务器做了Raid阵列(比如Raid5),可能是有其中一块盘坏了,导致整体写入速度变慢。