今天下午好像有人对服务器ddos,或者大量灌spam(我不敢说每个人都安装了anti spam插件,即使安装了,“应对”spammer也要消耗服务器资源),http服务器耗尽服务器资源后挂掉,一会儿被watchdog重启,过不了多一会儿再次挂掉。。。以前也尝试过优化apache,不过今天似乎终于摸到了一点儿窍门。
我们合租的MediaTemple服务器cpu负载不高,内存相对紧张:
top - 23:39:45 up 16 days, 7:24, 2 users, load average: 0.58, 0.50, 0.47
Tasks: 46 total, 1 running, 45 sleeping, 0 stopped, 0 zombie
Cpu(s): 9.9% us, 2.5% sy, 0.0% ni, 87.6% id, 0.0% wa, 0.0% hi, 0.0% si
Mem: 689496k total, 550892k used, 138604k free, 0k buffers
所以优化主要针对如何节约内存。主机内存实际是256M,可能是多核的缘故,总显示接近700M内存,不过对应的各个进程占用的内存也相应增加了。MediaTemple的KB中有一篇[(dv) HOWTO: Performance tuning (Optimization)](http://kb.mediatemple.net/article.php?id=771),先按照这个来优化一下,主要分为三个部分。
优化Apache(httpd)
缩短超时时限:
#Timeout 120
Timeout 30
调整prefork参数,我调整的结果是:
<IfModule prefork.c>
#1/1/3
StartServers 1
MinSpareServers 1
MaxSpareServers 3
# 50 ?
ServerLimit 20
MaxClients 20
MaxRequestsPerChild 2000
</IfModule>
StartServers是开始的httpd进程数,Min和Max SpareServers是最少和最多空闲进程数,ServerLimit和MaxClients是总进程数限制,这两个参数一般来说是相同的,httpd所消耗的总内存数就和这个相关(实际进程数还会多两个,应该是负责管理子进程的“父进程”),内存不够可以把这两个数值进一步缩小,但这也同时对应着httpd同时处理的并发数。MaxRequestsPerChild是每个进程在处理多少个任务后自杀,根据需要和相关设置还会再启动新的子进程,这种机制有利于释放一些内存碎片。
MaxClients不够会在log产生错误信息,可以用下面的命令查询:
grep -i maxclient /var/log/httpd/error_log
可以根据情况再调整MaxClients的值,但如果内存就是短缺,又能有什么办法呢?
优化Mysql
设置缓存,在my.cnf的[mysqld]
段中增加:
# Cache
query-cache-type = 1
query-cache-size = 16M
虽然会多占用一些内存,但能加快处理的速度,尽快把等待队列“消化”掉,还是有利于加速的。在mysql中可以查询cache使用情况:
mysql> show status like 'Qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 12 |
| Qcache_free_memory | 13028408 |
| Qcache_hits | 35117 |
| Qcache_inserts | 751 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 56 |
| Qcache_queries_in_cache | 377 |
| Qcache_total_blocks | 872 |
+-------------------------+----------+
8 rows in set (0.00 sec)
...... some times late ......
mysql> show status like 'Qcache%';
+-------------------------+---------+
| Variable_name | Value |
+-------------------------+---------+
| Qcache_free_blocks | 88 |
| Qcache_free_memory | 8837920 |
| Qcache_hits | 164437 |
| Qcache_inserts | 3572 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 432 |
| Qcache_queries_in_cache | 1177 |
| Qcache_total_blocks | 2579 |
+-------------------------+---------+
8 rows in set (0.00 sec)
调整query-cache-size的值让Qcache_lowmem_prunes保持在0最好,设置太大了也是浪费内存。
关闭不需要的服务
比如named,域名解析使用域名注册商提供的就足够了,关闭spamassassin,邮件服务仅限于对外发送邮件,不接收:
chmod 644 /etc/init.d/psa-spamassassin
watchdog暂时不建议关闭,人不在的时候它会自动重启服务,还是有一点用处的。
其它优化设置
从其它地方还看到可以开启KeepAlive:
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 15
这样每个连接可以发送100次请求,超时时间为15秒。如果KeepAliveTimeout减少一些,MaxKeepAliveRequests还可以设置得更大一点。
还可以启用apache的压缩输出功能:
<ifmodule mod_deflate.c>
# DeflateCompressionLevel 2
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-php application/x-javascript text/css
</ifmodule>
简单观察一下,开启deflate之后,服务器cpu idle值大概会减少15~20%,国外主机数据传输本身就慢,希望这些花销值得。
top - 01:39:03 up 16 days, 9:23, 3 users, load average: 2.16, 2.09, 1.97
Tasks: 48 total, 1 running, 47 sleeping, 0 stopped, 0 zombie
Cpu(s): 24.1% us, 8.4% sy, 0.0% ni, 67.6% id, 0.0% wa, 0.0% hi, 0.0% si
Mem: 689496k total, 431452k used, 258044k free, 0k buffers
Swap: 0k total, 0k used, 0k free, 0k cached
结果
现在看一下结果,ps -U apache u
能看到一共有20个apache进程在运行,占用内存总量为:
root@fwolf:~# ps -U apache u|awk '{S+=$6} END {print S}'
385396
随着服务运行,内存使用量还会增加(所以MaxRequestsPerChild别设太大,定期重启一些进程)。再看看那个疑似对我ddos的家伙:
root@fwolf:~# netstat -nap|grep :80|wc -l
513
root@fwolf:~# netstat -nap|grep TIME_WAIT|wc -l
9
root@fwolf:~# netstat -nap|grep 124.115|wc -l
464
root@fwolf:~# netstat -nap|grep 124.115.0|wc -l
376
root@fwolf:~# netstat -nap|grep 124.115.4|wc -l
93
此时服务器访问稍慢,有时会超时,但起以前动不动内存不足,httpd挂掉要好一些了。查了一下,这个IP地址属于“陕西省西安市 电信”,地址总换,但基本都在上面两个网段之内。
再后来,访问量降下来之后,系统就恢复正常了,优化应该还是对服务器速度有一些作用的。
root@fwolf:~# netstat -nap|grep :80|wc -l; netstat -nap|grep TIME_WAIT|wc -l
69
47
最后贴两张后台流量图表,异常大概开始于18号下午16点,导致18号流量剧增。服务器时间是西8区,所以小时图表中的0点就是16点。按天的那个图表不知为什么出不来,不过注意18号的流量只是前9个小时的就是了。
另外,合租的兄弟们,[现在新的dv主机默认是PHP 5.2了](http://www.mediatemple.net/webhosting/dv/details.htm#php5),咱们啥时候升级呢?
参考
- [再议apache优化](http://jed.dzhope.com/read.php/272.htm)
- [APACHE优化之apache的内存使用](http://hi.baidu.com/swgweb/blog/item/dba900e94cbe9b3cb90e2d18.html)
- [谈谈Apache的优化](http://tech.idv2.com/2007/08/09/about-apache-perf-tuning/)
Update @ 2008-01-19
看来我的担心是多余的,mod_deflate启用之后并没有耗费太多系统资源,访问量恢复正常之后,cpu load也恢复了正常:
top - 16:15:45 up 17 days, 0 min, 1 user, load average: 0.04, 0.05, 0.07
Tasks: 51 total, 1 running, 50 sleeping, 0 stopped, 0 zombie
Cpu(s): 1.8% us, 0.7% sy, 0.0% ni, 95.9% id, 1.7% wa, 0.0% hi, 0.0% si
Mem: 689496k total, 510200k used, 179296k free, 0k buffers
Swap: 0k total, 0k used, 0k free, 0k cached
好像启用了KeepAlive后httpd进程轮换得特别快,不像以前半天不重生一个。现在可以清楚的看到18号全天的流量图标了,再补两张图:
按每小时400M流量计算,每秒流量为110K,不知道算是个什么样的水平。
Update @ 2008-01-19
关闭named服务后,jail环境的ssh用户使用wget下载文件会遇到Name or service not known
错误,把/etc/resolv.conf
也配置到chroot中就可以了。有趣的是,如果named服务启动着就不存在这个问题。
顺便还把denyhosts装上了,daemon模式运行,占内存不多,攻击者还不少呢,值得。参考:[使用DenyHosts阻止SSH暴力破解](http://www.sofee.cn/blog/2006/10/22/51/)
那两个IP段已经是臭名昭彰,建议直接用iptables封段这两个段。 BTW,用的是什么流量统计工具?
我是直接在netstat中看的ip,太显眼了。主机上自带awstats,也可以选择Webalizer。