Tag: nginx

基于wp 的blog 遭遇一次自杀式攻击

微博的名人确实有杀伤力啊,周五的时候,Kaifu 老师的微博转了一下公司的博客地址,结果访问一下子涌过来了。5000 的访问里有3000+ 是访问 / ,wp 的 / 是动态的啊,难怪撑不住,load1m 飙到50 ,20 个php-fpm 忙得不行。我把这类都归结于自杀式攻击,其实,很多时候,弄死我们的,都是自己啊。

解决也不是很难,静态化吧。curl 一个首页放到wp 的文件夹里,命名为 index.htm ,顺便改改 nginx 的配置:

if ($uri = “/”){
rewrite “^/$” /index.htm break ;
}
完事,load1m 迅速下降到1 以下了。

处理这个事情的时候我正在打火锅呢,其实还想做得更完美一点的,静态化的首页,也能定时更新一下,但发现没那么简单,就放弃了。就放下去吃火锅了,天杀的谁想出来在这么热的天时吃火锅的!!

其实最好的做法就是,用 wp 的 wp super cache 插件。

nginx+apache+dav_svn 的怪异问题

最近帮朋友的网站做个小优化,由apache 迁移到nginx ,结果问题多多,svn 在提交的时候竟然有这个错误:

$ svn ci -m”fix the mail problem “
Sending        util.php
svn: Commit failed (details follow):
svn: File ‘util.php’ is out of date
svn: ‘/svn/!svn/bc/496/trunk/util.php’ path not found
但是提交其它文件貌似没有问题。怪异到爆!!!

首先说说nginx 的配置。

svn 仍然使用 apache 的dav_svn ,只是端口由80 改为 1234,其它配置不改。

location  /svn {

proxy_pass http://127.0.0.1:1234 ;

proxy_set_header Host “svn.mysite.net” ;

}

