March 2010

LVS hash size

LVS 有个 connection hash table ,默认的 size 为 4096,可以通过以下命令得到:

# ipvsadm -ln
IP Virtual Server version 1.0.12 (size=4096)

简单地说,这个hash table 用于记录每个进来的连接及路由去向的信息。面对庞大的连接时,这个4096是远远不够的,这时就会产生冲突,然后hash table  就不断置换table 中的数据,系统的负荷就这样上来了。所以,很多调优文章都说,要把这个值调大。至于如何调大呢,好像必须重编译内核了。。。

我的是 centos 5.4 final ,利用 srpm 去重编译吧,使用当前系统的 config ,这样编译后的内核只不过是改变了 hash table 的值,并没有改变其它的东西。

下一个 kernel 的 srpm :http://mirrors.163.com/centos/5.4/os/SRPMS/kernel-2.6.18-164.el5.src.rpm

重编内核时,把原来的 config(/boot/config-2.6.18-164.el5) copy 覆盖 SOURCES/kernel-2.6.18-x86_64.config .

把第一行的

#

改为

# x86_64

同时,修改 CONFIG_IP_VS_TAB_BITS=12 (2的12次方,4096)为 CONFIG_IP_VS_TAB_BITS=20 。

然后 rpmbuild -ba –target=`uname -m` kernel-2.6.spec ,新编译出来的kernel-2.6.18-164.el5.x86_64.rpm 就在 RPMS/x86_64/ 里了。

rpm -Uvh 吧。

reboot 后,再 ipvsadm -ln 就可以看到

IP Virtual Server version 1.2.1 (size=1048576)

成功!
lvs 调优的文章通常会说,如果你的并发连接数是 200,keep alive 是200秒,那么hash table size 就应该设置为不要低于 200×200=40000 太多,2的15次方32768 就差不多了。不过,谁知道我们的需求是否会变呢?我一般都懒得算,直接开到最大,20 就是最大的了。

还需要注意一点,就是每个连接是要占用内存的,印象中是每个连接占用136 bytes ,尽管说 lvs 可以抗百万级别的连接,也要注意有没有足够的内存哦,呵呵。

利用 piranha 快速搭建 lvs

最近为那个公司很重视的项目搭建 lvs ,在这里 log 一下吧。

利用red hat 提供的 piranha ,简单快捷。

我选择的是 centos 5.4 ,安装 piranha ,很简单

yum install piranha

此时,它还需要你安装 ipvsadm , php , php-cli , php-common , httpd ,piranha 是一个 web 管理的工具,没办法,虽然我不用web 界面,但这些在yum 下还是必须装上的。

装完以后,/etc/sysconfig/ha/lvs.cf 还是空的,我去抄一份过来。

serial_no = 1
primary = 60.12.227.1
service = lvs
backup_active = 1
backup = 60.12.227.2
heartbeat = 1
heartbeat_port = 10001
keepalive = 6
deadtime = 18
network = direct
debug_level = NONE
virtual vs[1] {
    active = 1
    address = 60.12.227.200 eth0:200
    vip_nmask = 255.255.255.0
    port = 80
    send = "GET / HTTP/1.0\r\n\r\n"
    expect = "HTTP"
    use_regex = 0
    load_monitor = none
    scheduler = wlc
    protocol = tcp
    timeout = 6
    reentry = 15
    quiesce_server = 0
    server rs[1] {
    address = 192.168.0.1
        active = 1
        weight = 2
    }
    server rs[2] {
    address = 192.168.0.2
        active = 1
        weight = 2
    }
}

到此,lvs 的 director 端,算是安装完成了。

有人会问了,为什么我没有修改 /proc/sys/net/ipv4/ip_forward 为1 。其实,这里我也还不是很懂,理论上,转发是必须设为1 的,但我发现,貌似不设,也可以正常工作,难道是 piranha 的关系??

然后就是配置 real server 端了。

我又抄一个shell 过来

#!/bin/sh
 
VIP=60.12.227.200
/sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up
 
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

