再见,网易

在这个开玩笑的节日,我做了一个艰难的决定,不是开玩笑,我要离开我工作了三年的网易了。

离职的原因,说到底是环境。三年前,我所在的部门是一个比较懒散的部门,没有统一的规章制度,没有统一的开发流程,没有太多的技术分工,但是部门的人相处起来很开心,就像一家人。其实,这不是一个做事情的部门,单纯从公司的角度去看,这是不好的。但从个人来说,挺开心的。从 09 年7 月部门搬迁到北京以后,一切都开始改变。部门进来很多新人,能力就不评价了,呵呵,我只能说性价比不高。整个部门现在看起来,更像是一个做事情的部门了,也确实做了不少事情出来了。但是,工作环境却越来越压抑。最重要的是,部门已经不再是搞技术的了,搞政治的。但不能不承认,现在的部门是一个做事情的部门,确实做出来不少事情。但一直没有改变的是,这个部门开发出来的东西,一直都是大学生都做得出来的,完全没有一个平台的思想在里面,这一点我讲了无数次,从今天开始,不再需要讲了。我在这个职位做下去,越来越不搞技术了,都是在处理繁杂的事务和需求。或许吧,我会升为一个小组长,但我觉得我仍然需要继续积累。在这个部门,除了处事方式不够成熟,其它方面,我做个小领导足够有余,但是,我仍然钟爱技术,不想搞政治,也不懂,所以,我离开吧。

我再也不用重复地向同一个人解释缓存是什么了。我再也不用面对这种情况:需求方发了邮件后,im 上对我说hi ,然后我还没回复就一个电话打过来对我说,“我给你发了一个邮件”。我再也不用面对着一堆截图,我不能复制上面的文字啊老大。我再也不用担心迟到的问题了!做IT 尤其是做运维竟然有严格的考勤制度!!我再也不用使用windows 了!我解脱了,哈哈

本来,我想离职后,在咖啡店享受一下小人生,写写代码的。还想着一个人去旅行,第一次一个人旅行呢,或者可以改变一下人生观呢。还想着,可能要练一下ios 开发了,现在够热门的嘛,把我的SA 技术放一下,转型去赚钱玩玩。做完这一切再去找工作。不过,貌似这些都会停留在计划了,因为貌似有事情等着我去做了。。。

坦白说,我是充满了怨念地离开的,但是,当离开在即,没有怨念,有点不舍。离开之际,三年的回忆又涌上心头,一幕一幕,虽然周围的同事基本完全换了一批,但不乏可爱的同事,我还是会经常想你们的。我毕业后就一直在网易工作,即使它已经不是我喜欢的当初那个网易了,我仍然会在心里留了一个位置给它,仍然会不时留意它的发展。

再见,网易。

kernel 2.6.32 的服务器作为lvs 的rs 无法建立tcp 连接的问题

最近用xen 的虚拟机作为lvs 的rs 组了一下lvs ,发现上线以后,无法与client 建立tcp 连接,开始还以为是xen 的bridge 网络的问题,后来才把问题定位到系统内核。其实之前也出现过类似的问题的,但当时急着上线,没去研究了,这回太忙,连测试环境都搭出来了,也都没空去深究,今天同事帮我测试了一下,倒是完全明白了。

问题描述:

LVS 用dr 的方式组起来以后,访问vip 时,无法与real server 建立tcp 连接。tcpdump 看到只有client 过来的syn 包,rs 并不返回ack 包,根本无法完成tcp 握手。用curl 来模拟访问测试的话,会看到这样的返回 curl: (7) couldn’t connect to host 。

看看我的配置吧。

lvs director :

采用dr 的调度方式,通过内网把请求分配到real server

lvs 的 real server :

内核为 2.6.32-5-amd64 (2.6.32 这个内核很普遍了,debian 6 和 rhel 6 默认都这个了),不响应arp 配置

echo “1″ >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo “2″ >/proc/sys/net/ipv4/conf/lo/arp_announce
echo “1″ >/proc/sys/net/ipv4/conf/all/arp_ignore
echo “2″ >/proc/sys/net/ipv4/conf/all/arp_announce

其它基本的配置就不说了,如果就这样子起服务后,就会出现我描述的问题了。

原因在于内核的这个参数 : reverse path filtering,这个是啥,我摘抄一下:

Reverse Path Filtering (RPF) is a technology that is used on InternetProtocol routers to try and prevent source address spoofing, which is often used for DenialOfService attacks. RPF works by checking the source IP of each packet received on an interface against the routing table. If the best route for the source IP address does not use the same interface that the packet was received on the packet is dropped. There are some situations where this feature will obviously not be the desired behaviour and will need to be disabled. In general if you are not multi-homed then enabling RPF on your router will not be a problem.

简单地说,就是如果从eth1 接收到包,就不会从eth0 返回,内核把这个包丢弃。

正好我们的LVS 就是这样的服务模式,lvs director 接收到client 对vip 的访问,经过包的重写通过内网把包分配给rs ,rs 直接使用外网返回这个client 的请求。正好就会被rp_filter 给干掉了。

