06 2012存档

某些开发测试团队会有这样的需求:多个开发或测试人员在一台物理机上搭环境、装rpm包、测试等,目录很可能互相干扰。避免干扰的最直接办法当然是装虚拟机,但是如果仅仅只是想把根目录隔离一下,而不需要隔离CPU和内存,那么虚拟机方案偏重了些。
所以,我们做了一个叫troot的小工具,每个人都可以自己创建一个虚根目录,然后进入这个虚根目录工作,工作起来感觉就像一个全新的跟别人互不干扰的新根目录一样。

不过这个troot的主要实现是靠overlayfs,也就是说,必须用淘宝linux-kernel,淘宝linux-kernel源代码的git库在 http://kernel.taobao.org/git/?p=taobao-kernel.git;a=summary

而troot本身只是个小shell脚本而已,代码在这里:


制作troot的rpm方法是:
svn co http://code.taobao.org/svn/troot/trunk troot
cd troot
sh rpm/troot-build.sh `pwd`


装上淘宝linux-kernel和troot以后就可以用了,用法:

troot list #显示本机已经创建的根目录,第二栏显示当前处于哪个根目录
troot create world1 #创建名为"world1“的根目录
troot enter world1 #进入名为"world1"的根目录,进入以后,就可以随意写文件了
#直接敲入exit就可以从根目录中退出

欢迎感兴趣的同学试用反馈
经过几个月的线上测试,ext4 bigalloc的测试报告终于出炉,我发复取了n多次的数据(这些去数据的过程最后都被我磨成bash脚本了),感谢刘亮同学和桑彦斌同学对CDN上线的支持,感谢柯旻同学和刘毅同学对hadoop线上的支持,还要感谢coly一遍又一遍的reivew报告和逼着我一遍又一遍的采集线上数据并作图(此公开版拿掉了图)。

测试报告(由于是从word文档改的,字体较小,可能需要全屏;部分内容由于公司政策不予显示,此保密政策是“量子时代”要求的,大家勿直接喷我):


hadoop与午睡

| | Comments (2) | TrackBacks (0)
这一阵子在折腾hadoop集群上linux kernel的优化,开始没机器,只好悲惨的用虚拟机来装,但是kvm虚拟机又不给力,虚拟机之间死活连不上,最后终于等到柯旻同学婚假归来,支援了我几台线下测试机,刘毅同学帮我搭了环境,终于可以见到活生生的hadoop运行状态。

接下来是两周的运行观察和调试。

目前为止最大的进展是揪出一个2.6.32(upstream也有)的一个pagevec引发的性能退化,见patch

然后,考虑到hadoop里,源数据一般只读一次,目标结果也只写一次,cache没什么用,所以我们很想试试新版带有cache抛弃功能(所谓的drop-behind)的hadoop,我看hadoop-0.23.1有此功能,于是想在测试集群里跑起来。

没想到hadoop-0.23.1比0.19变了那么多,配置文件的名字变了、配置项变了、连resource manager也变了,我在网上翻了不少文章,试了好多配置方法,hadoop的log报了不少WARN(无非都是某些配置项名字变了),好像这些WARN也不影响运行,但最后却只能在单机上跑任务....诸多毛病,我折腾了两个工作日外加一个周末,还是没能把最基本的terasort在多机上run起来....这五个白天看了不知道多少hadoop那无病呻吟却又提供不了多少帮助的log。

昨天(星期天)睡午觉,梦见早上起床要去上班,提起裤子准备穿,突然发现裤子上有妈妈绣的字:”WARN:此裤子颜色已经发旧,不要再穿“,我心想,不就是”WARN“嘛,又不是”ERROR“或者”FATAL“,于是我还是把裤子穿上了。等到醒来,不禁失笑。

今天早上,找到了吴威同学,还是专家有办法:别再搭郁闷的hadoop-0.23.1了,搭cdh3u4!吴威同学三下五除二把cdh搭好,我终于能跑上terasort测试了。