由于我的director 端配置的是 dr 模式,所以必须关闭arp 响应。

执行一下这个shell,real server 端也算是完成了。

启动 director 端:

# /etc/init.d/pulse start
Starting pulse:                                            [  OK  ]

查看服务状态:

# ipvsadm -ln
 
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  60.12.227.200:80 wlc
-> 192.168.0.1:80             Route   2      326        172
-> 192.168.0.2:80             Route   2      326        192

搭建完成了,算是比较快速的了,呵呵。还有一点知识点的,下回再说吧。

Protected: “cms 很重要”

This content is password protected. To view it please enter your password below:

零编码 nginx + html 实现山寨版url shorten 服务

nginx 有个 memcache 的模块,可以读取 memcache 里的数据。但这个模块很简单,只能get,不能set。如果要set 就必须依靠别的方式了。

今天浏览一下nginx wiki module 的时候,发现国人写了一个功能稍多一点的模块,叫 memc_module ,几乎已经实现了 memcache 的所有tcp 协议。
路过见到,那我就玩玩啦,尝试下不用动态语言实现 url shorten 。

安装 memc module ,按照wiki 上面说的安装吧。

启动 memcache ,memcached -d 。

nginx 配置下,然后启动nginx

location / {
root   html;
index  index.html index.htm;
rewrite “^(.*)$” /hello?key=$1 last;
}

location /hello {
memc_pass 127.0.0.1:11211 ;
set $memc_key $arg_key ;
}

写html ,写个form 吧,用 post 把原始的url 提交给 nginx ,然后nginx 在对 memcache 做set 操作。这个是 value 部分,还有一个key 的部分,可以用js 生成一个随机数提交。
这里,我用curl 模拟一下这个 form 的动作,其中,就当我的随机数是 hello 吧
curl –data “<html><body><meta http-equiv=\”refresh\” content=\”0;url=http://blog.hellosa.org\”></body></html>” http://127.0.0.1/hello?key=/hello

在这句话里,
key 是  /hello
value 是 <html><body><meta http-equiv=”refresh” content=”0;url=http://blog.hellosa.org“></body></html>

然后,我们访问 127.0.0.1/163 是,就会跳转到我的blog首页了。

哈哈,url shorten 的服务就是这样实现了,实在有点山寨!

ssh-agent 的安全隐患

ssh 是SA 的一大利器,登录服务器、翻墙。。。ssh 通常都配合着 ssh-agent 来使用,ssh-agent 是个管理 private key 的 passphrase 的工具,启动 ssh-agent 后,执行一次 ssh-add ,此时需要输入一次 private key 的 passphrase ,输入正确后,passphrase 就归 ssh-agent 管理,往后的 ssh 操作,就不需要询问 passphrase 了。这里需要注意,ssh 必须开启了forwardagent ,一劳永逸的方法,就是在 /etc/ssh/ssh_config 中把#ForwardAgent no 去掉注释,并改为 ForwardAgent yes。

重点说说它的安全隐患。

ssh-agent 工作过程中会创建一个 socket 文件在 /tmp 目录里,如 /tmp/ssh-jlhtX14952/agent.14952 。我们需要使用 ssh-agent 时,运行一下 ssh-add ,把 private key 加入到 ssh-agent 中管理,此时,是需要输入一次 passphrase 的,当输入正确了以后,往后都不需要输入 passphrase 了。任何用户,只要连接上这个socket ,就可以使用已经加入到ssh-agent 管理的 private key 了,而且不需要输入 passphrase 。所以,这个 socket 的权限是 600 ,如:

srw——-  1 raymond raymond 0 May  1  2009 /tmp/ssh-jlhtX14952/agent.14952
但是。。。我们的 root ,是可以随意访问的。。。
这里演示一次!
1,用root 连接socket,这里很简单,就执行一句话
# SSH_AUTH_SOCK=/tmp/ssh-jlhtX14952/agent.14952; export SSH_AUTH_SOCK;

