网易视频云是网易倾力打造的一款基于云计算的分布式多媒体处理集群和专业音视频技术,提供稳定流畅、低时延、高并发的视频直播、录制、存储、转码及点播等音视频的PAAS服务,在线教育、远程医疗、娱乐秀场、在线金融等各行业及企业用户只需经过简单的开发即可打造在线音视频平台。现在,网易视频云的技术专家给大家分享一则技术文:基于Hadoop山寨Amazon S3。
S3( http://aws.amazon.com/s3/)是amazon提供的高可用、高可靠、高可扩展的对象存储服务, 单桶支持无限存储空间, 每个对象最大5TB。 虽然实现这么一个大型的对象存储系统非常有挑战性, 但是用开源软件山寨一个对象存储也并没有这么复杂, 本文将尝试基于Hadoop的HDFS和Hbase构建一个这么系统HOS(Humor Object Storage), HOS能扩展到千台服务器规模, 足以满足中小型云计算的对象存储需求。当然, HOS纯属娱乐, 切勿模仿, 以免被坑。
上图展示了HOS对象的存储模型, HOS对象存储于HDFS文件, 小对象连续存放, 而大型对象则拆分为多个片段存储。 对象元数据包括对象名,对象位置信息等存储于Hbase。 HOS的核心Hbase表如下:
S3的核心操作由PUT_OBJECT/GET_OBJECT/DELETE_OBJECT/GET_BUCKET, 我们来看看HOS的实现。
操作(一):上传对象PUT_OBJECT(key, value)的流程:
1. 打开(或者获取)一个HDFS文件句柄
2. 将value拆分为数个分片, 分片的长度不超过4MB
3. 追加每个分片到HDFS文件, 记录分片在HDFS文件中的偏移off和长度len, 分片在对象中的偏移objoff
4. 插入记录< filename, off, len, key, objoff> 到FileObjectIndex
5. 插入记录 到ObjectTable,Locations是对象分片的存储位置信息
6. 若文件长度超过阈值,则关闭文件,设置文件状态为closed
上述流程只能处理key不存在情况, 若key存在, HOS先执行删除流程,再执行上述流程, 已达到替换的效果。
上传过程错误处理: 任何一个步骤出错, 对象都是创建失败, 所有已分配资源最终都被回收利用。出错可能遗留两种垃圾信息, 一是文件数据, 二是文件数据和FileObjectIndex中的索引记录。 第一种情况下, 文件数据没有被引用, 能被清道夫的垃圾回收流程处理。
第二种情况发生时必须删除FileObjectIndex中的索引记录。 当错误发生时, 应用服务器暂时往HDFS文件追加数据, 开启后台线程,异步清理FileObjectIndex中的记录。 当应用服务器工作正常时, 索引记录能被删除,但是万一应用服务器发生宕机, 怎么清理索引记录? 清道夫程序会定期扫描pending状态文件, 若文件很长时间都没有写入,则 以文件名和文件长度为key逆序扫描FileObjectIndex, 比对FileObjectIndex记录与ObjectTable记录, 清理不匹配的FileObjectIndex记录。 扫描和比对的FileObjectIndex数目,取决于HDFS上最大的并发写入量, 由于并发量通常比较小, 清理代价非常小。
操作(二):读取对象GET_OBJECT(key)
1. 根据key查询ObjectTable得到对象存放位置信息, 位置信息是一个数组, [< file1, off1, len1>, < file2, off2, len2>, …, ]
2. 根据位置信息读取对象。
操作(三): 删除对象DELETE_OBJECT(key)
1. 插入记录到DeletedObjectTable
2. 删除ObjectTable记录,通知客户端删除成功。
错误处理
1. 第1步失败,则返回删除失败
2. 第2步失败,则重试几次操作。无论重试是否成功,都认为删除操作已经成功。 虽然删除操作已经成功,由于ObjectTable记录未删除, 后台删除操作执行之前, 此对象仍然是可以访问的。这听起来怪怪的,不过为了简化问题, HOS准备容忍这个问题。
操作(四): 后台删除操作。 DELETE_OBJECT只是把对象移动到了DeletedObjecTable表中。 DeletedObjectTable相当于是回收站, 清道夫会定期扫描回收站,找到过期对象, 执行删除操作。
1. 清理程序定期扫描DeletedObjectTable
2. 针对已经过期的对象,找到对象的分片存储位置
3. 针对每个分片,增加File表中的相关记录的Free字段
4. 删除分片对应的FileObjectIndex记录
5. 删除DeletedObjectTable表当前对象。
错误处理: 后台删除操作是幂等的, 过程中任意步骤出错, 不影响正确性。
操作(五):垃圾回收
1. 清道夫扫描File表, 找出空闲率(Free/Size)大于阈值,且状态为closed的文件集合
2. 针对每个满足要求的HDFS文件, 以文件名为键值, 升序扫描FileObjectIndex表
3. 针对扫描得到的每条记录R, 根据R从文件读取有效数据, 追加一个新的HDFS文件。
4. 生成新文件的FileObjectIndex表记录,插入。
5. 更新ObjectTable的Locations字段, 指向新文件
6. 删除当前记录R。
7. 每处理完一个HDFS文件之后, 删除该文件。
错误处理: 垃圾回收过程发生错误时, 可从发生错误的记录开始重做, 最多导致新文件中遗留一段垃圾数据, 不影响正确性。
操作(六): LS目录操作GET_BUCKET(path)。 对象的key允许包含”/”, 譬如 “MyBucket/a” , “MyBucket/a/b”, “MyBucket/a/b/c”, “MyBucket/a/d”, 都是合法的对象名称。因此用户可以把桶当做一个文件系统来用, 而GET_BUCKET操作的非常类似目录LS。 GET_BUCKET(“MyBucket/a”) 返回 “MyBucket/a/b”和 “MyBucket/a/d”。 GET_BUCKET可以用coprocessor查询ObjectTable实现, 不再详细展开。
总结:
HOS利用HDFS/Hbase, 实现简单, 且稳定性、可靠性、可伸缩性有保障, 但是Hadoop是用于离线业务的, 性能难以保证,多租户也支持不好。 当然HOS还不是实现s3最简单的办法, 或与直接用Ceph就解决了问题。