论坛---挂掉的思考
某天,某dz论坛整站垮掉,事后分析:遭遇cc攻击,非常多的肉机(不同IP)对该论坛某个特定的url进行访问,造成整站瘫痪。
排查思路
如果遇到整站瘫痪,我们应该怎么办?
1,测试静态页面,检测web-server是否正常,通常是正常的
2,测试php页面,检测php是否正常,两种状态都有可能,大部分是正常的,少数情况异常
3,手工连接数据,测试连通性,执行show processlist,查慢sql
4,查access-log,慢请求肯定会在access-log中体现,大部分情况查慢请求能迅速定位问题
因为请求慢才会造成后续请求阻塞进而出现问题,请求足够快就不会有问题。
请求慢的原因
可能1:php跑满了,请求被饿死(深层原因还是请求慢,这是表象);
可能2:应用程序内部逻辑问题,有互锁,死循环,函数处理慢要优化(注意,内存溢出不属于此类);
可能3:io阻塞(写文件慢,目前未碰到过),sql慢(因为sql必须等待执行结束才会返回,未结束会一直等待,即使客户端主动断开,mysql有可能还会一直执行,sql慢是碰到最多的)
另,内存溢出一定会报php错误,会被记录在php错误日志中,会返回500的错误,只会影响单次执行,不会影响后续请求。
access-log已经多次为排查事故原因做出了贡献。
CC攻击案例分析
我们根据access-log来还原下这次cc攻击下webserver和系统的表现。
攻击从10:45:48开始一直持续到10:52:05,10:55:22恢复正常,持续10分钟。
第一阶段:10:45:48到10:46:50,整站沦陷
[30/Oct/2014:10:45:48 +0800] "GET /status.php HTTP/1.0" 499 0 "-" "KeepAliveClient" 82 4.999 -
[30/Oct/2014:10:45:48 +0800] "GET /search.php?searchsubmit=yes HTTP/1.1" 499 0 "-" "Mozilla/4.0" 142 30.000 -
攻击一开始,大量的攻击请求打过来,整站瞬间塌陷,响应全部超过30秒,返回499状态码
单台机器的攻击请求数是50个/秒,从第一秒开始所有php请求均响应失败返回499(30秒为客户端连接nginx超时,客户端主动断开连接),图片请求正常,status.php也返回499(估计检测脚本设置nginx连接超时是5秒)。这段时间内lvs已经知道nginx无法连接(间接说明了nginx处理php特别慢),但是没做下线处理
第二阶段:10:46:50-10:51:13,LVS下线前端机,重启php-fpm
lvs认为前端机确实有问题,执行下线操作。在此期间,一直有status心跳探测。我们看到了这样的日志:
[30/Oct/2014:10:46:56 +0800] "GET /status.php HTTP/1.1" 504 182 "-" "-" 50 60.002 -
[30/Oct/2014:10:46:56 +0800] "GET /thread-3029964-1-1.html HTTP/1.1" 504 ... 60
[30/Oct/2014:10:46:56 +0800] "GET /status.php HTTP/1.0" 499 0 "-" "KeepAliveClient" 82 5.000 -
分析:第三条日志,5秒+499,是正常的status脚本检测,执行时间为5秒,连接nginx超时;
第一条日志为什么会是60秒超时呢?
合理的解释:client到nginx已建立连接,但nginx到php连接失败,socket_timeout设置为60s,连接超时退出,nginx返回给客户端504。(同时能知道,access-log是在执行结束后记录的,实际请求时间=日志时间减去执行时间)
那么这样就容易解释第二条日志了,和第一条日志一样的原理。可以看到,超时时间是60秒,请求时间是10:45:56,请求是在cc攻击之后发生的,cc攻击之后请求处理有两类,一类返回499(连接nginx超时,被客户端断开),另一类返回504(nginx连接php超时)
部分结论:status.php连接nginx超时返回499,连接nginx成功但nginx连php失败会返回504。
第三阶段:10:51:13-10:52:05,前端机上线,攻击继续,多次重启php-fpm,10:55:22恢复正常
[30/Oct/2014:10:51:12 +0800] "GET /status.php HTTP/1.1" 200 13 "-" "-" 50 13.673 -
怀疑,lvs判断status是正常的,所以上线前端机。
攻击日志如下:
[30/Oct/2014:10:51:26 +0800] "GET /search.php?searchsubmit=yes HTTP/1.1" 499 0 "-" "Mozilla/4.0" 143 29.993 -
恢复后的第一条200日志:
[30/Oct/2014:10:55:22 +0800] "GET /forum-77-489.html HTTP/1.1" 200
上线处理了些正常请求后又遭攻击,攻击在10:52:05停止后,打出了些504连接超时的语句,在10:55:22恢复正常。
我认为,主因是客户端瞬间连接太多,导致nginx连接数打满,php连接数打满,和mysql关系不大。
那么针对cc攻击,需要做什么事情呢?
php版本升级?可以查slowlog,但不是防cc的解决方案,瞬间打满php,处理多快都没用。
增加前端机?能够增加nginx和php连接数,可以缓解CC攻击带来的冲击。
优化mysql?和mysql没直接关系,不是防cc的解决方案。
接扛攻击集群?让集群来扛量和过滤非法IP,是个不错的解决方案。
环境变量
nginx.conf,php连接超时是300s
etc/php-fpm.conf,请求执行超时是31s
lib/php.ini, default_socket_timeout = 60
额外了解到的
502:Bad gateway。如果脚本运行时间很长,比如循环80次,每次等待1秒,nginx会返回502。这意味着,client-nginx连接成功,nginx-php连接成功,但php耗时太长
499:NGX_HTTP_CLIENT_CLOSED_REQUEST。客户端关闭请求。这意味着,client-nginx连接失败
504:Gateway Time-out。用户连接该服务器,该服务器作为网关请求上游服务器,上游服务器响应超时。这意味着,client-nginx连接成功,(nginx-php连接失败,或者连接成功,但是一直没处理该php)
Reference
nginx状态码解释:http://www.daniel-journey.com/archives/1699
504相关:http://wenku.it168.com/d_000790933.shtml