但是,为什么我们以前并没有出现过类似的问题呢??看看rp_filter 的默认内核配置

net.ipv4.conf.eth1.rp_filter = 1

net.ipv4.conf.eth0.rp_filter = 1

net.ipv4.conf.lo.rp_filter = 0

net.ipv4.conf.default.rp_filter = 1

net.ipv4.conf.all.rp_filter = 0

rp_filter 的值的意义是:

814 rp_filter – INTEGER

815 0 – No source validation.

816 1 – Strict mode as defined in RFC3704 Strict Reverse Path

817 Each incoming packet is tested against the FIB and if the interface

818 is not the best reverse path the packet check will fail.

819 By default failed packets are discarded.

820 2 – Loose mode as defined in RFC3704 Loose Reverse Path

821 Each incoming packet’s source address is also tested against the FIB

822 and if the source address is not reachable via any interface

823 the packet check will fail.

0 就是对进来的包完全不作检查,这样有被dos 攻击的风险。

1 就是严格检查,只要不是这个interface 的包,就不返回。

2 就是不太严格,只要本机配置了这个ip ,还是可以返回的。

对于lvs 来说,用2 也是可以的。

只要把eth1 的 rp_filter 的值置为 0 ,lvs 的服务就能正常了。

从这里可以找到答案:http://www.spinics.net/lists/linux-net/msg17162.html

The first patch changed rp_filter from a boolean to an integer, and the

second patch changed the way the interface-specific value and the “all”

value are combined to produce a functional value from a logical AND to

an arithmetic MAX.

Before patches : functional value = interface AND all

After patches  : functional value = MAX(interface, all)

So now if net.ipv4.conf.all.rp_filter=1, source validation is enabled on

all interfaces as their functional value is at least 1. You may either

set net.ipv4.conf.all.rp_filter to 0 (to disable it) or 2 (to enable

loose mode globally), or set net.ipv4.conf.$interface.rp_filter to 2 (to

enable loose mode on $interface).

I guess that the patch suggested by Dave Miller is related to another

(apparently incomplete) change that occured in 2.6.32 :

在2.6.31 , 对于rp_filter 的最终值,有了不同的计算方法。

之前,是只要设置了all.rp_filter 为0 ,那么就是0 了。

之后,看具体的interface 和 all 的值的最大值来取最终值。

默认是 net.ipv4.conf.eth1.rp_filter = 1 和 net.ipv4.conf.all.rp_filter = 0 ,因此,组lvs 的时候,就会丢弃包了。

问题解决!!下次调一下内核参数吧。

PS:可以通过设置这个内核参数来查看一下log

echo 1 >/proc/sys/net/ipv4/conf/<interfacename>/log_martians

64 位linux 上安装svn 1.4.x 的错误

很久没更新了,随便更新一篇吧,2011 年的1 月一篇blog 都没有post 。。。皆因全去做杂事了。做事情的人了,没有技术上的长进阿!

部门内部的svn 用了很旧的版本,1.4.6 了,最近把它迁移到一台64 bit 的机器上,svn 编译不过去,具体报错如下:

cd subversion/libsvn_ra_dav && /bin/sh /home/download/subversion-1.4.6/libtool –tag=CC –silent –mode=link gcc  -g -O2  -g -O2 -pthread    -rpath /usr/local/lib -o libsvn_ra_dav-1.la  commit.lo fetch.lo file_revs.lo log.lo merge.lo options.lo props.lo replay.lo session.lo util.lo ../../subversion/libsvn_delta/libsvn_delta-1.la ../../subversion/libsvn_subr/libsvn_subr-1.la /home/download/subversion-1.4.6/apr-util/libaprutil-0.la -lexpat /home/download/subversion-1.4.6/apr/libapr-0.la -lrt -lm -lcrypt -lnsl  -lpthread -ldl /home/download/subversion-1.4.6/neon/src/libneon.la -lz
/usr/bin/ld: /home/download/subversion-1.4.6/neon/src/.libs/libneon.a(ne_request.o): relocation R_X86_64_32 against `a local symbol’ can not be used when making a shared object; recompile with -fPIC
/home/download/subversion-1.4.6/neon/src/.libs/libneon.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
make: *** [subversion/libsvn_ra_dav/libsvn_ra_dav-1.la] Error 1

其实它也提到了解决方案,recompile with -fPIC ,但。。。我不知道在哪里加……

祭出google 大神,竟然要自己手动改Makefile 。。。

修改 neon/src/Makefie 的 CFLAGS 为 -fPIC -g -O2

困扰了一会,顺便更新一下blog 。

cnnic 证书更新问题

最近为部门内部系统的https 快要过期的证书更新,出现了一系列的问题,很是郁闷!!一个字:恨!!

原来从2010 年 3 月后,由cnnic 签发的证书,有所改变了。2010 年 3 月前,root CA 是 entrust ,中级CA 是cnnic 。3 月后,root 和中级CA ,都是cnnic 了。。。

cnnic 证书本身就没有多少诚信可言了,还做了root CA 。。。

举例说明:

$curl -I https://blog.helosa.org/ 的时候,会有这类报错

curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a “bundle”
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn’t adequate, you can specify an alternate file
using the –cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you’d like to turn off curl’s verification of the certificate, use
the -k (or –insecure) option.

提示是说,加一个-k 的参数,就不会去验证证书了,但我想了解一下原因。它也给了提示,让我们去这个网页http://curl.haxx.se/docs/sslcerts.html 里了解详情。

通读了一次,大概了解了,因为root 和中级CA 都是cnnic ,并且根CA 的证书并不在curl 的信任列表里,curl 认为它是self-signed 证书,不安全,于是就报错了。

解决方案嘛,把cnnic 的root 证书wget 回来,在这里:http://www.cnnic.cn/uploadfiles/cer/2010/3/2/113823.cer

然后curl 时加上这个证书,curl –cacert 113823.cer https://blog.helosa.org/

=====================================================

在这个问题上,我有两个不明白的地方:

1,其实,可以将cnnic 的root 证书加入到信任列表的,信任列表在/etc/ssl/certs/ 里,通过 curl -vv 可以看到

CAfile: none

CApath: /etc/ssl/certs

/etc/ssl/certs/ 里的文件,其实都是软链,软链到firefox 的证书目录吧,这个 /usr/share/ca-certificates/mozilla/ 。

既然如此,那我把cnnic root 的证书扔进去,总可以了吧?结果发现,还是不行的,难道是名字也有要求?格式不对?

2,朋友用mba 的curl 帮我测试,是正常的,是因为cnnic 的root 证书在信任列表吗?日后入手了mbp 再测试!

亚运赛事系统架构探索

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

亚运赛事系统最初的系统架构,非常简单,就是前端用一堆组了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 阻塞。不过我没时间看他的架构,把问题解决了就算了,留个坑给后人吧。

cacti 又不能采集流量了

最近总遇到一些莫名其妙的问题,总要troubleshooting 。

先前cacti 出现过,到了一定流量时,就采集不到了。。。这个实在诡异,即使按照 joecen 说的,把output type id 改为64bit 都无济于事。。。

今天竟然发现cacti 完全不采集了!!在google 大神的帮助下,成功不明所以然地解决了,也记录一下吧。

直接原因是,采集的脚本出错:

执行,/usr/bin/php5-cgi /data/cacti/poller.php

Content-type: text/html
X-Powered-By: PHP/5.3.3

<br><strong>This script is only meant to run at the command line.</strong>

看来与cacti 本身没有关系,是php 执行错误。

祭出google 大神,修改 php.ini 的 register_argc_argv 为 on 。问题解决。

php 文档说,register_argc_argv 这个参数是

Tells PHP whether to declare the argv & argc variables (that would contain the GET information).

呃。。。我不懂 php ,我完全不知情!!^_^

grub 和 grub2 的重建

我的小黑是双系统,windows + ubuntu ,前者用来打游戏或者网上银行,基本很少用。但无奈,最近坏了,重装了个英文版的windows 上去,要重建grub 。grub 和 grub2 的重建会稍有不同,在这里 mark 一下。

开始的步骤都一致,我是用livecd ,也可以用usb 什么的,主要是要个linux 的环境。

grub 的重建:

sudo grub  # 进入grub ,之后的操作在 grub> 的提示符下进行

find /boot/grub/menu.lst # 没有错误的话,就会返回本来装载有grub 的分区,如 (hd0,1)

root (hd0,1) # root 刚才的返回

setup (hd0) # 安装grub

quit # 退出

sudo reboot 即可

###################################

grub2 的重建:

用grub 的方法已经不可行,不过要利用一下grub 的find 功能

sudo grub # 进入grub

find /boot/grub/grub.cfg # grub2 的菜单配置文件不再是 menu.lst ,而是grub.cfg ,没有错误的话,就会返回grub2 所在的分区 , 如 (hd0,1)

quit # 退出grub

(hd0,1) 也就是第一个硬盘的第二个分区,一般是 /dev/sda2

sudo mount /dev/sda2 /mnt # 挂载之前装有 grub 的分区

sudo grub-install –root-directory=/mnt /dev/sda  # 安装grub2

零编码实现非办公网络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 验证了。

我要发牢骚

好像10 月一篇文章都没有发过,好歹发一篇吧,结果就有了以下这篇牢骚。

看见别的部门,连翻墙的费用都可以报销,领导支持。这个我不介意,有些东西不是我可以改变的,但我改变不了并不代表我不能骂吧??你娘亲的(这句是骂那些把考勤当成考核成绩的领导,不是我的直接领导),我每晚工作到两三点,第二天要我准时上班??互联网公司不能弹性工作时间??

我是搞技术的, 不是写报告,写申请单,搞政治的,我不懂人情世故,我不懂勾心斗角,但我觉得,我在技术方面比你懂得多那么一点点,所以,在讨论技术话题时,请你shut up 。当然,如果你在我面前都shut up ,我没有意见。

其实有时候,我只是想静下来写两行代码。