OpenStack Object Storage(Swift)是OpenStack开源云计算项目的子项目之一, 是整个OpenStack项目的一个模块。

Swift最适合的就是永久类型的静态数据的长期存储。
比如虚拟机的镜像啦,文档的备份啦,还有陈老师、李老师的艺术作品啦之类的。

先来熟悉一下Swift中的几个概念:
Account
出于访问安全性考虑,使用Swift系统,每个用户必须有一个账号(Account)。只有通过Swift验证的账号才能访问Swift系统中的数据。提供账号验证的节点被称为Account Server。Swift中由Swauth提供账号权限认证服务。用户通过账号验证后将获得一个验证字符串(authentication token.),后续的每次数据访问操作都需要传递这个字符串。

Container
Swift中的container可以类比Windows操作系统中的文件夹或者Unix类操作系统中的目录,用于组织管理数据,所不同的是container不能嵌套。数据都以Object的形式存放在container中

Object
对象这个概念在后面会提到,这里先不说明了。

Swift有如下几个特性:
0、极高的数据持久性,上面已经提到了。
1、各个存储的节点完全对等,是对称的系统架构。
2、因为是对称的系统架构,扩容的时候只需简单的增加机器,扩展性很好。
3、不存在单节点故障,前面提到因为各个节点完全对等,没有所谓的“主从”结构。

存储在Swift里面的数据有好几个备份,而且各个节点之间是平等的关系,没有“主节点”这个概念,因此任意一个节点出现故障时,数据并不会丢失(注意,这里是任意一个节点出现故障)。而与它形成对比的是Hadoop的HDFS。

HDFS有一个元数据存储节点,保存在HDFS集群中的所有文件都会在元数据存储节点上保留一份元数据,元数据记录了每个文件的一些必要的信息,例如文件大小,属于哪个用户,更新的时间,存储在HDFS哪台数据服务器上等等,感觉这个元数据的概念有点类似Linux中文件的inode信息。HDFS的缺点是一旦元数据服务器挂掉,那么整个HDFS集群就玩完了。当然,这只是我对HDFS一点浅显的认识,真正的部署的时候肯定还有很多保护措施,HDFS的健壮性是很好的。

回到Swift上,Swift的元数据存储是完全均匀随机分布的,并且与对象文件存储一样,元数据也会存储多份。
下图给出了Swift架构的一张示意图

————————更新———————

下面是关于几个服务器作用,在上图中有 account server 和 container server 没有画出来。
原文是英文,就直接放在这里了。

Proxy server accepts incoming requests via the OpenStack Object API or just raw HTTP. It accepts files to upload, modifications to metadata or container creation. In addition, it will also serve files or container listing to web browsers. The proxy server may utilize an optional cache (usually deployed with memcache) to improve performance.

Account servers manage accounts defined with the object storage service.

Container servers manage a mapping of containers (i.e folders) within the object store service.

Object servers manage actual objects (i.e. files) on the storage nodes.

—————————————————

其中Proxy Node是提供Swift API的服务器进程,我们要做的各个操作都是直接提交给Proxy Node, 由它来负责具体的操作。

但是这里有个疑问:Client需要的数据,最后是由Proxy Node直接返回给Client? 还是Proxy Node只回复Client要的数据在哪台Storage Node上,然后Client再去对应的Stroage Node上取呢?(我猜测应该是后者)

Storage Node就没什么好说的了,就好比是一个个大的数据仓库,提供存储服务。

无论是HDFS也好,Swift也好,必须面对的一个问题就是如何保持数据的一致性。 因为一个文件并不是只保存一份的,在Swift中默认要保存3个副本,当更新的时候这3个文件要同时更新,当其中一个文件损坏时必须能迅速的复制一份完整的文件来替换。

Swift有3个服务来解决这个问题:Auditor、Updater和Replicator。 Auditor运行在每个Swift服务器的后台持续地扫描磁盘来检测数据的完整性。如果发现数据损坏,Auditor就会将该文件移动到隔离区域,然后由Replicator负责用一个完好的拷贝来替代该数据。如果更新失败,该次更新在本地文件系统上会被加入队列,然后Updaters会继续处理这些失败了的更新工作。

