五一节就这么废了,因为线上服务器负载一直飙高。
负载这么高,居然还能登录系统进行操作,佩服佩服。
这是一套新上线的业务,购买的是阿里云的主机及服务。业务请求先到负载均衡,业务承载由2台云主机来担当,缓存redis直接购买服务,mysql数据库也是购买现成的服务。这意味着,能直接进行维护操作的,就是两台云主机,上边部署了nginx、php,以及必须的php扩展。
登录上系统后,常用的套路有:查看进程、查看负载、查看网络连接情况、查看系统日志、查看web日志、查看php日志(错误日志、慢查询日志)、查看数据库状况...
1、查进程数,发现php进程数量保持一个恒定的数值。这说明php开启的进程数到达设定的最大值,资源占完,又不能正常释放。通过修改配置php-fpm.conf,重启php观察其运行情况,修改后的配置文件如下:
[global]
pid = /usr/local/php/var/run/php-fpm.pid
error_log = /usr/local/php/var/log/php-fpm.log
log_level = notice
[www]
listen = 127.0.0.1:9000
;listen = /dev/shm/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
pm = dynamic
pm.max_children = 2000
pm.start_servers = 100
pm.min_spare_servers = 20
pm.max_spare_servers = 100
;access.log = /home/wwwroot/logs/phplog/$pool.access.log
access.log = /home/wwwlogs/phplog/$pool.access.log
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
pm.max_requests = 102400
request_terminate_timeout = 4s
request_slowlog_timeout = 2
slowlog = /home/wwwlogs/phplog/slow.log
说明:access.log这行,原来程序员配置的日志路径是一个共享NAS,php代码发布在其上,两台云主机同时对它进行读写,担心两台机器同时对同一个文件打开和写入会带来io上的负担,因此把日志写入本地路径/home/wwwlogs/phplog.
通过上述修改以后,php的进程数基本处于正常,但对负载降低的作用还是很有限。查看php日志,滚屏得飞快。
2、查看网络状况,算不上异常,输出如下:
[root@web1 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'LAST_ACK 54
SYN_RECV 6
ESTABLISHED 528
FIN_WAIT1 33
TIME_WAIT 5641
修改了系统文件/etc/sysctl.conf,重新加载,效果改善不明显。
3、流量检查,用了两个工具iftop和iptraf,从输出可以判断,基本在可接受的范围。但有个ip地址,其一直排在流量第一位,有点可疑,是什么业务呢?
执行 netstat -anp|grep 172.31.176.238 进一步核实,是对redis的请求,看起来还不少呢!
[root@web1 ~]# netstat -anp|grep 172.31.176.238|wc -l
3197
两台主机都查了,加起来得有7000左右的请求,不太正常吧!
3、最近借服务器挖矿很流行,担心被入侵,拿acunetix一通猛扫,未见异常;又拿360认证后扫一遍(webscan.360.cn,不是windwos安装的安全卫士一类),也一无所获。再仔细检查文件、系统安全日志、帐号文件等,基本可以判断没有被入侵。
折腾了好几天,这些招数都不灵,白天负载高都还想得通,用户在访问嘛。可是稀奇的是,当通过调整,负载降下去了,到凌晨的时候,又开始飙升。不得意,在nginx做访问限制,其主要配置如下:
map $request_method $limit {
default "";
POST $binary_remote_addr;
}
limit_conn_zone $binary_remote_addr zone=one_limit:10m;
limit_req_zone $limit zone=zone_limit_post:10m rate=10r/m;
访问量大的站点,再单独插入如下的行:
limit_req zone=zone_limit_post burst=5;说明:前边一段代码,插入到nginx主配置文件里边;后边一段,插入到具体站点配置server的 location那段里边。如果位置不对,做语法检查会报错,当然也就启动不了nginx。
重载nginx后,负载稍微有所下降,但相关部门反馈,这限制影响大用户访问了。
五一假期都结束了,尝试了多种办法,效果还是不理想。于是我就打算自己下载app,安装在手机上,了解一下客户端的访问行为。开打app以后,底部菜单栏三个:快讯、行情、我的。其中“快讯”又分几个板块--快讯、动态、微博、教程。
通过点击菜单和对比服务器,发现两个问题:
1、不管点不点“行情”,客户端都会疯狂地去抓取行情数据。通过web访问日志可以看到同一个ip,对同一对象发起的频繁请求(“POST /index.php?_url=/market/list&”)。通过与其他技术人员沟通,证实了我的猜测,客户端每秒钟会发起大概20次的请求,只要app开着。
2、只要打开了app,不管是否需要,都会全部读取所有的信息。通过“快讯”这一屏显示内容,手指一直往上滑,一直都有内容。而我拿别人家的app做对比,别的app是上滑的过程,会有一个短暂的加载过程,即需要数据的时候,才真正去抓取和加载。
掌握这些信息后,赶紧电话跟其它人沟通,强烈建议更细app,改变现在这种无限制读取数据的方法。相关人员也意识到问题确实由此引起,承诺尽快处理。但本文撰写进行时,据称目前已经强制更新了大概50%的客户端。从服务器端看负载,趋势逐渐好转。