首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

OpenStack 基础介绍08——Swift 组件详细介绍(中)

今天咱们接着聊 Swift 组件的技术特性,以及一些关键技术。

1 Swift 技术特性

1.1 Swift的主要特征

Swift 的主要特性如下:

(1)极高的数据持久性(Durability)。

(2)完全对称的系统架构:“对称”意味着 Swift 中各节点可以完全对等,能极大地降低系统维护成本。

(3)无限的可扩展性:包括两方面的意义,一是数据存储容量无限可扩展;二是 Swift 性能(如QPS、吞吐量等)可线性提升。

(4)无单点故障:Swift 的元数据存储是完全均匀随机分布的,并且与对象文件存储一样,元数据也会存储多份。整个 Swift 集群中,也没有一个角色是单点的,并且在架构和设计上保证无单点业务是有效的。

(5)简单、可依赖。

1.2 Swift 和 HDFS 的技术差异

Swift 和 Hadoop 分布式文件系统(HDFS)都有着相似的目的:实现冗余、快速、联网的存储,它们的技术差异如下:

(1)在 Swift 中,元数据呈分布式,跨集群复制。而在 HDFS 使用了中央系统来维护文件元数据(Namenode,名称节点),这对 HDFS 来说无异于单一故障点,因而扩展到规模非常大的环境显得更困难。

(2)Swift 在设计时考虑到了多租户架构,而 HDFS 没有多租户架构这个概念。

(3)在 Swift 中,每次操作时,文件可以写入多次;在并发操作环境下,以最近一次操作为准。而在 HDFS 中,且每次只能有一个文件写入,不支持并发写入。

(4)Swift 用 Python 来编写,而 HDFS 用 Java 来编写

(5)Swift 被设计成了一种比较通用的存储解决方案,能够可靠地存储数量非常多的大小不一的文件;而 HDFS 被设计成可以存储数量中等的大文件(HDFS针对更庞大的文件作了优化),以支持数据处理,而在处理大量小文件时反而会使其耗费更多内存,从而影响数据处理的效率,而且 HDFS 是用来处理大吞吐量的离线数据,它需要牺牲一定的延时为代价,因此它不太适合哪些对延时有较高要求的应用程序。

2 Swift 关键技术

2.1 一致性哈希(Consistent Hashing)

在分布式对象存储中,一个关键问题是数据该如何存放。Swift 是基于一致性哈希技术,通过计算可将对象均匀分布到虚拟空间的虚拟节点上,在增加或删除节点时可大大减少需移动的数据量;虚拟空间大小通常采用 2 的 n 次幂,便于进行高效的移位操作;然后通过独特的数据结构 Ring(环)再将虚拟节点映射到实际的物理存储设备上,完成寻址过程。

下面我们用百度的一张示意图说明一下:

衡量一致性哈希的4个指标:

(1)平衡性(Balance)

平衡性是指 Hash 的结果能够尽可能分布均匀,充分利用所有缓存空间。

(2)单调性(Monotonicity)

单调性是指如果已经有一些内容通过 Hash 分派到了相应的缓冲中,又有新的缓冲加入到系统中。Hash 的结果应能够保证原有已分配的内容可以被映射到新的缓冲中去,而不会被映射到旧的缓冲集合中的其他缓冲区。

(3)分散性(Spread)

分散性定义了分布式环境中,不同终端通过 Hash 过程将内容映射至缓存上时,因可见缓存不同,Hash 结果不一致,相同的内容被映射至不同的缓冲区。

(4)负载(Load)

负载是对分散性要求的另一个纬度。既然不同的终端可以将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。

Swift 使用该算法的主要目的是在改变集群的 node 数量时(增加/删除服务器),能够尽可能少地改变已存在 key 和 node 的映射关系,以满足单调性。

考虑到哈希算法在 node 较少的情况下,改变 node 数会带来巨大的数据迁移。为了解决这种情况,一致性哈希引入了“虚拟节点”(vnode,也称为 partition)的概念: “虚拟节点”是实际节点在环形空间的复制品,一个实际节点对应了若干个“虚拟节点”,“虚拟节点”在哈希空间中以哈希值排列。

总的来说,Swift 中存在两种映射关系,对于一个文件,通过哈希算法(MD5)以及移位运算找到对应的虚节点(一对一的映射关系);虚节点再通过映射关系(ring 文件中二维数组)找到对应的设备(多对多的映射关系),这样就完成了一个文件存储在设备上的映射。

在设置虚结点数的时候,需要对系统预期的规模做充分考虑,假如集群的规模不会超过 6000 个结点,那么可以将虚结点数设置为结点数的 100 倍。这样,变动任意一个结点的负载仅影响 1% 的数据项。此时有 6 百万个 vnode 数,使用 2bytes 来存储结点数(0~65535)。基本的内存占用是 6*(10^6)*2bytes = 12Mb,对于服务器来说完全可以承受。

假设有 65536(2^16) 个 node,有 128(2^7) 倍的 partition 数(2^23,则PARTITION_POWER = 23)。由于 MD5 码是 32 位的,使用PARTITION_SHIFT(等于32- PARTITION_POWER) 将数据项的 MD5 哈希值映射到 partition 的2^23的空间中。

2.2 数据一致性模型(ConsistencyModel)

按照Eric Brewer 的 CAP(Consistency,Availability,PartitionTolerance)理论,无法同时满足 3 个方面,Swift 放弃严格一致性(满足 ACID 事务级别),而采用最终一致性模型(Eventual Consistency),来达到高可用性和无限水平扩展能力。

