基本构架组成
1.网关服务(Gateway):
客户端发送请求(Request)到网关服务(Gateway)再由网关服务实现将客户端请求转换为相应的数据(Data)、元数据(Metadata),消息对列(MQ)的操作。一般来讲网关服务主要承担以下几个角色的功能:
协议转换:实现前端客户端协议(HTTP/RPC)等向后端模块(TCP/RPC/MQ)之间的协议转换。
请求分发:负责将前端请求按不同请求类型(数据操作。元数据操作、异步队列操作)分发到不同后端模块上。
协同与调度:部分前端请求可能会同时涉及到与多个后端模块之间的交互,因此网关服务还需要统一这些请求,并实现多个模块之间的协同与调度。
负载均衡:实现客户端请求的负载均衡,提升整体系统的并发吞吐性能。
高速缓存:实现热数据的高速缓存,提高客户端请求的命中率,同时降低底层模块的访问压力。当出现底层模块不可用时,仍然能够提供部分数据来支撑客户端的请求访问,提供类似降级服务,从而在一定程度上提高整体服务的可用性。
正是鉴于上面讲到的几个功能特性,如果把整个对象存储比作一辆超级大卡车,网关服务相当于“方向盘,变速箱,仪表盘”这些和司机有着密切交道的操控设备,车子开起来顺不顺手,很大程度上都由这些决定。
2.数据存储服务(Data store):
同时满足水平扩展,高性能、高可用等分布式存储的特性,为整个对象存储提供底层数据存储最坚实的基石,用一句话来形容就是"坚如磐石".数据存储服务模块可以对上提供多种类型的数据存储I/O接口,比如文件存储、对象存储、块存储,上层通过调用这些标准化的存储接口,实现对象数据内容的存储。如果把对象存储系统比作一辆车,那么数据存储服务相当于整个对象存储的"车身、悬架、轮胎".
3.元数据存储(KV store):
一个完整的对象数据主要由数据内容和元数据两部分构成,除了通过上面提到的数据存储服务以外,一些元数据信息也需要用到存储。值得注意的是数据内容一般都是非结构化化或者半结构化,但元数据一般都是可以结构化的内容,比如文件的MIME,MD5值、修改时间(mtime),属主(ower)等,这些信息一般都是以key-value方式存储并关联到具体的对象,而且这些元数据信息经常性的需要进行快速遍历和查询、更新等,同时为了更好的做到模块之间的解耦,将元数据存储单独抽离出来并以Key-value方式存储在特定的KV存储引擎中变得非常有必要,特别是当对象存储数据规模到达海量以后,独立的KV存储(元数据存储)能够极大的避免成为整个系统的性能瓶颈。可以毫不夸张的说元数据存储的重要性相当于整个对象存储系统的"传动系统、变速器".
4.异步任务队列(Async queue):
为什么一个对象存储系统需要用到一个独立的异步任务队列系统,相信这是很多新手司机的困惑。同样也是基于解耦的初衷,让我们看看下面几个场景。
1)。用户数据需要进行一些定期的数据操作,比如通过lifecycle,实现定期筛选并清除用户数据,亦或是定期从热存储资源池将数据迁移到冷存储资源池。
2)。用户已经删除了对象,底层需要按一定的规则触发相应的垃圾回收(GC)机制,释放那些被占用的磁盘空间。
3)。用户需要跨越物理区域去同步多个存储集群之间的数据,考虑到网络延迟、磁盘延迟等各方面因素,这些操作都无法做到实时同步。
4)。用户需要将传上来的数据进行加工处理,比如对上传上来的视频文件进行转码,对图片进行压缩,对文件进行加密等,这些操作都需要消耗大量的计算资源,而且都无法做到实时返回结果。
了解完上面的几种场景,你会发现,如果采取同步机制去要求所有的客户端操作都立即返回执行结果,是非常不现实的,至少目前硬件层面还无法做到这么高的实时性,于是我们只能做出适当取舍,设计一个独立的异步任务队列来满足这些需求,把一些耗时操作都丢给这个异步的任务队列。引入异步队列系统确实能解决整个对象存储系统中一些无法实时操作的痛点,但同时也引入了一些新的问题:
1)。如何确保用户的数据一致性,特别是用户频繁进行数据和元数据操作的时候,如何保障这些异步操作原子化,大程度的符合用户对数据一致性的预期。
2)。异步队列自身的健壮性,如何保障每一个提交到异步队列的实务(task)能够实时有效的执行,特别是在异步队列自身出现故障等各种问题的时候,如何快速有效且正确的去执行这些实务。
3)。平滑的水平扩展,如何在处理现有任务队列的同时确保整个队列系统的平滑水平扩展。
4)。任务时序化和优先级,对象存储系统一般实现的都是数据的最终一致性,如何确保所有任务严格按时间序列或者其他规则执行,如何确定同一时刻对同一个对象的不同操作的优先级顺序。
上面只是我这边简单罗列的几个引入异步队列所带来的问题,相信各位读者对这些问题都有着自己不同的理解,一千个读者就有一千个哈姆雷特,这里因为篇幅有限,我们不再深入下去,谈到这些需要思考的问题主要是想告诉各位读者,异步任务队列是一把"双刃剑",如果你功底深厚可以做出很多超出你想象的功能特性,将整个对象存储服务在功能上提高好几个Level,但是反之,一旦陷入深坑,也可能“万劫不复”。所以我个人的经验是,对待异步队列时刻保持警惕态度,尽可能少的去涉及这个模块,用一句话概括就是"simple is the best".可以毫不掩饰的说,异步任务队列是一个对象存储产品是否成熟的关键指标,类似"倒车雷达,定速巡航"一类高级功能,如果把选购对象存储产品比作选购汽车,这也将成为区别“普通汽车”与“高档汽车”的关键。