摘要:众所周知,Nginx是目前最流行的Web Server之一,也广泛应用于负载均衡、反向代理等服务,但使用过程中可能因为对Nginx工作原理、变量含义理解错误,或是参数配置不当导致Nginx工作异常。本文介绍的就是福建开机广告Nginx的参数location处理静态文件配置不当引发的nginx日志骤增到14G的问题排期过程。
一、问题现象及系统介绍
现象:12月15日 21:02分,正在外面吃宵夜,手机收到监控平台的一条“服务器磁盘空间<20%”报警短信。
系统介绍:为了看此文的童鞋更好理解我下面介绍的东西,这里我先简单介绍下福建开机广告系统。
整个系统可以分为管理平台与API两个部分:
管理平台完成素材(包括下面提到素材图片名也是有放到缓存里的)、广告、策略、排期制作和下发等工作,提供接口将广告策略、用户分组等信息同步到API;
API向机顶盒/EPG提供广告接口,采集广告请求日志,当STB访问EPG,EPG调用广告请求接口获取广告策略(地区、分组、平台、黑白名单等策略),并在匹配到策略的时候进行展示;
API节点我们是放在其中6台服务器的23个tomcat里面,使用nginx实现负载请求分发;图片服务器我们是放在另外的3台服务器,也是使用的nginx实现的负载请求分发。相信大家对nginx都不陌生,这里我就不在赘述。
二、问题排查过程
2.1 初步分析
判断一:可能是crontab未执行
一看是Nginx所在服务器,初步判断可能是crontab异常,没有定期清除5天以前的日志导致(这里说明下:我们线上的nginx日志是每天凌晨切割access.log日志,然后通过crontab实现只保留最近五天日志)。
2.2 深入分析:
判断二:可能图片同步出问题
回到家,打开SHH客户端 查看/data/nginx_log目录查看,发现access.log只有近五天的日志,「排除原以为是crontab异情况」。
然后发现error_log很大,命令du -h error_log一看都有14G了,tail -200 error_log发现全是“/usr/local/nginx/html/resources/material/img/1511488532192.JPG”图片请求失败的记录,于是赶紧清空error_log,排除短信空间报警。
心想,难道是图片没有同步?
为验证我的猜想,我打开浏览器访问这张图片:http://IP:port/resources/material/img/1511488532192.JPG(上面IP指的是nginx所在服务器IP,port是nginx.conf配置图片分发端口),请求几次返回都是404。
于是切换到主图片服务器查看,发现这张大写图片存在,切换到其他两台从图片服务器,发现也是存在的(这里说明下:我们系统的素材图片都是通过管理平台以接口的形式下发主图片服务器,主图片服务器再通过inotify+sync同步到其他两台从图片服务器),「排除图片同步异常情况」。
判断三:可能是请求不到大写后缀图片导致
因为看到图片服务器目录下,唯有这几张大写后缀图片是请求异常的,那改成小写会怎么样呢?接着改了下三台图片服务器的图片大写后缀为小写后缀。再打开浏览器请求,发现请求正常了,继而判断可能运营人员在管理平台制作广告的时候上传了大写后缀的格式的图片,同步到API和数据库的缓存,那么导致有广告请求的从缓存查询到的图片地址也就是大写的了。
顺着这个思路,我先到登录到数据库改了下素材表图片大写后缀为小写后缀,再登录redis,准备改缓存,info命令一看,傻眼了,136万的key数量,而我又不记得具体广告策略key,
由于没办法查找,那就只能flushall清空缓存,重启ad-cache工程(这里说明下:ad-cache工程的作用主要就是两个,一是把当前符合要求的用户、广告策略等相关信息初始加载到缓存,另一个是启一个定时任务,每小时加载当前时段的策略到缓存),然后在查看tail -f error_log查看日志,发现还在增加之前那种大写后缀图片请求失败的错误,「排除图片后缀大写情况」。
判断四:可能是nginx配置不当导致
这么操作完还是不行,当时着实有点懵逼,我心想当时已经把广告请求所有涉及到会查询图片大写后缀的地方改过来了,为什么还是会有大写后缀图片请求失败的记录?但转念一想会不是nginx的配置有问题?
为验证我的判断,我先sz命令从图片服务器上下载了一张名为“1511488578911.JPG”的大写后缀格式的图片,然后通过管理平台上传这个“1511488578911.JPG”图片素材,发现这张图片是可以预览的。由此更加确信就是nginx某些参数配置不当导致。vim命令查看配置nginx.conf,当定位到图片请求配置这里的时候,
发现location ~是表示区分大小写的,而后面全是配置小写后缀格式,于是加上JPG,使用/usr/local/nginx/sbin/nginx -s reload命令重载nginx的配置,打开浏览器发现可以查看到这张图片了,再切换到nginx日志目录,tail -f error_log,发现日志没有再增加,至此问题终于解决。
三、问题反思
反思一:要做到知其然并且知其所以然
对Nginx工作原理、参数含义理解不深,从而参数配置不当,导致产生nginx日志骤增这种问题产生。
反思二:缺少一个快速定位问题的系统或工具,导致排查的时间比较长。
当时在作出判断三的时候,因为没在公司,不记得广告策略缓存key,导致不得不直接执行flushall命令直接清空缓存,再重新刷入缓存,这样做其实是有风险的,因为把广告策略、用户、分组等信息从缓存清空之后,用户的广告请求只能直接去查询数据库,这样响应的时间肯定会慢了,而且缓存中还存了广告请求的日志记录,直接flushall就会丢失部分的广告请求数据,影响到PV、UV统计。所以当时也是想就是有一个系统,在浏览器直接输入一个用户名或是图片名,就能从数据库和缓存查询到中涉及到相关联的数据,以可视化的形式在页面展示,这样定位问题也就可以更快定位问题了。
四、引申
语法规则: location [=|~|~*|^~] /uri/ { … }
= 开头表示精确匹配
^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。
~ 开头表示区分大小写的正则匹配
~* 开头表示不区分大小写的正则匹配
!~和!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则
/ 通用匹配,任何请求都会匹配到。
多个location配置的情况下匹配顺序为(参考资料而来,还未实际验证,试试就知道了,不必拘泥,仅供参考):
首先匹配 =,其次匹配^~, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
例子,有如下匹配规则:
[plain] view plain copy
location = / {
#规则A
}
location = /login {
#规则B
}
location ^~ /static/ {
#规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
#规则D
}
location ~* \.png$ {
#规则E
}
location !~ \.xhtml$ {
#规则F
}
location !~* \.xhtml$ {
#规则G
}
location / {
#规则H
}
那么产生的效果如下:
访问根目录/, 比如http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而 http://localhost/static/c.png 则优先匹配到 规则C
访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。