Cloudeep对象存储系统>存储系统简介(2) --- 元数据存储
--Adam
一、前言
在大规模存储系统>存储系统或云存储系统>存储系统中,高可用、高扩展性的元数据存储问题一直是一个关键点。
在GFS 中,Namenode 所维护的元数据信息主要包括file system 的目录树和数据块位置信息;正因为单点的Namenode 容量有限,使得GFS 的namenode 所能维护的文件数量,受到单点资源的限制。幸运的是GFS 是为大文件案例设计的,通常情况下单节点的内存Cache 都能满足要求(对元数据的频繁访问,使得运行时,元数据信息存储在Disk 不是明智之举)。同时由于GFS 提供global 的file system namespace ,使得GFS 的namenode 的横向扩展变得非常困难。
S3-Like 的云存储系统>存储系统,摒弃了global 的file-system namespace ,使得元数据存储在横向的扩展变得容易;从而方便实现海量对象(文件)的存储。对象(文件)之间没有了树形层次关系,对象(文件)之间再无依赖关系。单个对象(文件)的表述就变成了一个简单的key /value 对的形式。Key 就是一个对象(文件)的全局唯一的ID ,Value 就是与该对象(文件)相关的块数据信息和属性信息。进一步,元数据就可以存储在一个 key /value 对的存储子系统上。
key /value 对存储 技术 ,包括超越 key /value 对存储的Bigtable 都是比较成熟的,都是No SQL 技术,颜开在他的《No SQL 数据库笔谈》中详细的列举各种 key /value 对数据库和Bigtable 技术( http://sebug.net/paper/databases/nosql/Nosql.html )。我们在为Cloudeep 对象存储系统>存储系统选择元数据 key /value 对存储方案时,对几种典型的NoSQL 技术做了简单分析和对比:
1、 Memcahced 、dbcached 、BeanDB 等
效率很高的key/value 对存储技术,但都没有很好的解决动态可扩展性和副本修复;
2、 Amazon Dynamo
Amazon 为解决在线业务中类似“购物篮“的问题,提供Always Available 的存储服务。其部署规模一般在几十上百台的规模(估计),主要用于支持在线用户数据的存储。为解决” Always Available “的问题,系统引入了副本的DHT 分发、向量时钟、马可树、均匀的分区策略等手段,甚至最终由用户解决数据一致性冲突问题等。
对象存储的元数据存储,主要保证最终一致性,同时“购物篮“问题也不突出,而且也不太可能交给用户做终极一致性冲突裁决。因此Dynamo 用于存储元数据信息,有太多的”富余“,增加了系统的复杂度。
3 、Cassandra
Cassandra 是一个 Dynamo + Bigtable 的开源项目 , 底层采用 Dynamo 做存储 , 上层实现 Bigtable 的数据模型。该系统的当前版本在评估过程中,感觉对节点动态性的容忍度比较低,扩展性能不强,增加和删除一个节点没有预期的简单和平滑;同时Bigtable 的数据模型对当前元数据的存储需求来说也有太多的“富余“,复杂度太高。
4 、 Hadoop HBase
Hadoop 的Hbase 项目也是一个Bigtable 的开源实现,数据模型也是有“富余“;同时Hbase 依赖Hadoop 的HDFS ,如果用于存储元数据,子系统太多,不方便维护和部署。
二、Cloudeep 元数据存储
1 、需求:
- 支持水平分区(shard ),有良好的伸缩性
- Key/Value 对存储(Key 是对象的键值,Value 是对象的块数据索引信息)
- 三份副本
- 副本自动修复功能
2 、方案:
一致性Hash 环,基于DHT 分发的key/value 对存储方案。
图 1. Key/Value 对的 DHT 分发
几个关键问题:
- 节点拓扑的维护: 基于Chubby-like 的子系统,所有的节点都可以和该子系统建立Session 链接,并从该子系统得到全局节点列表信息,包括节点状态的动态变化信息。这和Dynamo 依靠Gossip 协议获取Member List 的方案不同。请参阅( http://blog.csdn.net/Cloudeep/archive/2010/07/12/5729309.aspx )。
- Key 的哈希: 该对象存储系统>存储系统提供Amazon-S3 类似的接口功能,所以对Key 的哈希也和类似。对象被存储在Bucket 中,因此一个对象的Full Key = Bucket info + Full Path , 其中Full Path 指对象在Bucket 内部的全路径名。Bucket Info 往往包含User 、Application 和Bucket 等信息集合。在DHT 寻址过程中,系统只对Bucket Info 计算哈希值,用于元数据节点定位。如此可以更好的保证Bucket 内的字典序操作。
- 最终一致性: 由于环上的节点经常发生加入或离开事件;系统对于每次写操作,并不确保对象的存储位置和节点哈希值有严格的匹配关系,但系统确保所有的对象最终会流向和它对应的元数据节点。同样系统对于每次读操作,并不确保读到的对象是最后提交的版本,但最终可以读到正确的版本。
- 环的空间划分: 参考Dynamo 的实现,元数据存储节点的哈希空间划分,尽可能保持均匀划分。
- 环的动态性维护: 环上节点的动态性带来两个主要的问题,一是副本数目的修复(节点离开),而是数据的迁移(节点加入),以及这两个问题的叠加。解决这些问题,可以参考Dhash (MIT Chord 项目)的实现和Dynamo 。Dhash 的描述中有这样一句话“ Since membership changes happen continuously, DHash is rarely or never in the ideal state, but always tends toward it by continually running these maintenance protocols. ”,为了加速解决系统的动态性问题,Dynamo 里也提到使用Merkle Tree 等方式来解决数据迁移的问题。
- 如何对待节点的离开(失效): 即使具备自愈能力,我们都很难做到对“节点永久离开的事件” 完全“无动于衷”,除非节点的动态性处在我们的设定范围内。任何可能导致三份副本永久丢失的情况都是应该被严密监控的。