刚才提到过,Swift没有元数据服务器,也就是说,不会特意为每一个文件生成一个类似inode的东西,并且保存在特定的一个服务器上,这一点与HDFS有很大的不同。那么剩下最后一个问题:Client要存储一个文件,用什么策略决定存在哪台Storage Node上呢?

实际上,与传统的文件系统不同,Swift保存的不是“文件”而是“对象”,这就是所谓的“对象存储”,具体可以通过下图理解:

可以看出,在对象存储中,存储的不仅是数据,还有与丰富的数据相关的属性信息。系统会给每一个对象分配一个唯一的ID。对象本身是平等的,所有的ID都属于一个平坦的地址空间,而并非文件系统那样的树状逻辑结构。

这种存储结构带来的好处是可以实现数据的智能化管理,因为对象本身包含了元数据信息,甚至更多的属性,我们可以根据这些信息对对象进行高效的管理。例如我们可以制定这样的存储策略,如果对象中包含priority:high,这样的属性,我们就对文件做比平常文件多的备份次数。

平坦地址空间的设计使得访问对象只通过一个唯一的ID标识即可,不需要复杂的路径结构。

因此,可以知道Swift中没有“路径”这个概念,所以也没有有所谓的“文件夹”这样的概念。

现在,我们有了对象的ID了,那么如何根据这个ID把对象存在合适的Storage Node呢?

在解决这个问题时,要注意几个约束条件:

0、能快速的做一个决策,到底存在哪个Node上。
解决这个问题,我们的第一反应应该是根据ID做一个Hash,不错,Swift确实是这么做的。

1、Swift里面存储着成千上万,甚至上亿个 Object,当我们往集群中增加Storage Node的时候,最好不影响已有的数据。
对于固定数量的Storage Node,使用普通的取模Hash法应该是又快又好的,当时当Node的数量会变动时,这种简单的Hash就不行了,因为这时所有对象的Hash值都会改变,这对于存储了上亿个对象的Swift来说是相当可怕的。

解决的方法是使用“一致性Hash法”

一致性哈希算法的基本实现原理是将机器节点和key(在本文里就是对象的ID)值都按照一样的hash算法映射到一个0~2^32的圆环上。当有一个写入缓存的请求到来时,计算Key值k对应的哈希值Hash(k),如果该值正好对应之前某个机器节点的Hash值,则直接写入该机器节点,如果没有对应的机器节点,则顺时针查找下一个节点,进行写入,如果超过2^32还没找到对应节点,则从0开始查找(因为是环状结构)。

经过一致性哈希算法散列之后,当有新的机器加入时,将只影响一台机器的存储情况,例如新加入的节点H的散列在B与C之间,则原先由C处理的一些数据可能将移至H处理,而其他所有节点的处理情况都将保持不变,因此表现出很好的单调性。而如果删除一台机器,例如删除C节点,此时原来由C处理的数据将移至D节点,而其它节点的处理情况仍然不变。而由于在机器节点散列和缓冲内容散列时都采用了同一种散列算法,因此也很好得降低了分散性和负载。而通过引入虚拟节点的方式,也大大提高了平衡性。

这个一致性hash算法倒是蛮有意思的,有时间应该详细的学习一下。

以上就是本文的全部了,因为最近在实习,BOSS布置了这个任务,于是就去了解了一下OpenStack。这里也只是我对Swift的一些浅显的认识,如果文章里面有错误,欢迎指出,谢谢。

在写这篇文章的时候,参考了很多网上的资料,但是很难一一列举出来,下面是我能找到参考资料的链接:

http://blog.huanghao.me/?p=14

http://os.zju.edu.cn/bbs/zjuos2011/?q=node/1501

Tags: . 222,089 views
Home

2 Comments so far

Trackbacks/Pingbacks