01 2013存档

想测一测Cubieboard最多能支撑多少tcp长链接(当然,是比较空闲的链接)。

我的cubieboard上安装的是linaro(其实就是linux),首先得调节单个进程打开的句柄数(修改/etc/security/limit.conf),然后还要修改sysctl里tcp_mem等网络参数(具体配置可以参考这里 1, 2) 然写了一套简单的TCP链接客户端和服务端的代码。Server端用epoll模型; Client端创建500个链接然后把fd放入数组里,每个connection每5秒发送128字节。
开始测试时,在cubieboar上我分别对5个端口启动了5个Server,客户端(我的笔记本)则是用脚本不停的创建Client实例。
测试结果:cubieboard可以支撑到10万个tcp长链接,网络流量稳定保持在3.75MB/s,此时系统内存还有大约300MB free(总共1G),CPU idle在20%左右
cubieboard只有网口没有网卡(也就是没有network controller),所有的收包解包都由CPU完成,所以能支持的流量比较有限,不过撑个10万的闲链接还是没问题的。

还想了解一下cubieboard对https的支撑能力,于是我又在cubieboard上装了tengine(在arm上编译还挺顺利,连warning都没有,编译时间4分钟24秒),配上https签名(参加这里)再用ab压力测试,ab压测脚本是:
ab -n 20000 -c 20 -k url
测试结果:访问https的QPS为755, 访问http的QPS为1269

看来用cubieboard搭个小网站是绰绰有余了,一个小的聊天服务器兴许也可以。


====== 2013.1.28 ======

应 @pythonee 同学的要求,测试了200个并发:

ab -n 20000 -c 200 -k url

测试结果:访问https的QPS为858,访问http的QPS为1741,毕竟是单核,提升不明显,压测的时候CPU idle已经为0了
我另外还试了一下把openssl的签名长度改为512bit,以减轻CPU的压力,再测https,QPS可以到959,当然,签名长度再短,QPS也不可能高于http的1741了

cubieboard

皓庭同学在给一台测试机做压力的时候出现了kernel panic:

<4>[  223.202997] RIP: 0010:[<ffffffff81194e79>]  [<ffffffff81194e79>] iput+0x69/0x70
......
<4>[  223.210475]  [<ffffffffa007de6d>] ext4_free_io_end+0x2d/0x40 [ext4]
<4>[  223.210864]  [<ffffffffa007e02c>] ext4_end_aio_dio_work+0xac/0xf0 [ext4]
<4>[  223.211277]  [<ffffffffa007df80>] ? ext4_end_aio_dio_work+0x0/0xf0 [ext4]
<4>[  223.211693]  [<ffffffff8108cc50>] worker_thread+0x170/0x2a0
<4>[  223.212033]  [<ffffffff810925c0>] ? autoremove_wake_function+0x0/0x40
<4>[  223.212425]  [<ffffffff8108cae0>] ? worker_thread+0x0/0x2a0
<4>[  223.227238]  [<ffffffff81092256>] kthread+0x96/0xa0
<4>[  223.241935]  [<ffffffff8100c10a>] child_rip+0xa/0x20
<4>[  223.256518]  [<ffffffff810921c0>] ? kthread+0x0/0xa0
<4>[  223.271085]  [<ffffffff8100c100>] ? child_rip+0x0/0x20

重现的环境和步骤都很简单:只要在redhat linux-2.6.32-279.14.1 kernel上进一个使用ext4的目录一跑:

stress --cpu 2 --io 2 --vm 1 --vm-bytes 128M --hdd 2 --timeout 1d

几分钟后就出现。
这个stress工具果然是神器。
由于重现步骤简单,我也没有太多需要绞尽脑汁的猜测和bug重现工作,就是加trace_printk一点一点调试,最后找到了原因:

stress测试工具是用DIRECT_IO发起的aio(异步IO)请求,在ext4里对于DIRECT_IO请求,都会用ext4_init_io_end初始化一个ext4_io_end_t结构,初始化时调用igrab对该inode里面的i_count进行递增;

struct inode *igrab(struct inode *inode)
{               
        spin_lock(&inode_lock);                                                    
        if (!(inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)))
                __iget(inode);
        else {  
                /*
                 * Handle the case where s_op->clear_inode is not been             
                 * called yet, and somebody is calling igrab
                 * while the inode is getting freed.
                 */          
                printk("%s: %lx\n", __func__, inode->i_state);                     
                inode = NULL;
        }
        spin_unlock(&inode_lock);
        return inode;
}       

这些aio结束后,会调用ext4_free_io_end进而调用iput把inode的i_count递减,等到i_count递减到0时,就用iput_final把该inode置为I_CLEAR,意思是该inode可被清除了(当内存不够的时候会把这种I_CLEAR的inode占的内存空间回收)。
但是,如果一个文件已经被rm了,即已经调用了generic_delete_inode,那么inode就已经置上了I_FREEING,此时再调用igrab时,由于第一个判断无效,inode里的i_count就不会被加1了,i_count会一直保持0!等到aio结束后,iput被调用了多次,第一次触发iput_final把inode置上I_CLEAR,第二次就坏了,触发BUG_ON

void iput(struct inode *inode)          
{                                                                            
        if (inode) {                                                               
                BUG_ON(inode->i_state == I_CLEAR);              
                              
                if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
                        iput_final(inode);
        }                                                                          
}

因为一般对同一个inode,调了iput_final就不能再调iput了,因为你已经final了、没了。

说来说去,就是igrab似乎不该做那个判断,或者,干脆不要用igrab,用别的计数方式。翻了一下upstream,得,又已经被fix了,commit f7ad6d2e9201a6e1c9ee6530a291452eb695feb8, Ted两年前就已经fix了,抛弃了igrab改为自己管理计数。这个fix backport到rhel-2.6.32-279 kernel还需要一些修改,好在有文卿帮我review代码。

还要感谢皓庭同学帮忙找到了这么快速的重现方法,以及余峰老哥推荐的stress这个生猛工具。


====== 2013.1.18 ======

很不好意思,patch的标题写错了,还请忽略标题,我回头再改,patch内容是对的。

2012年读书

| | Comments (2) | TrackBacks (0)
今年就读了12本书,已经出乎我的意料了,因为所有业余时间都在陪宝宝,只能趁她睡午觉时偷偷看看书或者看个片。

年度收获最大的书 —— 《The Wild Wheel》在米塞斯学院的网站找到了这本免费电子书(必须免费,这是1940年代的书),Henry Ford可能是美国最后一个纯自由主义派的企业家了,他的关于流水线生产、关于资本与利润、关于机器与人、关于大萧条的很多观点,现在看来都如此先进如此特别。

年度最感慨的书——《Jurassic Park》,够怀旧




关于存档

This page is an archive of entries from 01 2013 listed from newest to oldest.

12 2012 is the previous archive.

02 2013 is the next archive.

Find recent content on the main index or look in the 存档 to find all content.