2, 查看此 socket 是否已经加入了 private key
# ssh-add -l
1024 fa:2d:87:1a:c5:a6:9d:7c:67:eb:51:a3:6a:7b:49:34 /home/raymond/.ssh/identity (RSA)
看,raymond 的 key 已经加入进去了

3,尝试登录raymond 的服务器,以root 的身份,但使用 raymond 的 key
# ssh raymond@220.181.xxx.xxx
Last login: Sat Mar  6 04:41:55 2010 from 220.181.xxx.xxx
[raymond@VM ~]$ whoami
raymond
看,此时,已经是以raymond 的身份登录的服务器了

resin 在debian testing下的ipv6 问题

最近装的resin 3.0.x 都很不顺利,经常起不来,jvm.log 爆出这样的错:

Can’t connect to parent process through socket 48403
Resin needs to connect to its parent.

resin 3.0.x 大概是这样的工作机制的,起一个perl 作为一个master process ,这个master process 再负责起一个jvm 负责处理java 请求。而log 中的意思,就是 jvm 无法与这个master process 连接通讯,结果就起不来了。

国外也有朋友与我同样的问题呢:http://bugs.caucho.com/view.php?id=350

后来我看到这篇文章 http://people.debian.org.tw/~chihchun/2010/02/03/connectivity-issue-of-java-with-ipv6/,觉得终于找到正解了!

大概的意思就是,jvm 是支持ipv6的,可惜一般情况下,debian 会启动 ipv6 的 network interface ,但是,并没有其相应的路由,这样,java 就找不到路去连接 parent process 了。

既然是ipv6 的问题,剩下的问题就是如何关闭ipv6 了。

以下这个帖子比较全,linux 下n种禁用ipv6 的方法:http://hi.baidu.com/ramboo0913/blog/item/71efa09959ddcb0b6f068cc8.html

但是,这些方法,只是关闭以模块的形式载入内核的ipv6,如果已经把ipv6 编译进内核,那以上的方法都是不奏效的。我的debian 通常会升级到 testing ,很不幸,ipv6 已经在内核中了。可以这样查看,uname -a 看一下我使用了哪个内核,结果是“2.6.30-2-amd64” ,然后去 /boot/ 中,查看config-2.6.30-2-amd64 这个文件,这个文件记录了编译内核的参数,会见到 “CONFIG_IPV6=y” ,证明ipv6 已经编译进内核了,如果是模块的话,应该是“CONFIG_IPV6=m” 的。

其实判断ipv6 是否以模块的形式载入,很简单。

命令 ip addr | grep inet6 有输出,但是 lsmod | grep ipv6 却没输出,证明了ipv6 已经编译进内核了。

那这种编译进内核的情况,如何解决呢??google 告诉我,修改 /boot/grub/menu.lst ,把

kernel          /boot/vmlinuz-2.6.30-2-amd64 root=/dev/cciss/c0d0p1 ro

改为

kernel          /boot/vmlinuz-2.6.30-2-amd64 root=/dev/cciss/c0d0p1 ro ipv6.disable=1

reboot 即可。

其实还可以在线地关闭ipv6 ,运行命令

$sudo /sbin/ip addr del <ipv6address>/<prefixlength> dev ethX

文中还提到一个方法,就是在resin/bin 下,修改wrapper.pl,在

#
# Additional args to pass to java after command-line args.
#

后,加一句

$EXTRA_JAVA_ARGS="-Djava.net.preferIPv4Stack=true";

这样也就默认使用ipv4了。

其实文章已经说得很明白的了,我只是稍微简化一下,觉得不能理解的,还是参看一下原文吧。

祭出google 大神无数,终于解决问题。我这个SA 啊,就是一个靠google 混饭吃的。。。

———————————————–

updated :

新装的 debian 的内核参数,都是

net.ipv6.bindv6only = 1

的,而旧的都是

net.ipv6.bindv6only = 0

这样就解释了为什么resin 一启动就要 ipv6 了,但可以找不到 ipv6 的路由。。。sign….