zoukankan      html  css  js  c++  java
  • Nginx + PHP-FPM 参数优化、性能监视和问题排查

    Linux内存优化:

    打开文件 /etc/sysctl.conf,增加以下设置

    #该参数设置系统的TIME_WAIT的数量,如果超过默认值则会被立即清除
    net.ipv4.tcp_max_tw_buckets = 20000
    #定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数
    net.core.somaxconn = 65535
    #对于还未获得对方确认的连接请求,可保存在队列中的最大数目
    net.ipv4.tcp_max_syn_backlog = 262144
    #在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
    net.core.netdev_max_backlog = 30000
    #能够更快地回收TIME-WAIT套接字。此选项会导致处于NAT网络的客户端超时,建议为0
    net.ipv4.tcp_tw_recycle = 0
    #系统所有进程一共可以打开的文件数量
    fs.file-max = 6815744
    #防火墙跟踪表的大小。注意:如果防火墙没开则会提示error: "net.netfilter.nf_conntrack_max" is an unknown key,忽略即可
    net.netfilter.nf_conntrack_max = 2621440

    运行 sysctl -p 使配置生效

    设置系统打开文件数设置

    解决高并发下 too many open files 问题。此选项直接影响单个进程容纳的客户端连接数。

    Soft open files 是Linux系统参数,影响系统单个进程能够打开最大的文件句柄数量,这个值会影响到长连接应用如聊天中单个进程能够维持的用户连接数, 运行ulimit -n能看到这个参数值,如果是1024,就是代表单个进程只能同时最多只能维持1024甚至更少(因为有其它文件的句柄被打开)。如果开启4个进程维持用户连接,那么整个应用能够同时维持的连接数不会超过4*1024个,也就是说最多只能支持4x1024个用户在线可以增大这个设置以便服务能够维持更多的TCP连接。

    Soft open files 修改方法:

    (1)ulimit -HSn 102400

    这只是在当前终端有效,退出之后,open files 又变为默认值。

    (2)在/etc/profile文件末尾添加一行 ulimit -HSn 102400,这样每次登录终端时,都会自动执行/etc/profile。

    (3)令修改open files的数值永久生效,则必须修改配置文件:/etc/security/limits.conf. 在这个文件后加上:

    * soft nofile 1024000
    * hard nofile 1024000
    root soft nofile 1024000
    root hard nofile 1024000

    这种方法需要重启机器才能生效。

    PHP参数优化

    php-fpm.conf文件参数调整

    pm = dynamic; 表示使用哪种进程数量管理方式

    dynamic表示php-fpm进程数是动态的,最开始是pm.start_servers指定的数量,如果请求较多,则会自动增加,保证空闲的进程数不小于pm.min_spare_servers,如果进程数较多,也会进行相应清理,保证多余的进程数不多于pm.max_spare_servers。
    static表示php-fpm进程数是静态的, 进程数自始至终都是pm.max_children指定的数量,不再增加或减少。

    pm.max_children = 300;  静态方式下开启的php-fpm进程数量
    pm.start_servers = 20;  动态方式下的起始php-fpm进程数量
    pm.min_spare_servers = 5;  动态方式下的最小php-fpm进程数量
    pm.max_spare_servers = 35;  动态方式下的最大php-fpm进程数量

    如果pm为static, 那么其实只有pm.max_children这个参数生效。php-fpm服务启动后,系统会开启设置数量的php-fpm进程

    如果pm为dynamic, 那么pm.max_children参数失效,后面3个参数生效。系统会在php-fpm运行开始的时候启动pm.start_servers个php-fpm进程,然后根据系统的需求动态在pm.min_spare_servers和pm.max_spare_servers之间调整php-fpm进程数

    那么,对于我们的服务器,选择哪种pm方式比较好呢?事实上,跟Apache一样,运行的PHP程序在执行完成后,或多或少会有内存泄露的问题。这也是为什么开始的时候一个php-fpm进程只占用3M左右内存,运行一段时间后就会上升到20-30M的原因了。

    对于内存大的服务器(比如8G以上)来说,指定静态的max_children实际上更为妥当,因为这样不需要进行额外的进程数目控制,会提高效率。因为频繁开关php-fpm进程也会有时滞,所以内存够大的情况下开静态效果会更好。数量也可以根据 内存/30M 得到,比如8GB内存可以设置为100,那么php-fpm耗费的内存就能控制在 2G-3G的样子。如果内存稍微小点,比如1G,那么指定静态的进程数量更加有利于服务器的稳定。这样可以保证php-fpm只获取够用的内存,将不多的内存分配给其他应用去使用,会使系统的运行更加畅通。

    pm.max_requests = 10240;

    nginx+php-fpm 组合中最大问题是内存泄漏出问题:服务器的负载不大,但是内存占用迅速增加,很快吃掉内存接着开始吃交换分区,系统很快挂掉!
    其实根据官方的介绍,php-cgi不存在内存泄漏,每个请求完成后php-cgi会回收内存,但是不会释放给操作系统,这样就会导致大量内存被php-cgi占用。
        
    官方的解决办法是降低PHP_FCGI_MAX_REQUESTS的值,如果用的是php-fpm,对应的php-fpm.conf中的就是max_requests
    该值的意思是发送多少个请求后会重启该线程,我们需要适当降低这个值,用以让php-fpm自动的释放内存,不是大部分网上说的51200等等,实际上还有另一个跟它有关联的值max_children,这个是每次php-fpm会建立多少个进程,这样实际上的内存消耗是 max_children*max_requests*每个请求使用内存,根据这个我们可以预估一下内存的使用情况,就不用再写脚本去kill了。

    request_terminate_timeout = 30;
    最大执行时间, 在php.ini中也可以进行配置(max_execution_time)

    rlimit_files = 1024;  增加php-fpm打开文件描述符的限制

    listen.backlog 参数设置为-1时,在2.6.18内核的机器上会有问题,参考 https://blog.csdn.net/haoluojie/article/details/76070191

    php-fpm的高CPU使用率排查方法

    资源占用查看

    1、查看php-fpm的进程个数

    ps -ef |grep "php-fpm"|grep "pool"|wc -l

    2、查看每个php-fpm占用的内存大小

    ps -ylC php-fpm --sort:rss

    3.查看PHP-FPM在你的机器上的平均内存占用

    ps --no-headers -o "rss,cmd" -C php-fpm | awk '{ sum+=$1 } END { printf ("%d%s ", sum/NR/1024,"M") }'

    4.查看每个php-fpm进程消耗内存的明细

    pmap $(pgrep php-fpm) | less



    1) 查询php-fpm慢日志

    request_slowlog_timeout = 2; 开启慢日志
    slowlog = log/$pool.slow.log; 慢日志路径

    grep -v "^$" www.slow.log | cut -d " " -f 3,2 | sort | uniq -c | sort -k1,1nr | head -n 10

    参数解释:
    sort:  对日志文件每行日志按字母进行排序,以便传递给uniq -c进行行数(慢查询出现次数)统计
    uniq -c:  统计内容相同的行,合并显示为一行,并在行首加上本行在文件中出现的次数
    sort -k1,1nr:  按照第一个字段(出现次数),数值排序,且为逆序
    head -n 10:  取前10行数据

    结果类似:

    出现次数    被调用的函数    文件和调用行号
    5181        run()            /www/test.net/framework/web/filters/CFilter.php:41

    5156        filter()        /www/test.net/framework/web/filters/CFilterChain.php:131

    2636        run()            /www/test.net/application/controllers/survey/index.php:665

    2630        action()        /www/test.net/application/controllers/survey/index.php:18

    2625        run()           /www/test.net/framework/web/actions/CAction.php:75

    2605        runWithParams()    /www/test.net/framework/web/CController.php:309

    file_get_contents 请求url有个问题值得注意:http://zyan.cc/tags/request_terminate_timeout/1/

    2) 监测php-fpm线程状态

    nginx 在站点中增加配置

    location ~ ^/status$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    }

    php-fpm 配置

    pm.status_path = /status

    然后就可以通过http://域名/status就可以看到当前的php情况,输出参数说明:
    pool:php-fpm池的名称,一般都是应该是www
    process manage:进程的管理方法,php-fpm支持三种管理方法,分别是static,dynamic和ondemand,一般情况下都是dynamic
    start time:php-fpm启动时候的时间,不管是restart或者reload都会更新这里的时间
    start since:php-fpm自启动起来经过的时间,默认为秒
    accepted conn:当前接收的连接数
    listen queue:在队列中等待连接的请求个数,如果这个数字为非0,那么最好增加进程的fpm个数
    max listen queue:从fpm启动以来,在队列中等待连接请求的最大值
    listen queue len:等待连接的套接字队列大小
    idle processes:空闲的进程个数
    active processes:活动的进程个数
    total processes:总共的进程个数
    max active processes:从fpm启动以来,活动进程的最大个数,如果这个值小于当前的max_children,可以调小此值
    max children reached:当pm尝试启动更多的进程,却因为max_children的限制,没有启动更多进程的次数。如果这个值非0,那么可以适当增加fpm的进程数
    slow requests:慢请求的次数,一般如果这个值未非0,那么可能会有慢的php进程,一般一个不好的mysql查询是最大的祸首。

    3) strace分析跟踪进程


    方法一:利用nohup将strace转为后台执行,直到attach上的php-fpm进程死掉为止

    nohup strace -T -p 13167 > 13167-strace.log &

    参数说明:

    -c 统计每一系统调用的所执行的时间,次数和出错的次数等.
    -d 输出strace关于标准错误的调试信息.
    -f 跟踪由fork调用所产生的子进程.
    -o filename,则所有进程的跟踪结果输出到相应的filename
    -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
    -h 输出简要的帮助信息.
    -i 输出系统调用的入口指针.
    -q 禁止输出关于脱离的消息.
    -r 打印出相对时间关于,,每一个系统调用.
    -t 在输出中的每一行前加上时间信息.
    -tt 在输出中的每一行前加上时间信息,微秒级.
    -ttt 微秒级输出,以秒了表示时间.
    -T 显示每一调用所耗的时间.
    -v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
    -V 输出strace的版本信息.
    -x 以十六进制形式输出非标准字符串
    -xx 所有字符串以十六进制形式输出.
    -a column
    设置返回值的输出位置.默认为40.
    -e execve 只记录 execve 这类系统调用
    -p 主进程号

    结果类似:

    select(7, [6], [6], [], {15, 0})               = 1 (out [6], left {15, 0})
    poll([{fd=6, events=POLLIN}], 1, 0)     = 0 (Timeout)
    select(7, [6], [6], [], {15, 0})               = 1 (out [6], left {15, 0})
    ...

    方法二:用利用-c参数让strace帮助汇总

    strace -cp 9907

    输出类似

    Process 9907 attached - interrupt to quit

    Process 9907 detached

    % time     seconds  usecs/call     calls    errors syscall

    ------ ----------- ----------- --------- --------- ----------------

    56.61    0.016612           5      3121           read

    11.11    0.003259           1      2517          715 stat

    0.00    0.000000           0        26           chdir

    0.00    0.000000           0         1           futex

    ...
    ------ ----------- ----------- --------- --------- ----------------

    100.00    0.029344                 18000       986 total

    4) 使用xdebug性能监控(xdebug对php运行有性能影响,线上服务器慎用)

    常用的方法就是开启xdebug的性能监控功能,将xdebug输出结果通过WinCacheGrind软件分析。

    xdebug的安装和配合IDE调试的方法参见:Vim+XDebug调试PHPWinCacheGrind分析脚本执行时间

    php.ini中配置的这几项是输出性能信息的:

    xdebug.auto_trace = on

    xdebug.auto_profile = on
    xdebug.collect_params = on
    xdebug.collect_return = on
    xdebug.profiler_enable = on
    xdebug.trace_output_dir = "/tmp"
    xdebug.profiler_output_dir ="/tmp"


    这样XDebug会输出所有执行php函数的性能数据,但产生的文件也会比较大。可以关闭一些选项如collect_params、collect_return,
    来减少输出的数据量。或者关闭自动输出,通过在想要监控的函数首尾调用xdebug函数来监控指定的函数。

    输出的文件名类似cachegrind.out.1277560600 和 trace.3495983249.txt,可以拿到Windows平台下用WinCacheGrind进行图形化分析。

    4) 使用 xhprof 做被动分析

    https://blog.csdn.net/maquealone/article/details/80434699

  • 相关阅读:
    ISO14443 Type A 和 Type B 的数据流
    return false vs stopPropagation(), preventDefault(),stopImmediatePropagation()
    jq mouse事件
    jq next nextAll nextUntil siblings的区别
    UITextView布局不是从0开始的问题
    App开发者需要更新此App以在此iOS版本上正常工作
    委托,深入浅出才是王道(二)
    委托,深入浅出才是王道(一)
    委托,深入浅出才是王道(三)
    设计模式学习日记二(持续更新)
  • 原文地址:https://www.cnblogs.com/lbnnbs/p/13558384.html
Copyright © 2011-2022 走看看