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 使配置生效
如果报错:sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_max: No such file or directory,能是 conntrack没有加载,执行
lsmod | grep conntrack
如果 返回 为空,表示没有加载,执行下面命令 重新加载
modprobe ip_conntrack
重新运行 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 = 120; 静态方式下开启的php-fpm进程数量,或者动态方式下最大php-fpm进程数量
pm.start_servers = 30; 动态方式下的起始php-fpm进程数量,该参数必须在 min_spare_servers 和 max_spare_servers 之间,一般等于 min_spare_servers
pm.min_spare_servers = 30; 动态方式下的最小空闲php-fpm进程数量,一般是 max_children 的 25%
pm.max_spare_servers = 90; 动态方式下的最大空闲php-fpm进程数量,空闲php-fpm进程超过此数量就会开始回收,一般是 max_children 的 75%
max_children 的计算方式一般有两种
如果是长时间高强度计算型服务,单个php-fpm进程耗时较长且cpu消耗大,一般max_children设置为CPU核心数的2倍或者4倍,太大也没有用,因为要等待之前的计算进程完成
如果是高IO型服务,一般max_children设置为 可用内存数量 / 每个PHP-FPM进程消耗的内存平均值,一般每个PHP-FPM进程消耗的内存在30M左右
一般的系统基本都是高IO型的,主要就是数据的读写,但如果你的系统有部分高计算型业务,可用按实际情况做出调整
如果是专用的PHP后端服务器,可用内存数据 = 总内存 - 系统消耗 - 缓存消耗(比如OPCache,一般为内存的10%,可以查询php.ini中的opcache.memory_consumption参数) - 保留内存(一般为内存的10%-20%),比如8G总内存,CentOS7操作系统,系统消耗1G,开启OPCache消耗1G,保留内存1G,那么可用内存就只有5G了,可以开启的 max_children = 5 * 1024 / 30 = 170
每个PHP-FPM进程消耗的内存也不是什么系统都是30M左右,具体可用下面的命令在业务稳定或高峰时查询出来看看
ps aux|grep php-fpm|awk '{print $6/1024 " "$2" "$11" "$12" "$13" "$14}'|sort -n -k 1
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\n", 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调试PHP 、 WinCacheGrind分析脚本执行时间
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 做被动分析