前年我去考过一次雅思,口语的考官是个面无表情的瘦高个儿,老外,非常非常的面无表情,我回答了一堆东西,他每次都只问一个字:“Why?“...“Why?”...“Why?“,我当时真想抓起桌上的电子钟砸他脑袋上去——你他妈哪来那么多的Why! 无奈考雅思就是求老外,我当然不敢动手。至今想起来,依然忿忿不平,唉,只要国内的食品略安全一点,我也用不着一把年纪了还背单词学英语(我读书时背得够累的了)、还得看这老外考官的脸色。

今天在组内群里发了娃的照片



涛哥: 你娃这么小就考雅思呵

我: 这你都看出来了

涛哥: 10天突破系列啊

我: 唉,10天是突破不了的,尤其是像我这样7年都在民企干,一点读、写、说、听英语的机 
       会都没有的人

文卿: 请参加ext4 weekly conference call

我: 雅思口语是不会考文件系统的

文卿: 但是会考你跟人扯淡

我: 雅思口语一般是问 “你最近最爽的一次散步是在哪里,跟谁散的,你们聊了什么,为什么 
        你觉得很爽” 一类的问题,然后接下来考官就一脸的木然,不停的问“why?..why?..why?”

文卿: 我最爽的一次是在google compus跟Ted散的,聊了ext4,因为我和他握了爪,所以爽 :)

我: 如果我是雅思考官,我就会继续问:“Why you feel happy when catching Ted's claw?"

文卿: because he is a well-known man in ext4 community.

我: why you want to catch a ext4 fellow's claw?

文卿: His claw can make me happy.

我: Why his claw could make you happy?

文卿: that was a long time ago. When I was a frehman in my university, I firstly hear his name and blabla ....

我: ....看来你能通过口语考试,我反正是不行了

为了监控上线的新内核,我们把google的netoops backport到了自己的内核,生产上如有kernel panic,会将panic的栈信息发送到日志服务器,方便调试和修复。

前天,洪川同学报告说以前线上的netoops都是把bond的slave网口作为发消息的dev,新上线2.6.32-220内核后,启动netoops失败,系统报:

”eth0 is a slave device, aborting."

找了一下从 2.6.32-131 到 2.6.32-220 的redhat的变动,发现了王聪同学的这个patch:


commit 0c1ad04aecb975f2a2014e1bc5a2fa23923ecbd9
Author: WANG Cong <amwang@redhat.com>
Date:   Thu Jun 9 00:28:13 2011 -0700

    netpoll: prevent netpoll setup on slave devices
    
    In commit 8d8fc29d02a33e4bd5f4fa47823c1fd386346093
    (netpoll: disable netpoll when enslave a device), we automatically
    disable netpoll when the underlying device is being enslaved,
    we also need to prevent people from setuping netpoll on
    devices that are already enslaved.
    
    Signed-off-by: WANG Cong <amwang@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 2d7d6d4..42ea4b0 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -792,6 +792,12 @@ int netpoll_setup(struct netpoll *np)
                return -ENODEV;
        }
 
