flashcache支持资源隔离的改造

去年年底的时候对flashcache做了一番研究,并进行了改造,所谓改造,其实就是希望它能支持cgroup,也就是说,当有在不同cgroup里运行的进程对flashcache进行读写时,flashcache能根据cgroup的不同权重分配这些进程以不同的iops(IO per second)。详细的资料在这里:《flashcache原理及改造》

事情还没有结束,现在能给flashcache设备设io-scheduler了,设成cfq就可以按cgroup weight来分配iops,但是,做为稀缺资源的ssd设备,其cache空间并没有像IOPS那样按比例分配给各个cgroup,所以,今年,我继续把“cache空间按cgroup比例分配给进程”的功能做完了。patch系列在这里

原理:flashcache按hash把io缓存到ssd设备的不同的LRU链表上。我加了一个“struct flashcache_group”,将cgroup的信息存入其中,同时由它来管理”子LRU“。比如,有4个cgroup的进程在对flashcache做读写,那每个LRU都要被拆成4个由"struct flashcache_group”管理的”子LRU“,每个“子LRU”所用的cache空间的大小(即flashcache所谓的block的个数),就是由它所在的cgroup的权重决定的。
当flashcache设备刚初始化好时,所有的“子LRU”都是空的,cache都在根group的手中(正好对应cgroup里的root group概念),一旦有进程的IO来了,才根据它所在cgroup的权重,慢慢将block划入它所属的”子LRU“(当然,不能超过最大比例);当该进程退出后,cgroup即被destroy,于是,对应的”子LRU“也会将自己占的cache返还给”主LRU“。

由于这些改动不仅涉及flashcache本身,还要牵扯kernel里很多block层的代码,所以,目前还不能单独提交给flashcache社区,只能先保留在ali_kernel里,想试用的同学,可以用如下方法:

1. 下载ali kernel的代码并编译dev分支,然后安装内核并重启机器

git clone git@github.com:RobinDong/ali_kernel.git
git checkout -b dev origin/dev
make localmodconfig #根据自己机器的硬件情况选择config文件
make -j20
make modules_install
make install
vim /etc/grub.conf #修改grub以启动ali kernel
reboot

2. 进入ali kernel后,下载flashcache工具并编译stable_v2.1分支

git clone git@github.com:RobinDong/flashcache.git
git checkout -b stable_v2.1 origin/stable_v2.1
make

3. 使用编译的flashcache工具创建设备(加"-r"参数以确保flashcache进去request base模式)

src/utils/flashcache_create -p back -r cachedev /dev/rxdrv /dev/sdf

咱们接着用以下fio文件做个测试:

[global]
direct=1
ioengine=libaio
runtime=60
bs=4k
rw=randwrite
iodepth=8
filename=/dev/mapper/cachedev
numjobs=1

[group1]
cgroup=test1
cgroup_weight=1000

[group2]
cgroup=test2
cgroup_weight=800

[group3]
cgroup=test3
cgroup_weight=600

[group4]
cgroup=test4
cgroup_weight=400

测试结果:

cgroup IOPS
test1 684
test2 581
test3 425
test4 264

再看看SSD设备里block的分配情况:

cat /proc/flashcache/rxdrv+sdf/flashcache_blocks

Group		Weight		Block Count
/test2		800		54865
/test1		1000		68582
/test3		600		41149
/test4		400		27433

看来cache空间的分配比例还是很准确的

nginx关闭上传文件的缓存

nginx-1.5.7做前端,一个c语言写的deamon用fastcgi做后端。同时上传多个大文件的时候,报了"Internal Error“,查看发现是/usr/目录满了。仔细一查,是因为我把nginx装到了/usr/local/nginx下面,结果,nginx默认会把上传文件缓存到 /usr/local/nginx/client_body_temp/ ,结果爆了。

