作者:吴就业
上传虽不是业务非常重视的能力,但却也是业务不可缺少的能力。
我们内部研发的罗马上传中间件,主要解决通用的文件上传场景,为业务提供简单的接入能力。
该中间件通过统一的上传API,屏蔽S3、OSS、OBS、MinIO、Ceph、MFS等文件系统的差异,支持分片上传API。业务使用同一个SDK可将文件上传至任意的文件系统,并可客户端直传文件到S3等云存储服务,可动态切换文件系统等。
基于云原生背景做的架构设计,对于mfs和ceph这类文件系统,我们并未采用挂盘的方式去使用,因为当时缺少运维提供PVC能力,所以mfs我们采用基于底层通信协议去读写文件,我们找到了开源的sdk。而ceph则用官方提供的go-ceph库。从上线开始到现在,遇到非常多棘手的问题,都是因为这两个文件系统所致。
根本原因是因为我们hold不住mfs和ceph这两个文件系统。以至于只要出现问题,都是非常头疼的问题,有的耗时一周、一个月解决,有的甚至无能为力。
难题一:上传MFS文件MD5不一致
在测试阶段,我们发现通过这个中间件上传文件到moosefs后,moosefs上存储的文件的md5与本地原文件md5不一致,如果是图片,能很明显的看出少了一块像素。
问题的根因是我们找的开源组件在实现文件读写存在协议上的bug,这个开源组件的start数只有几个,应该是一个demo组件,并未经过生产的验证。
关于bug的详细描述可以阅读这篇文章:"被开源组件坑惨了,文件上传到MFS后MD5不一致"
这个之所以成为难题,是因为moosefs官方只推荐挂盘方式使用,内部的api是不暴露的,所以没有任何的文档资料。我是通过去阅读moosefs的c++源码,从源码中找出我们用到的协议。
难题二:疑是go-ceph导致的内存泄漏
这个问题难在几个容器基本同一时间一起挂掉,而且不是内存慢慢涨上去挂掉的,而是突然说挂就挂,没有一丝丝防备。通过jemalloc的dump信息也看不出来任何的问题。
虽然这一篇文章("Go写的文件上传中间件内存泄露问题排查")说通过用例覆盖找到了问题,但实际上只是找到了另一个隐藏的内存泄漏问题,一个开源webp库存在内存泄露,后面找到google开源的webp库替代解决。但上线后一段时间还是出现了一次内存泄漏,现象一致,但出现的频率低了,所以猜测是存在两个内存泄漏问题的,与ceph相关的我们还是没找到原因。
难题三:ceph文件首次下载慢
文件上传后首次下载耗时非常慢,正常最慢都不可能超过1秒,文件的大小只有几十byte,耗时也要几秒,这个现象非常奇怪。
我们经过go语言提供的pprof和trace工具,问题定位到go-ceph这个库依赖的cephfs这个libc库的Open和Read方法非常耗时,但是ceph服务并不存在性能问题。详细描述可看这篇文章:"文上上传ceph首次下载耗时慢问题排查"
我并无法像排查mfs问题一样去排查ceph,即便我们用bpftrace等eBPF工具追踪到底层。因为我对ceph一无所知,一样无法解决问题。
关于bpftrace可以阅读这篇文章:"如何使用bpftrace追踪系统调用性能问题"。
经过一年的折磨,对mfs文件系统算是很了解了,但是ceph文件系统,还是非常的陌生,无奈,我们只能重构ceph,通过PVC挂盘ceph使用,把难题抛给专业运维人员。
总结
前期的技术选型非常重要,理想的架构自然好,但要考虑团队有没有人能hold住,出了问题是否能解决。如果hold不住,技术选型应该保守一点,可以不那么完美。
本文经「原本」原创认证,作者吴就业,访问yuanben.io查询【2T7J4YA6】获取授权信息。