终于在google 大神找到一篇俄文的mailing-list(http://www.lexa.ru/nginx-ru/msg39625.html),竟然有人和我同样的错误,也终于弄清楚什么事了。。。简直是自己白痴!!
我的php 的配置:
location ~ \.php$ {
root           /var/www/backend/  ;
fastcgi_pass   127.0.0.1:9000;
fastcgi_index  index.php;
include        fastcgi.conf;
}
这个location 用了正则匹配,比svn 的普通location 优先级高,结果svn 提交util.php 的时候(会发送一堆svn 的指令如propfind , option 等),优先到php 的location 里,结果就出错了。。。
那svn 也用高优先级的location 匹配吧,修改一下,用前缀匹配:
location ^~ /svn
ok , 成功了。。。
事后我才看到,nginx 本身就有一个404 的log :
211.102.143.12 – hello [03/Jul/2011:15:34:53 +0800] “PROPFIND /svn/!svn/bc/496/trunk/util.php HTTP/1.1″ 404 31 “-” “SVN/1.6.15 (r1038135) neon/0.28.6″ “-“
唉。。。怪自己~~

一个关于cookie 的怪异登陆问题

近来有一些用户在某些网络环境下,登陆不了网站。通过详细的联系沟通,终于得出了结论。用户自己用http analyzer ,我在服务器端抓包。

用户端的请求头:

GET / HTTP/1.1
Accept:application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, /
Referer:http://www.zhihu.com/
Accept-Language:zh-CN
User-Agent:Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Win64; x64; Trident/4.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
UA-CPU:AMD64
Host:www.zhihu.com
Connection:Keep-Alive
Cache-Control:no-cache
Cookie:*****
我抓包得到的请求头:
GET / HTTP/1.1
Host: www.zhihu.com
Connection: keep-alive
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Qtnddkdrcx: zojajzrgfrdigltciezwhgoumzevhyzqexwfsgkkoyhpiyctzvwzbqzscjzqpuqrflttgfcuxuvzvfiurfjaojmgmenvrfgnqfolulvapnmnjhetvsmktvpdxxekebsrnnnzokqnyuesfldfpbgwcivwgmmjfkgtilacaixdlpibhhvckjbbsupufbjxbhuizwfuhfvyarrowwvipbzmvrh
Accept-Language: zh-CN,zh;q=0.8
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3
Accept-Encoding: gzip,deflate,sdch
Cookie:
Cookie: *****

哇塞,基本全改了,除了cookie 也是那个,不过,多了一行空的cookie 。这是一个什么网络啊!!还加了一串不知道是什么的东西。

我测试了一下,nginx 是可以把 $http_cookie 正确读取出来的,但是后端的web 读取不了,读取了第一个空的cookie 。结果,一直认为用户没有cookie ,所以,用户就不能登陆了。

nginx 针对这种情况修复一下,在所有使用proxy_pass 的地方,加一行:

proxy_set_header Cookie $http_cookie ;

这样就把cookie 硬塞给后端了。

很不负责任地讲一句,我怀疑是运营商做的手脚。当然,也有可能是该用户的上网环境导致。

亚运赛事系统架构探索

广州亚运亚残在今天落幕了,一班亚运的同事将要离职,真让人伤感。随便写篇东西纪念一下我为亚运付出的一个月。

亚运赛事系统最初的系统架构,非常简单,就是前端用一堆组了lvs 的 squid 作为cache server ,后端跑nginx+resin 。

这个架构,优点就是够简单,如果cache server 不够,就横向扩展,同样简单。

但是,当整个系统的瓶颈不在缓存端时,缺点也很明显了。我发现,后端的load 很容易跑高,特点就是,缓存时间比较短(1 分钟),然后前端的穿透较多,再且,前端的访问很散列,并没有特别的热点。这样,如果作横向扩展,只会对后端的压力越大,因为穿透更多了。

之前去听SACC 2010 的,其实很多公司都用了一层haproxy 做 url hash 。于是,就对现有的架构作一次调整,希望对当时的负载情况有所帮助。

调整后的架构是这样的:最前端是一堆组了lvs 的haproxy ,作用是url hash 到后端的cache 。nginx 其实也是可以做url hash 的,在这里,选择nginx 还是 haproxy 呢,功能上nginx 确实稍胜一筹,但性能上 haproxy 也略优,选择什么也可以按个人爱好来定。呵呵。cache server 端,我也做了小调整,因为不需要只使用一个80 端口了,我一台服务器上跑两个squid 。用taskset 把2 个squid 绑定到cpu1 和 cpu2(默认都是cpu0 ) ,让cpu0 处理系统调用,cpu3 处理网络io 。一台4G 的服务器,在这个情况下已经算是把服务器使用得很尽了。cachedir 一律使用内存分区,不要出现磁盘io 。

但这个架构也不是绝对无敌,url hash 最怕遇到热点,特别热那种,就像110米跨栏决赛和男篮决赛。因为单一的url 并发过高,而导致其中一个cache server 跑满了一个cpu(url hash 把这个url 都调度到这个cache ) ,众所周知,squid 只能使用一个cpu ,这个cpu 跑满载了,请求就会开始阻塞了。然后连接数不断彪高,直接导致了前端的haproxy 也挂了,同时骨牌效应,所有的haproxy 都挂了。。。无奈,只好针对这个url 做特殊处理,rr 分配到后端多个squid ,而不走url hash 了。真是害人不浅阿。。。如果可以预先知道将会是热点的url ,这个问题将会更好解决,而不是要到haproxy 挂了才去处理。

末了,贴一下haproxy 的url hash 配置吧:

global
log 127.0.0.1 local3 notice
ulimit-n 409600
maxconn 102400
chroot /home/haproxy
pidfile /home/haproxy/var/haproxy.pid
user haproxy
group haproxy
nbproc 4
daemon
quiet

defaults
log global
mode http
option httplog
option dontlognull
option redispatch
option forwardfor
option httpclose
option log-separate-errors
monitor-uri /do_not_delete/monitor.txt
retries 3
stats uri /haproxy-status
maxconn 102400
contimeout 5000
clitimeout 50000
srvtimeout 50000
stats auth admin:123456

frontend http_server
bind :80
default_backend info_cache
acl url_static path_end BKM400101.json
use_backend info_cache_temp if url_static

backend info_cache
option httpchk HEAD /live.js HTTP/1.1\r\nHost:\ info.2010.163.com
balance uri len 15 # url hash
server inst1 192.168.51.1:3128 check inter 5000 fall 3
server inst2 192.168.51.1:3129 check inter 5000 fall 3
server inst3 192.168.51.2:3128 check inter 5000 fall 3
server inst4 192.168.51.2:3129 check inter 5000 fall 3
server inst5 192.168.51.3:3128 check inter 5000 fall 3
server inst6 192.168.51.3:3129 check inter 5000 fall 3

backend info_cache_temp
option httpchk HEAD /live.js HTTP/1.1\r\nHost:\ info.2010.163.com
balance roundrobin # rr
server inst1 192.168.51.1:3128 check inter 5000 fall 3
server inst2 192.168.51.1:3129 check inter 5000 fall 3
server inst3 192.168.51.2:3128 check inter 5000 fall 3
server inst4 192.168.51.2:3129 check inter 5000 fall 3
server inst5 192.168.51.3:3128 check inter 5000 fall 3
server inst6 192.168.51.3:3129 check inter 5000 fall 3

其实这个架构只是一个调优,如果整套系统需要优化的话,还是需要从最初的设计入手,很多细节都要顾及。

细节包括,那些数据传输的地址,不要使用163.com 的,因为带了很大串的cookie ,用户每一次访问都带有这么一大串,是很占带宽的。还有根据不同的文件设置不同的缓存,这个最初没有设计好的话,js , css 等文件就混入到163.com 的域名中难以隔离。还需要根据具体的业务去配置一下缓存。业务数据,一定要从一开始就要有系统地收集统计,调优后对比分析。等等等等。。。

在这个架构下,前面的haproxy 只是纯代理,后面的cache server ,可以任意选择,经典一点的,可以用 squid 。或者上varnish ,再或者试用 ATS 。

使用了nginx proxy_cache 引起的io 阻塞

这几天一直忙于解决各类莫名其妙的问题,今天遇到一个使用了nginx proxy_cache 的机器,io 出奇地高,简单处理了一下,简单记录下,没有太详细的数据。

这个nginx 的前面是一堆squid ,它作为一个二级缓存,这样对后端是很有好处的。

开发的同事说,这台机器使用了 proxy_cache 后,io 压力很大。

我粗略分析了一下,分析结果如下:

#vmstat 1

procs ———–memory———- —swap– —–io—- -system– —-cpu—-
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
0  7     68  52720 437416 1325168    0    0     1     2    2    2  0  0 10  1
0  7     68  51916 437528 1325848    0    0     0  4000 2812 2737  0  2 6  90
0  7     68  51868 437624 1325644    0    0     8  3040 2808 2705  1  2 0  99
0  7     68  52540 437596 1325068    0    0     8     510 3040 2841  0  1 1  97
0  7     68  51668 437700 1325964    0    0    60     4033 3479 3220  1  2 5  90

可以看到procs 栏处于b 状态的很多,一般情况下是io 阻塞了

#ps aux

nobody   32622  1.1  0.6 530236 19248 ?        D    23:31   0:12 nginx: worker process

nobody   32623  0.9  0.6 530136 19064 ?        D    23:31   0:10 nginx: worker process

nobody   32624  0.9  0.6 530372 19276 ?        D    23:31   0:09 nginx: worker process

nobody   32625  1.1  0.6 530332 19296 ?        D    23:31   0:11 nginx: worker process

看下nginx worker 的状态,全是D,请求资源阻塞了?

#iostat -x 1

avg-cpu:  %user   %nice %system %iowait  %steal   %idle

0.00    0.00    0.00   16.16    0.00   83.84

Device:         rrqm/s   wrqm/s   r/s   w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util

sda               0.00     8.00  0.00 15.00     0.00   184.00    12.27     0.58   38.67   4.53   6.80

sdb               0.00   611.00  0.00 308.00     0.00  7200.00    23.38    98.31  193.23   2.27  70.00

粗略算一下,峰值io ,也就200r + 100w /s ,对于nginx 来说,这个应该算是中等,不算很高。但 %util 经常在 100.00 左右徘徊,这个就有点异常了。

看看配置吧,改改调调,发现引起问题的是以下这段配置

proxy_cache_path  /data/cache/proxy_cache_dir levels=2:2:2 keys_zone=cache_one:500m inactive=5d max_size=200g;

levels = 2:2:2

也就是nginx 那些缓存下来的文件,会存放到 $CACHE_PATH/[0-9a-f][0-9a-f]/[0-9a-f][0-9a-f]/[0-9a-f][0-9a-f]/xxxxxxxxxxxxxxxxxxxx 里

猜想,会不会是目录层次太多了呢?

改之,levels = 2:2

这里有个重点,改了nginx 配置还不能根治,还需要重建缓存目录。

改完,load 下来了,完成。

其实io 优化的最根本还是用内存分区,不会有io 阻塞。不过我没时间看他的架构,把问题解决了就算了,留个坑给后人吧。

零编码实现非办公网络http 验证

有个需求,需要网站对非办公网络的访问进行验证,办公网络正常访问。
我山寨一下吧,没理由去改php 代码的。
不详说了,直接贴配置(别人贴代码我贴配置。。。)
set $safe 0 ;
location / {
if ($http_x_forwarded_for ~ (x.x.x.x)|(y.y.y.y)|(z.z.z.z) ){set $safe 1;}
if ( $cookie_bad_man = “x” ){ set $safe 1;}
if ($safe = 0){rewrite “^.*$” http://wp.helosa.org/redirect/ redirect;}
index index.html index.php;
root /data/wordpress/;
}
location /redirect/ {
charset utf-8 ;
alias /data/redirect/;
auth_basic “~oO-_-Oo~”;
auth_basic_user_file  htpasswd;
expires -1 ;
set $bad_man “x”;
add_header “Set-Cookie” “bad_man=$bad_man ; path=/; domain=wp.helosa.org”;
}
原理是,如果x-forwarded-for (因为前面有代理)符合办公网络ip ,放行(set $safe 1).
如果$safe 为0,跳转至 /redirect/ 目录
这个 /redirect/ 目录,设置http 验证,验证文件,用htpasswd 建一个吧
如果验证成功,set cookie ,主要是set 一个标示位,在这里是 bad_man ,当见到这个标志位的,也是放行的。
在 /redirect/ 下,有个index.html ,内容可以如下:
<html><body>
<meta http-equiv=”refresh” content=”0;url=http://wp.helosa.org/”>
</body></html>
主要用于跳转。
这样,就可以做到,办公网络不用验证,而在家访问,就要http 验证了。

个人主页上线

开了个个人主页,全手工书写html ,且极其简洁,全英文。

http://www.helosa.org/

写了个nginx module ,第一次写,纯练练手,业务有个需求,想用nginx module 来完成,就试着写一个来练习下先。

这个模块很简单,就是定义返回头的server 的值。以前lighttpd 有个 server.tag 的配置,就是差不多的用途的。

这个模块是在nginx 配置的 server 栏定义的,但直到使用时,我才发现,其实这个模块应该是放在main 那里才合适的。。。呃。。。算了,不改了!

nginx-0.8.42 的一个新feature

nginx 0.8.42 有个新功能:

Feature: a text answer may be added to a “return” directive. (via nginx.org )

这个功能其实很有趣,当然自己写也不难,官方实现了就最好。

找了下,找不到相关的配置说明,只好自己摸索一下吧。一试就出来了,真神奇,哈哈。

三步走(./configure ; make ; make install)安装好 nginx 后,在配置上加一段:

location /iloveu/ {
return 200 “iloveu” ;
}
同时把
default_type  application/octet-stream;
修改为
default_type  text/plain;
如果是前者的话,不会看到字符串,而会下载的噢。
启动 nginx 后,curl -i http://127.0.0.1/iloveu/
HTTP/1.1 200 OK
Server: nginx/0.8.42
Date: Sun, 27 Jun 2010 18:44:04 GMT
Content-Type: text/plain
Content-Length: 3
Connection: keep-alive
iloveu
就这样玩玩吧。

debian 下nginx 快速搭建FCGI环境

我的想法是。。。快点,快点,再快点!!

apt-get install spawn-fcgi php5-cgi

用 spawn-fcgi 启动 fcgi ,

spawn-fcgi -a 127.0.0.1 -p 8000 -u nobody -f /usr/bin/php-cgi -C 5 ;

在 nginx 里配置加一句:
location ~ \.php$ {
fastcgi_pass 127.0.0.1:8000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/nginx/html$fastcgi_script_name;
include fastcgi_params;
}

然后把一个 php 放在 /home/nginx/html 里,就可以使用了。

nginx 实现缓和切换新旧首页

最近首页要改版,瞎折腾,还要新首页和旧首页并行服务,只有网友点击了“新版首页”的按钮后,才会显示新版首页,否则,显示旧版首页。
灵感来自 ayou 的一段配置,我的实现原理如下:

网友点击了切换按钮以后,利用 javascript set 一个 cookie ,如 newindex=y ,首页的 / 会作判断cookie ,然后 rewrite 到相应的页面。

具体实现:
1, 网友点击 set cookie,我抄了一段最简单的东西:

<html>
<head>
<title>Welcome </title>
<script type=”text/javascript”>
function Set_Cookie( name, value, expires, path, domain, secure )
{
// set time, it’s in milliseconds
var today = new Date();
today.setTime( today.getTime() );
/*
if the expires variable is set, make the correct
expires time, the current script below will set
it for x number of days, to make it for hours,
delete * 24, for minutes, delete * 60 * 24
*/
if ( expires )
{
expires = expires * 1000 * 60 * 60 * 24;
}
var expires_date = new Date( today.getTime() + (expires) );
document.cookie = name + “=” +escape( value ) +
( ( expires ) ? “;expires=” + expires_date.toGMTString() : “” ) +
( ( path ) ? “;path=” + path : “” ) +
( ( domain ) ? “;domain=” + domain : “” ) +
( ( secure ) ? “;secure” : “” );
}
</script>
</head>
<body bgcolor=”white” text=”black”>
<center><h1>it is a test</h1></center>
<a href=”#” target=”_blank” onclick=”Set_Cookie( ‘newindex’, ‘y’, 30, ‘/’, ”, ” );window.location.href=’http://www.helosa.org/';”>我要访问新首页</a>
</body>
</html>

2,nginx 配置:

location =/ {

root html ;
index index.html ;
if ( $cookie_newindex = “y” )
{
rewrite ^/*$ /index_new.html break;
}

}

其中 /index.html 是旧首页,/index_new.html 是新首页。
如此一来,网友访问 http://www.helosa.org/ 时, location / 就会根据cookie rewrite 到相应的首页。但是要注意的是,
http://www.helosa.org/index.html
http://www.helosa.org/index_new.html
访问的是正确的页面,因为判断 cookie 只在 / 做。