zoukankan      html  css  js  c++  java
  • Linux性能优化实战学习笔记:第六讲

    一、环境准备

    1、安装软件包

    终端1

    机器配置:2 CPU,8GB 内存 预先安装 docker、sysstat、perf等工具

    [root@luoahong ~]# docker -v
    Docker version 18.09.1, build 4c52b90
    [root@luoahong ~]# rpm -qa|grep sysstat
    sysstat-12.1.2-1.x86_64

    终端2

    机器配置:1 CPU,2GB 内存 预先安装ab 等工具

    [root@nfs ~]#yum -y install httpd-tools 
    [root@nfs ~]# ab -V
    This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
    Licensed to The Apache Software Foundation, http://www.apache.org/
    

    2、实战拓谱图

    3、环境模拟

    终端一

    docker run --name nginx -p 10000:80 -itd feisky/nginx:sp
    $ docker run --name phpfpm -itd --network container:nginx feisky/php-fpm:sp

    终端二

    测试nginx是否启动

    # 192.168.118.97 是第一台虚拟机的 IP 地址
    $ curl http://192.168.118.97:10000/
    It works!
    

    性能测试

    # 并发 100 个请求测试 Nginx 性能,总共测试 1000 个请求
    $ ab -c 100 -n 1000 http://192.168.118.97:10000/
    This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, 
    ...
    Requests per second:    87.86 [#/sec] (mean)
    Time per request:       1138.229 [ms] (mean)
    ...
    

    继续压力测试

    ab -c 5 -t 600 http://192.168.118.97:10000/

    二、定位问题(top、pidstat、ps)

    1、top定位

    2、pidstat定位

    [root@luoahong ~]# pidstat 1
    Linux 3.10.0-957.5.1.el7.x86_64 (luoahong) 	05/04/2019 	_x86_64_	(2 CPU)
    
    03:41:55 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
    03:41:56 PM     0         3    0.00    2.94    0.00    0.00    2.94     0  ksoftirqd/0
    03:41:56 PM     0         9    0.00    6.86    0.00   27.45    6.86     0  rcu_sched
    03:41:56 PM     0        14    0.00   15.69    0.00    9.80   15.69     1  ksoftirqd/1
    03:41:56 PM     0      7500    4.90    2.94    0.00    0.98    7.84     0  vmtoolsd
    03:41:56 PM     0      9451    0.00    1.96    0.00    0.00    1.96     1  dockerd
    03:41:56 PM    27      9928    0.00    0.98    0.00    0.00    0.98     0  mysqld
    03:41:56 PM     0     10133    0.98    0.00    0.00    0.00    0.98     1  containerd-shim
    03:41:56 PM     0     10804    0.00    0.98    0.00    4.90    0.98     1  kworker/1:0
    03:41:56 PM     0     10835    0.98    3.92    0.00    0.00    4.90     1  containerd-shim
    03:41:56 PM   101     10891    0.00    5.88    0.00   15.69    5.88     0  nginx
    03:41:56 PM     1     84378    0.98    2.94    0.00    3.92    3.92     0  php-fpm
    03:41:56 PM     1     84388    0.00    1.96    0.00    3.92    1.96     1  php-fpm
    03:41:56 PM     1     84395    0.98    0.98    0.00    4.90    1.96     1  php-fpm
    03:41:56 PM     1     84411    0.00    0.98    0.00    3.92    0.98     0  php-fpm
    03:41:56 PM     1     84413    0.00    1.96    0.00    8.82    1.96     1  php-fpm
    03:41:56 PM     0    102735    0.00    0.98    0.00    0.00    0.98     1  pidstat

    3、top再次定位

    你有没有发现,nginx和所有的PHP-FPM都处于sleep状态,二真正处于Running(R)状态的,却是几个 stress 进程,这几个stree比较奇怪,需要我们做进一步的分析

    4、pidstat再次定位

    [root@luoahong perf-tools]# pidstat -p 24226
    Linux 3.10.0-957.5.1.el7.x86_64 (luoahong) 	05/04/2019 	_x86_64_	(2 CPU)
    
    03:47:45 PM   UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command

    奇怪、居然没有任何输出。难道是pidstat命令出问题了吗?在怀疑西能工具出问题前,最好还是先用其他工具交叉确认一下

    5、ps定位

    [root@luoahong perf-tools]# ps aux|grep 24226
    root      66566  0.0  0.0 112708   980 pts/0    S+   15:46   0:00 grep --color=auto 24226

    还是没有输出,现在终于发现问题,原来这个进程已经不存在了,所以pidstat就没有任何输出,既然进程都没了

    那西能问题应该跟着没了吧。我们在top命令确认一下;

    top
    ...
    %Cpu(s): 80.9 us, 14.9 sy,  0.0 ni,  2.8 id,  0.0 wa,  0.0 hi,  1.3 si,  0.0 st
    ...
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
     6882 root      20   0   12108   8360   3884 S   2.7  0.1   0:45.63 docker-containe
     6947 systemd+  20   0   33104   3764   2340 R   2.7  0.0   0:47.79 nginx
     3865 daemon    20   0  336696  15056   7376 S   2.0  0.2   0:00.15 php-fpm
      6779 daemon    20   0    8184   1112    556 R   0.3  0.0   0:00.01 stress
    ...

    可是,刚刚看到的stree进程不存在了,怎么还在运行呢?原来这次stree进程的pid跟前面不一样了,原来的pid不见了现在的是6779

    进程的 PID 在变,这说明什么呢?在我看来要么是这些进程在不停地重启,要么就是全新的进程,这无非也就两个原因

    第一原因:进程在不停地崩溃重启,比如因为段错误、配置错误等等这时,进程在退出后可能又被监控系统自动重启了。
    第二原因:这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用 top 这种间隔时间比较长的工具发现(上面的案例,我们碰巧发现了)

    6、用pstree | grep [xx],这样定位到具体的调用方法里。

    [root@luoahong ~]# pstree | grep stress
            |            |                 |         |-2*[php-fpm---sh---stress---stress]
            |            |                 |         |-php-fpm---sh---stress

    三、定位到具体的代码

    1、用grep [xx] -r [项目文件]

    查找是不是代码在调用stree命令

    # 拷贝源码到本地
    $ docker cp phpfpm:/app .
    
    # grep 查找看看是不是有代码在调用 stress 命令
    $ grep stress -r app
    app/index.php:// fake I/O with stress (via write()/unlink()).
    app/index.php:$result = exec("/usr/local/bin/stress -t 1 -d 1 2>&1", $output, $status);
    

    2、找到具体代码位置

    找到了,果然是app/index.php

    cat app/index.php
    <?php
    // fake I/O with stress (via write()/unlink()).
    $result = exec("/usr/local/bin/stress -t 1 -d 1 2>&1", $output, $status);
    if (isset($_GET["verbose"]) && $_GET["verbose"]==1 && $status != 0) {
      echo "Server internal error: ";
      print_r($output);
    } else {
      echo "It works!";
    }
    ?>

    3、给请求加入 verbose=1 参数后,就可以查看 stress的输出

    [root@nfs ~]# curl http://192.168.118.97:10000/?verbose=1
    Server internal error: Array
    (
        [0] => stress: info: [103660] dispatching hogs: 0 cpu, 0 io, 0 vm, 1 hdd
        [1] => stress: FAIL: [103661] (563) mkstemp failed: Permission denied
        [2] => stress: FAIL: [103660] (394) <-- worker 103661 returned error 1
        [3] => stress: WARN: [103660] (396) now reaping child worker processes
        [4] => stress: FAIL: [103660] (400) kill error: No such process
        [5] => stress: FAIL: [103660] (451) failed run completed in 0s
    )

    从这里我们可以猜测,正式由于权限错误,大量的stress进程在启动是初始化失败,进而导致用户CPU使用率的升高

    4、perf验证定位是否准确

    1、perf record -g 记录

    perf record -g 
    docker cp perf.data phpfpm:/tmp
    docker exec -i -t phpfpm bash

    2、 用perf report查看是否可以定位到问题

    cd /tmp/
    apt-get update && apt-get install -y linux-perf linux-tools procps
    perf_4.9 report

    四、execsnoop和实验过程中遇到的问题

    1、execsnoop查看短时进程详细信息

    execsnoop 就是一个专为短时进程设计的工具它通过 ftrace 实时监控进程的 exec() 行为,并输出短时进程的基本信息,
    包括进程 PID、父进程 PID、命令行参数以及执行的结果。

    用 execsnoop 监控上述案例,就可以直接得到 strress 进程的父进程 PID 以及它的命令行参数,并可以发现大量的 stress 进程在不停启动:

    git clone --depth 1 https://github.com/brendangregg/perf-tools
    cd perf-tools/
    [root@luoahong perf-tools]# ./bin/execsnoop
    Tracing exec()s. Ctrl-C to end.
    Instrumenting sys_execve
       PID   PPID ARGS
     70342  70322 gawk -v o=1 -v opt_name=0 -v name= -v opt_duration=0 [...]
     70344  50765            <...>-70344 [001] d...  2372.510629: execsnoop_sys_execve: (SyS_execve+0x0/0x30)
     70343  70341 cat -v trace_pipe
     70340      0 /usr/local/bin/stress -t 1 -d 1
     70346  70339 /usr/local/bin/stress -t 1 -d 1
     70347  70344 /usr/local/bin/stress -t 1 -d 1
     70351  50796            <...>-70351 [000] d...  2372.553884: execsnoop_sys_execve: (SyS_execve+0x0/0x30)
     70352  50775            <...>-70352 [000] d...  2372.555010: execsnoop_sys_execve: (SyS_execve+0x0/0x30)
     70353  70351 /usr/local/bin/stress -t 1 -d 1
     70355  50776            <...>-70355 [000] d...  2372.557869: execsnoop_sys_execve: (SyS_execve+0x0/0x30)
     70357  70355 /usr/local/bin/stress -t 1 -d 1
     70356  70352 /usr/local/bin/stress -t 1 -d 1
    

    execsnoop所用的ftrace是一种常用的动态追踪技术,一般用于分析linux内核的运行时为

    2、pstree的安装

    yum install psmisc

    3、小结

    如果碰到不好解释的CPU问题时,比如现象:

    通过top观察CPU使用率很高,但是看下面的进程的CPU使用率好像很正常,通过pidstat命令查看cpu也很正常。但通过top查看task数量不正常,处于R状态的进程是可疑点。

    首先要想到可能是短时间的应用导致的问题,如下面的两个:
    (1)应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过top等工具发现不了
    (2)应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用很多CPU资源

  • 相关阅读:
    浏览器同源政策及其规避方法---转阮大神
    js跨域详解
    js中top、self、parent
    杂记
    DOM 踩踩踩
    java idea 连接数据库
    数据库mySQL常用命令
    用迭代实现80人围成一圈逢3取出
    如何把通过类建立的对象存入数组中.
    面向对象编程
  • 原文地址:https://www.cnblogs.com/luoahong/p/10808936.html
Copyright © 2011-2022 走看看