于是,漫长的google之旅开始了。查了很多文章,有人说加一个"fastcgi_buffering off;“,试了不行,又有人说还要加"proxy_buffering off;”,试了还不行。然后是nginx的官方wiki说可以用HttpUploadProgressModule来做,我装上以后发现这玩意儿就是用来显示上传进度的,跟缓存不缓存一点关系也没有,或者是我弄错意思了?(http://wiki.nginx.org/Faq)

Q:Can I disable the buffering for upload progress? // How can I display upload progress on the client side?

A: These are both very frequently asked questions.
   Currently the only solution is the third-party module Nginx Upload Progress.
   (This functionality is planned for a future release of Nginx.)

最后找到这篇,显然有很多人遇到了跟我一样的问题,从里面"Weibin Yao“的回答来看,tengine已经加了方便这一功能的补丁。"Weibin Yao”,喔,原来是@淘文景同学,上次我问过他的,他早就告诉了我正确答案:下载最新版的tengine-1.5.2,然后在配置里加上

fastcgi_request_buffering off;

即可。是我自己稀里糊涂的拿upstream的nginx测试了这么久,唉。
照@淘文景同学所说搭了环境,一测,非常好,再没有讨厌的client_body_temp缓存了。在tengine的github上翻了一下,是这个补丁,小补丁帮大忙。

感谢@淘文景同学的工作和耐心 🙂

用guilt发patch小技巧

我之前本地的补丁都是用guilt管理的,修改好了以后,git format-patch -n生成patch,写上标题什么的,然后发出去。
一直都是这样,直到最近,手头有十几个patch,发了好几版,每次都要把标题从旧path上拷过来,改改内容或者版本号什么的,很麻烦。
后来同事泰来告诉我一个方法,可以这样:

1. 对每个guilt补丁运行 guilt head -e 然后会跳出编辑器,把该补丁的head写上,比如

iosched: add new type of io scheduler

We found panic on BUG_ON(tppg->nr_tppq < 1) in pressure-testing.
After long term (about one month) tracing we finally find out the reason: some scsi_cmds
passed from scsi_ioctl will call blk_execute_rq_nowait and call tpps_set_request() but
never call tpps_insert_request() (It even doesn't get into io-scheduler) so the counter
of nr_tppq gets wrong.

Signed-off-by: Robin Dong 

编辑完成后,运行 guilt refresh,再用git log看,head已经进去了

2. 生成要发邮件的补丁时,运行

git format-patch -2 --subject-prefix "PATCH v3"

生成的补丁便如下

Subject: [PATCH v3 1/2] iosched: add new type of io scheduler

We found panic on BUG_ON(tppg->nr_tppq < 1) in pressure-testing.
After long term (about one month) tracing we finally find out the reason: some scsi_cmds
passed from scsi_ioctl will call blk_execute_rq_nowait and call tpps_set_request() but
never call tpps_insert_request() (It even doesn't get into io-scheduler) so the counter
of nr_tppq gets wrong.

Signed-off-by: Robin Dong 
......

不用每次都手动拷贝了。

声明:我是才学到这个用法的,可能比较弱智,已经知道了的同学不必嘲笑我了

旧文件干扰

昨天直接从git源上update到最新upstream内核版本,编译的内核却无法启动。一开始我以为是.config文件不对,于是试了各种方法,make localmodconfig,甚至make allmodconfig,居然还是起不来。于是在grub里加了个" vga=771 ",看看启动失败的具体报错信息,发现里面有句:

kernel tool old

神奇,这3.12的内核还老啊,在google上找了一下,还真有人遇到同样的报错,文章, 不过他是在arm上编译,gcc版本和内核版本差异很大,我这是rhel6,不应该有这么严重的问题,如果rhel6上都启动不了upstream内核,那应该很多人会发现的。
折腾了一圈,还是仔细看看失败的报错信息吧,这次才看到,除了“kernel too old”,居然还有

Not tained 2.6.19-rc79

莫名奇妙,明明是3.12内核,怎么说是2.6.19?这应该就是失败的原因了,于是沿着dump_stack()函数一路找回去,看到了这个

struct uts_namespace init_uts_ns = {
        .kref = {
                .refcount       = ATOMIC_INIT(2),
        },     
        .name = {
                .sysname        = UTS_SYSNAME,
                .nodename       = UTS_NODENAME,
                .release        = UTS_RELEASE,
                .version        = UTS_VERSION,
                .machine        = UTS_MACHINE,
                .domainname     = UTS_DOMAINNAME,
        },
        .user_ns = &init_user_ns,
        .proc_inum = PROC_UTS_INIT_INO,
};
EXPORT_SYMBOL_GPL(init_uts_ns);

原来打印的2.6.19-rc79是从UTS_RELEASE和UTS_VERSION宏来的,一找UTS_RELEASE在哪里定义的,发现居然有三个头文件,其中一个include/linux/version.h里是2.6.19,但是git一看,这个文件根本不在git库里,应该是某次我checkout到旧版本残留下来的......就是它干扰了启动过程。看来编译内核前,除了make clean以外,还要把不在git里的文件删掉,免得干扰正常编译。

CLSF 2013讨论会纪要(二)

第二天早上先由oracle的刘博同学介绍btrfs的进展。做为集宇宙之大成的btrfs相比xfs/ext4,新功能和改进都非常多。从08年开始btrfs就内置raid5/6了,一直在做性能改进,现在性能已经比multi-device略好5%,估计是md因为引入了新的设备层,所以性能会有小小损失(不过,5%,我个人感觉大了一点)。btrfs是支持snapshot的,但是对snapshot做defrag却是最近才加入的功能,对COW类性的fs来说,这个很好。online device replace这个功能我们争吵了半天,觉得这个功能到底谁需要,跟互联网运维的磁盘更换确实不搭边。去掉了单目录下创建hardlink的数据限制。还做了很多代码清理的工作,但是btrfs还需要多多注释,否则一般人不容易看明白代码。
接下来是一年一度的老问题(反正我从2011年参加clsf就都是这个问题):btrfs什么时候稳定下来?刘博回答:btrfs已经稳定了,大家开会沟通一致认为,xfs只是btrfs的过渡。于是文卿同学问道:“你能提供我一个btrfs的配置参数,保证我用了这个参数性能最优同时一定稳定吗?“,我以为刘博同学会说”mkfs.btrfs不带任何参数就行“,结果刘博同学回答:”这个你应该问做发行版的公司,我只是开发而已“,看来“纯”软件公司的”纯“开发人员跟互联网公司的开发人员差别还真大(刘博同学,我举这个例子只为说明而已,不是针对你,如果有所得罪,线下请你吃饭赔不是),我们可是要自己backport、自己功能测试、自己压力测试、自己上线测试(能上线测试都是求爷爷告奶奶了)、自己出性能报告、自己出上线测试报告的、自己给出最佳配置和使用方案的,全套都要搞,当然,我们拿的钱比oracle中国(不算美国)的”纯“开发人员多些,这点我不抱怨。

然后是华为的沈灿泉介绍华为正在开发的私有云系统,用到了ocfs2。华为的这款虚拟机托管方案用专用存储设备做后端,前端是很多个跑xen或者qemu的client,ocfs2存的是虚拟机镜像文件和配置文件。华为的同学在使用中发现ocfs2 90%的bug都出在dlm(分布式锁管理)上,公正的说,在IO压力不大,集群里机器增减不频繁的时候dlm工作还好,但是在人造的大压力下问题就多多了。广军同学于是推荐互联网公司人见人爱的zookeeper,但是灿泉说,zookeeper性能不够,因为ocfs2不是整个集群一个master那么简单,它是对每一个文件都要一个锁管理者(一个master),连文件系统的journal都是一个节点一个,靠zk一个个选根本不行,所以还是得用dlm。大家于是说到了kernel里的那个dlm比redhat gfs提供的dlm更简单也更稳定,EMC的彭涛同学还推荐了luster的dlm,也可备选。华为已经向ocfs2社区发了46个patch,其中39个已经被收入。(这patch数还是很高的,难怪我们组今年突然说KPI可以加一部分社区的patch工作,原来是让华为最近一年的社区patch数给眼红的,唉,去年想做upstream不让做,我一年多贴应用的冷屁股贴得我心都冷了突然又说现在可以做了。算了,人生嘛,十有八九都是不赶趟)未来华为的工作是支持scsi的fence命令,通过scsi命令把主机从集群中隔离出来;还有就是集群的writeback cache,使用SSD做cache来缓解尖峰IO的压力(这招,很多文件系统,不管是单机还是分布式的,都开始采用了)。
ocfs2最早是oracle开发的,涛哥在oracle做了四年的ocfs2开发,攒下了厚厚的几百个patch。这种做upstream且不是只修bug的机会,真的很难得。不过之后几个主力开发人员离开了,ocfs2基本处于停滞状态,bug都没人修了,现在华为突然说正在使用且积极的参与开发,确实值得鼓励,开源减少重复工作,复用提高生产力。


clsf 2013

Asias He同学讲解了虚拟机方面的IO优化,主要是virtio的改进。virtio-scsi.ko做了中断的合并(这点和网卡的polling倒是很像)。block multi queue在guest机器上的引入也提高了性能。还有discard命令穿越虚拟机到达host的优化。大家提到了discard命令在磁盘上会不会影响性能,coly和我都觉得应该不会,对于磁盘,trim命令其实没有生效,但是fusionio的李少华同学提醒:SATA协议里discard是会清io队列的(为了保证trim后读返回全零的语义),性能会略有降低。少华同学果然是学贯文件系统块设备scsi加sata,一句话我们只能拜服。

LSI的Jeb Tang介绍了公司的一些新产品。LSI其实不光卖SAS/RAID卡,也卖芯片,浪潮华为都用的是LSI的芯片,然后自己设计存储卡。硬raid卡不用说,用DRAM+FLASH+SUPERCAP(超级电容)来保证服务器宕机不丢数据,而且这个DRAM不仅是保证数据不丢,它还能大大减少io的延迟,对于io深度较低的应用,可以帮助其明显提升性能,比如mysql。Jeb提到了:其实对于1T的硬盘,1G的DRAM完全够了,因为大部分应用io深度不会超过8(我表示拜服)。LSI推出了一款带压缩的RAID卡,可以在export卷大小的时候直接报出解压后的大小,当然,对监控的要求就高了。LSI还提供了mmap接口把DRAM设备直接暴露出来给类似DB写日志用,这招狠,文卿同学打算回去就让DB的同学帮忙试试效果。

Fusionio的李少华同学介绍了fast swap的相关工作。linux在内存不够的时候会把部分内存存入swap分区(如果有的话),这个swap分区一般是在磁盘上,现在有了fusionio的高速存储卡,可以把这个swap分区放在高速卡上,这样就可以疯狂的使用内存(比如一些HPC应用,动辄malloc几个TB的空间)而不用担心OOM或者swap造成的巨大性能降低。linux现有的swap代码在高速卡上跑会有很多性能瓶颈,比如pte里‘A'标记和'P'标记分别有两次TLB flush,解决办法是去掉一个或者合并TBL flush;swap先在找cluster是线性的(显然是为了磁盘读取),现在也可以改为更快的算法以迎合SSD了;per-CPU的cluster,更好的增加io合并(我问少华:fusioniio卡也需要合并io吗?少华回答:即使是高速卡,16K的io和4K的io性能差别还是很大的,最好还是略合并一下);swap代码路径上还有很多锁,像anon_vma的mutex,swap_lock还有swap address sapce lock,现在也慢慢暴露出瓶颈(有高速卡就是好啊,泪奔),少华同学都一一解之。

最后由来自ubuntu社区的汪黎博士介绍他们使用ceph做测试的各种心得。ceph已经很火了,就不介绍了。汪博士在测试各种搭配的local fs后发现:btrfs最快但最不稳定,xfs出过一次io error然后无法mount了,ext4一直正常(文卿听到这里激动得都快哭了,当面表扬啊)。对于此结论,Jeff询问用的是什么版本的xfs,汪博士说是2.6.38的,Jeff说至少要3.10后的内核xfs他才敢打包票说稳定。看来用文件系统还是得有一个稳定的tree和一伙苦逼的维护人员才行啊,不是拿个光盘装上就能放心用的。
汪博士还反映ceph的文件接口出问题最多,块设备和对象接口比较稳定。大家好奇ceph现在最大部署过多大的集群,intel的Zheng Yan同学回答:dreamhost部署最大的是3PB数据,但是节点数不详。汪博士在ceph上做的工作就是将小文件的数据直接放在MDS上,减少网络延时。


clsf 2013
CLSF-2013 参会人员合影

PPT: ext4 xfs ceph virtio btrfs

感谢华为和oracle对clsf的赞助,也感谢LSI提供会场和午餐,还要感谢负责会务工作的谢广军和茶水,更要感谢各位参会者的积极参与和热烈讨论,我学到了很多。
当我向彭涛同学询问EMC做为一家存储公司的未来时,他告诉我,EMC的未来不是VNX,不是Symmetrix,更不是Iomega,而是Pivatolisilon时,我被震动了,我发现干了七年的码农真是白干了,光会码code,不会抬头看看未来,唉,我要好好向彭涛学习,好好的看看这个世界,好好的思考一下将来。

1 2 3 4 5 6 14