问题描述
测试cephfs内核客户端的吞吐性能,direct写时单个客户端性能有上限,只能接近150 mb/s:
查看网卡流量,并没有打满:
查看集群负载也很低,osd磁盘很空闲,验证多台机器同时并发测试,总吞吐可以上去,怀疑单个客户端的上限有瓶颈。
源码分析
集群没有打满,网络也不是瓶颈,那么只能从内核客户端cephfs的写IO入手,寻找问题的根源。 cephfs内核客户端写IO的代码在文件fs/ceph/file.c:
从代码实现看,主要流程是new_request, start_request, wait_request三个步骤。 直觉告诉我这里的wait会被block住,跟踪一下这里的wait实现:
先看超时的时间,传入的是0,最终结果是LONG_MAX,差不多就是一直wait:
接下来看条件的满足:
从kernel的注释看,函数schedule_timeout就是sleep直到timeout:
从源码分析看,已经比较明确,一次请求下发后,只有等请求完成了才会进行下一次请求,IO并不是并发的下发给后端的集群。
接下来的问题是,每次请求的size如何决定? 这个和文件的layout属性和当前写的位置相关,如果从文件offset 0开始写的话,以及采用默认属性,最大就是ceph object size的大小,即4MB。 ceph的layout解释可以参考官方文档。
实验证明
调取文件属性
为了更明显的观察延时,我们将文件的属性调整一下,即从4m到64m:
获取文件inode
文件对应的对象
查看两个对象对应的osd信息,分别对应osd 121和130:
再次执行刚才的dd命令,并在两个primary osd(121, 130)上观察op的情况,并同时用ftrace,观察kernel客户端写的过程。
osd机器OP请求
通过以下命令查看osd的op信息,ID为上面的121和130:
ceph daemon osd.ID dump_historic_ops
上面是osd 121的信息,操作的对象是10000000388.00000000,op持续了426.153ms,主要耗费时间在网络读数据的延时和副本操作的延时。op开始时间16:04:19.049346,结束时间16:04:19.475499。
这是osd 130的信息,操作的对象是10000000388.00000001,op持续了439.539ms。op开始时间16:04:19.491627,结束时间16:04:19.931166。
可以很清楚的看见,先写第一个对象,再写第二个对象,对象之间是没有并发写的,这区别于块存储,块存储的实现,至少librbd的实现,如果一次io对应多个object,多个请求是同时发出的,而不会等第一个对象完成了才下发第二个对象的IO,参见如下代码:
写文件的客户端ftrace信息
enable ftrace步骤:
观察日志:
这里用了差不多500ms才开始下一个请求,而上面从osd端的分析看,第一个IO用了426ms才完成,osd完成IO后通知kernel客户端有网络延时,然后加上kernel调度的延时,差不多能够匹配。
结论
通过源码分析,然后分别从集群osd端和kernel客户端进行验证,direct的情况,cephfs性能确实有限制。但是,用户也不用过于担心性能跟不上,因为通常情况下,不会是direct写,kernel客户端有page cache,写会非常快,
更贴近真实的使用场景,用户先写数据,最后调用一次sync操作:
网友评论