为了实现这一目标,Swift 采用 Quorum 仲裁协议(Quorum 有法定投票人数的含义):

(1)定义

N:数据的副本总数;W:写操作被确认接受的副本数量;R:读操作的副本数量。

(2)强一致性

R+W > N,以保证对副本的读写操作会产生交集,从而保证可以读取到最新版本;

如果 W = N,R = 1,则需要全部更新,适合大量读少量写操作场景下的强一致性;

如果 R = N,W = 1,则只更新一个副本,通过读取全部副本来得到最新版本,适合大量写少量读场景下的强一致性。

(3)弱一致性

R+W

Swift 针对的是读写都比较频繁的场景,所以采用了比较折中的策略,即写操作需要满足至少一半以上成功 W > N/2,再保证读操作与写操作的副本集合至少产生一个交集,即R+W > N。

在分布式系统中,数据的单点是不允许存在的。线上正常存在的 replica 数量是 1 的话将非常危险的,因为一旦这个 replica 再次错误,就可能发生数据的永久性错误。假如我们把 N 设置成为 2,那么,只要有一个存储节点发生损坏,就会有单点的存在。所以 N 必须大于 2。但 N 越高,系统的维护和整体成本就越高。所以,工业界通常把 N 设置为 3。

Swift 默认配置是 N = 3,W = 2 > N/2,R = 1 或 2,即每个对象会存在 3 个副本,这些副本会被尽量存储在不同区域的节点上;W = 2 表示至少需要更新 2 个副本才算写成功。

当 R = 1 时,意味着某一个读操作成功便立刻返回,此种情况下可能会读取到旧版本(弱一致性模型)。

当 R = 2 时,需要通过在读操作请求头中增加 x-newest = true 参数来同时读取 2 个副本的元数据信息,然后比较时间戳来确定哪个是最新版本(强一致性模型)。

如果数据出现了不一致,后台服务进程会在一定时间窗口内通过检测和复制协议来完成数据同步,从而保证达到最终一致性。

但其实根据源码分析来看,Quorum 仲裁机制必须要等到 3 个 Response 都返回之后才会选举出最佳的 Response 返回给客户端(即使是 Timeout,也会等待 Storage Server 返回),所以一个集群一旦遇到有一个慢节点,将非常影响 Swift 的性能,导致写入速度上不去(这是一个可以改进的地方!)

2.3 环(Ring)

Ring 是 Swift 中最重要的组件,用于记录存储对象与物理位置间的映射关系。在涉及查询Account、Container、Object 信息时就需要查询集群的 Ring 信息。

环是为了将虚拟节点(partition,分区)均衡地映射到一组物理存储设备上,并提供一定的冗余度而设计的,其数据结构由以下信息组成:

(1)存储设备列表,设备信息包括唯一标识号(id)、区域号(zone)、权重(weight)、IP 地址(ip)、端口(port)、设备名称(device)、元数据(meta);

(2)分区到设备映射关系(replica2part2dev_id 数组);

(3)计算分区号的位移(part_shift 整数);

如下图所示,我们以查找一个对象的计算过程为例:

(1)使用对象的层次结构 account/container/object 作为键,使用 MD5 散列算法得到一个散列值,对该散列值的前 4 个字节进行右移操作得到分区索引号,移动位数由上面的 part_shift 设置指定(一致性哈希映射到虚拟节点);

(2)按照分区索引号在分区到设备映射表(replica2part2dev_id)里查找该对象所在分区的对应的所有设备编号,这些设备会被尽量选择部署在不同区域(Zone)内,区域只是个抽象概念,它可以是某台机器,某个机架,甚至某个建筑内的机群,以提供最高级别的冗余性,建议至少部署 5 个区域;权重参数是个相对值,可以来根据磁盘的大小来调节,权重越大表示可分配的空间越多,可部署更多的分区。

Swift 为账户、容器和对象分别定义了的 Ring,其查找过程是相同的。Ring 中每个 partition 在集群中都默认有 3 个 replica。每个 partition 的位置由 Ring 来维护,并存储在映射中。

Ring 使用 zone 来保证数据的物理隔离。每个 partition 的 replica 都确保放在了不同的 zone 中。Zone 只是个抽象概念,它可以是一个磁盘(disk drive),一个服务器(server),一个机架(cabinet),一个交换机(switch),甚至是一个数据中心(datacenter),以提供最高级别的冗余性,建议至少部署 5 个 zone。

权重参数是个相对值,可以来根据磁盘的大小来调节,权重越大表示可分配的空间越多,可部署更多的分区。

当集群中发生存储节点宕机、新增(删除)存储节点、新增(删除)zone 等必须改变 partition 和 node 间的映射关系时,还可以对 Ring 文件通过重新平衡(rebalance)来进行更新。当虚节点需要移动时,环会确保一次移动最少数量的虚节点数,并且一次只移动一个虚节点的一个副本。

总的来说

Ring 引入一致性哈希的原因是为了减少由于增加结点导致数据项移动的数量来提高单调性;引入 partition 虚节点的原因是为了减少由于节点数过少导致移动过多的数据项(数据负载不均衡);引入 replica 复本的原因是防止数据单点、提高冗余性;引入 zone 分区的原因是为了保证分区容忍性;引入 weight 权重的原因是为了保证 partition 分配的均衡。

图片授权基于:CC0协议

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180330A11VYK00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券