+       if (ndev->master) {
+               printk(KERN_ERR "%s: %s is a slave device, aborting.\n",
+                      np->name, np->dev_name);
+               return -EBUSY;
+       }
+
        if (!netif_running(ndev)) {
                unsigned long atmost, atleast;
 

从此,netpoll就无法使用slave设备了(netoops用的就是netpoll),不过我奇怪为什么以前可以现在又不行了,所以发邮件问了王聪同学为何现在不能使用slave设备,回答是:

“因为slave设备没有IP地址,http://wangcong.org/blog/archives/1657”

而且王同学在redhat搞netconsole也遇到了同样的问题,只能改用master网口。
我们的netoops也只能遵循同样的规则,统一改用 bond0做dev。

上个月,生产服务器上报来了内核bug:

 ------------[ cut here ]------------
 kernel BUG at mm/mmap.c:2352!
 invalid opcode: 0000 [#1] SMP
 last sysfs file: /sys/devices/system/cpu/cpu23/cache/index2/shared_cpu_map
 CPU 13
 ....
 [<ffffffff8105fb55>] mmput+0x65/0x100
 [<ffffffff81066605>] exit_mm+0x105/0x140
 [<ffffffff810667ed>] do_exit+0x1ad/0x840
 [<ffffffff81078680>] ? __sigqueue_free+0x40/0x50
 [<ffffffff81066ec1>] do_group_exit+0x41/0xb0
 [<ffffffff8107ccf8>] get_signal_to_deliver+0x1e8/0x430
 [<ffffffff8100a554>] do_notify_resume+0xf4/0x8a0
 [<ffffffff811f82f6>] ? security_task_kill+0x16/0x20
 [<ffffffff8107a992>] ? recalc_sigpending+0x32/0x80
 [<ffffffff8107ad15>] ? sigprocmask+0x75/0xf0
 [<ffffffff8107ae11>] ? sys_rt_sigprocmask+0x81/0x100
 [<ffffffff8107ad15>] ? sigprocmask+0x75/0xf0
 [<ffffffff8100b301>] int_signal+0x12/0x17

原因就是 exit_mmap 函数最后一行的BUG_ON被触发了(我们用的是 2.6.32 内核)

void exit_mmap(struct mm_struct *mm)
{
....
        BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT);
}

[ 这个 (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT 其实就是0 ]

从代码直观能想到的就是进程在退出的时候pte没有释放对,或者nr_ptes计数漏了,导致最后一步nr_ptes没有变成0。
想归想,这个非常难重现。但是很快,好运来了,同事在开发cgroup的过程中无意中也触发了了这个BUG_ON,触发的方法是在 __mem_cgroup_uncharge_common 函数里加了一对 down_read/up_read (除了这一对,没有任何别的操作)。于是我开始想象:这一对 down_read/up_read 没有做任何与page或者pte相关的事情,却引起 nr_ptes计算出错,那八成是这一对锁的添加触发了原来的某个race condition,最终导致 nr_ptes 没有计算对。
于是,我沿着这条思路,顺着 exit_mmap 一路 trace_printk ,终于发现是在 page_remove_rmap() 前后nr_ptes开始不对,调用路线还挺深(花了不少力气才找到):

--> exit_mmap
  --> unmap_vmas
    --> unmap_page_range
      --> zap_pud_range
        --> zap_pmd_range
          --> zap_pte_range
            --> page_remove_rmap

为什么是 page_remove_rmap ? 又花了两天才发现,原来exit_mmap里用到了 tlb_gather_mmu/tlb_finish_mmu,就是把要清空页表项的page暂存在一个 struct mmu_gather 里,然后在tlb_finish_mmu时统一清空页表,以提高性能。2.6.32内核里的这个 struct mmu_gather 是per cpu变量(每个cpu一个),这就意味着在 tlb_gahter_mmu 和 tlb_finish_mmu 之间进程不能切换CPU,否则拿到的 struct mmu_gather就可能是另一个CPU上的变量,那就彻底不对了(upstream为了支持抢占,已经将mmu_gather改为 stack argument)。糟糕之处就在于,page_remove_rmap调用了mem_cgroup_uncharge_page进而调用了__mem_cgroup_uncharge_common,而我们在里面加了一个down_read,而down_read里有一句might_sleep(),结果,进程睡眠了,等他醒过来,可能已经身处另一个CPU,于是mmu_gather拿错了,于是nr_ptes不对了....(其实我挺好奇:为什么down_read里要加一句might_sleep?求高手解答)

花了三天辛辛苦苦的找,最后发现不是race condition,就是自己加的down_read造成的问题。
但是毕竟,生产报来的bug是没有这一更改的,那就是另有原因,还得查。

上周刘峥同学给了个链接 https://lkml.org/lkml/2012/2/15/322 ,看来redhat也遇到不少exit_mmap BUG_ON(),不过他们发现是Transparent Huge Page造成的,咱们报bug的生产服务器上并没有用到THP,还不是一个问题。不过,我总体感觉,进程退出的代码路径里,这个 BUG_ON(mm->nr_ptes > 0) 是最后一关,结果成了bug触发的汇集处,很多别处的甚至不是mm相关的代码错误都可能触发这个BUG_ON,比如这个 https://lkml.org/lkml/2012/5/25/553

后来,生产服务器从 2.6.32-131 升到 2.6.32-220 后,再没报过这个BUG_ON,至于终极的原因....可能是mm部分的bug fix,也可能是某个驱动的升级,这个,只有redhat知道了

关于存档

This page is an archive of entries from 06 2012 listed from newest to oldest.

05 2012 is the previous archive.

08 2012 is the next archive.

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