hadoop集群上捉到linux kernel bug一个 (答读者提问)
首先感谢大家对原文的关注,能和大家一起交流内核技术我非常的荣幸,这里试着回答大家的提问。
超然台上仙:有点不太理解请教一下, “看,这样写完一个文件后,每个page都被makr_page_accessed了两次,也就是说都成了AC TIVE。在2.6.18 kernel里,确实是这样;” 这说明这些page应该是active的,可是后面的修改, “fix这个问题的方案非常简单,就是不要让第14个page有特权,而是让它在被mark_page_a ccessed之前就一直呆在pagevec,别去全局lru链表。” 这样这些page不都成REFERENCED的了么
答:是的,按我的patch的方案,这14个page在被write了两遍以后,都是REFERENCED了。
可能有人要说,文件写了两遍,应该page都是ACTIVE呀。道理上说是这样,但是,pagevec的引入已经造成了“两遍写之后page都是REFERENCED”这个即成事实(当然,还有不均匀的问题),所以我第一次在社区发出这个patch的第一版时,就有人回信说干脆把pagevec去掉得了,但毕竟去pagevec牵扯太多,可能带来的副作用也不好评估,于是最后社区还是决定先收我这个patch,至少先把这14个page弄“平等”,大家都是REFERENCED总好过“前13个REFERENCED后一个ACTIVE“。
等以后哪位内核牛人决定了最终去掉pagevec,我这个patch也就没有存在的必要了。到了那个时候,再也没有不平等的page,而文件在连续的写过(或读过)两遍之后,page们就都是ACTIVE了。
超然台上仙:2.6.18 kernel也同样使用了pagevec,__grab_cache_page中代码意思与32版本是一样的,似乎与文中描述不符
答:你看得非常仔细,我去翻了一下code,发现在upstream的2.6.18内核里,generic_file_buffered_write的逻辑是:
__grab_cache_page()
prepare_write (对应2.6.32内核里的write_begin)
copy content into page
commit_write (对应2.6.32内核里的write_end)
mark_page_accessed(page)
在__grab_cache_page里确实是把page先放入了pagevec,所以,一样会出现page冷热不均的情况(我的patch里有复现这个问题的方法,大家可以试一试)。
但是,redhat的2.6.18是打了补丁的(我上文的2.6.18都是指redhat的),打过之后,__grab_cache_page变成了grab_cache_page_write_begin,这里面就没有用pagevec,而是直接加入全局lru链表了。很可能redhat已经发现了pagevec会带来副作用。
奇怪的是,redhat如果知道了pagevec引入的这个问题,为什么在新的rhel6里没有fix?....这个就不得而知了。
Bergwolf:帅锅,IIUC这个问题的根源是pagevec破坏了active page的公平性,以及readahead window遇到已经存在的page就停下。看了下你的patch,如果在page 14两次mark_page_accessed()之间,有别的page需要加入到LRU,那page 14还是会被置成active。可以想象的场景是,你的test case在多进程并发写的场景下,vm还是出现少量独立的active page的情况。
答:我才发现,确实如你所说!如果用户是用2K的buffer来write且用多进程,那么即使是我的patch也不能完全避免page冷热不均。只是在hadoop上大文件是一次写成,一个page不会被两次mark_page_accessed,也就不会触发而已。
Bergwolf同学果然洞察玄机,拜服了!
相关文章
- 解block层死锁 - 12 19, 2012
- EMC USD组 招聘 - 09 24, 2012
- hadoop集群上捉到linux kernel bug一个 - 08 30, 2012
非常感谢博主耐心回答本人问题。
不过要指出所谓“zc19881024的来信”也是本人发的。。。
你的邮箱和法号也太不统一了,我马上改过来