理解 OpenStack Swift (2):架构、原理及功能 [Architecture, Implementation and Features]

本系列文章着重学习和研究OpenStack Swift,包括环境搭建、原理、架构、监控和性能等。html

(1)OpenStack + 三节点Swift 集群+ HAProxy + UCARP 安装和配置 前端

(2)原理、架构和性能node

(3)监控git

1. 架构

1.1 整体架构

Swift 的整体架构很是的清晰和独立:github

# 分层(Tier) 组件(Service) 功能(Function) 特性 部署考量
1 访问层(Access Tier) Load Balancer 硬件(好比F5)或者软件(好比HAProxy)负载均衡器,将客户端的请求按照配置的策略分配到无状态的 proxy service。    按照实际需求选择硬件仍是软件LB
2 Proxy Server
  • 提供 REST API 给客户端
  • 无状态的 WSGI 服务,由多个 Proxy Server 组成一个集群
  • 将客户端请求转给某个存储节点上的 Account,Container 或者 Object 服务

是 CPU 和网络带宽敏感的web

  • 分配更多的CPU和网络带宽,好比 10GbE 网络
  • 使用 Memcached 来作 token、account 和 container 数据缓存
  • 和存储服务分开部署
  • 使用负载均衡器
  • 每每每五个存储节点使用两个 proxy server 节点,而后再按比例扩展
  • 将 public network (用于客户端访问)和 backend network (用于访问存储服务)分开
  • 须要考虑安全性,能够将 SSL Termination 放在 Proxy Server 上
3 存储层 (Capactity Tier)

Account Server算法

提供 Account 操做 REST API 是磁盘性能和网络带敏感的
  • 对 Account 和 Container 服务使用更好的磁盘,好比 SAS 或者 SSD,来提升性能;
  • 使用 1GbE 或者 10GbE 网络
  • 须要的话,能够将 replicaiton network 独立出来
  • 须要的话,能够将 Account 和 Container 服务部署到独立的服务器上
4 Container Server 提供 Container 操做 REST API
5 Object Server 提供 Object 操做 REST API
 6 Consistency Servers 包括 Replicators, Updaters 和 Auditors 等后台服务,用于保证 object 的一致性

这是一张比较经典的 Swift 物理部署图:数据库

1.2 网络架构

以一个对外提供对象存储服务的集群为例,其网络架构能够为:ubuntu

  • 外部流量被放在一个单独的(上图中紫色)VLAN 中,终点为 LB
  • 控制(管理)网络链接全部节点
  • Swift 前端(front end / public)网络链接 LB 和 全部 Proxy server 节点
  • Swift 后端 (backend / private) 网络链接全部 Proxy server 节点和 存储节点
  • 须要的话,还能够从后端网络中分离出复制(replication)网络

在网络带宽选择上,swift

  • 考虑到复制数据的容量较大(每每是几个TB起步),后端网络每每是用 10GbE 网络
  • 根据前端负载,前端网络可使用 1GbE 网络,或者有条件时使用 10GbE 网络
  • 管理/IPMI网络每每是用 1GbE 网络

这是 SwiftStack 的一个例子:

2. 数据存放

2.1 Swift 的数据存放

2.1.1 Swift 的数据模型

Swift 的数据模型使用了如下三个概念来(见下图1):

  • Account: 帐户/租户。Swift 是天生支持多租户的。若是使用 OpenStack Keystone 作用户校验的话,account 与 OpenStack project/tenant 的概念相同。Swift 租户的隔离性体如今metadata上,而不是体如今 object data 上。数据包括自身元数据 和 container 列表,被保存在 SQLite 数据库中。
  • Container: 容器,相似于文件系统中的目录,由用户自定义,它包含自身的元数据和容器内的对象列表。数据保存在 SQLite 数据库中。在新版中,Swift 支持在容器内添加文件夹。
  • Object: 对象,包括数据和数据的元数据,以文件形式保存在文件系统上。

     

 (图1)                                                     (图2)

 

  • Containers 是用户建立的,用来 hold objects。
  • objects 能够是 0 bytes 长度,或者包含数据。
  • container 中的 object 最大大小为 5GB;超过的话,会作特殊处理
  • 每一个 object 使用它的 name 来被 referenced;Swift 没有目录概念
  • 在 object name 中可使用任意的能够被 ‘URL-encoded’ 的 字符,最大长度为 URL - coded 以后 1034 个字符
  • object name 中能够带 '/' 字符,它会带来目录结构的幻觉(illusion),好比 dir/dir2/name。即便看起来象个目录,可是它仍然只是一个 object name。此时,不须要 dir 或者 dir/dir2 container 的存在。
  • 若是一个 container 全部 objects 的大小为0,那么它将看起来象一个目录。
  • 客户端使用 HTTP 或者 HTTPS 访问 Swift,包括读、写、删除 objects。也支持 COPY 操做,它会建立一个新的 object,使用一个新的 object name,包含老 object 的 data。没有 rename 操做,它会首先 copy 出一个新的,而后再将老的删除。

2.1.2 选择数据存放位置

  Swift 保存每一个对象为多分拷贝,它按照物理位置的特色,尽可能将这些拷贝放在不一样的物理位置上,来保证数据的地理位置上的可靠性。它主要考虑如下几种位置属性:

  • Region:地理位置上的区域,好比不一样城市甚至不一样国家的机房,这主要是从灾备方面考虑的。
  • Zone:一个数据中心根据物理网络、供电、空调等基础设施分开的独立的域,每每将一个机架(Rack)内的服务器分在一个 Zone 内。
  • Node (节点):物理服务器
  • Disk (磁盘):物理服务器上的磁盘

Swift 在肯定对象的放置位置时,会尽可能将对象及其拷贝放在不会同时损失的物理位置上。见上图2.

2.1.3 保证数据一致性

    对象及其拷贝放置在某个磁盘上后,Swift 会使用Replicators, Updaters 和 Auditors 等后台服务来保证其数据的最终一致性。

  • Replicator – 拷贝对象,确保系统的最终一致性(Replicate objects and make a system in a consistent state);恢复磁盘和网络错误(Recover disk failure, network outages situation)
  • Updater – 更新元数据(Update metadata),从容器和帐户元数据高负载致使的问题上恢复(Recover failure caused by container, account metadata high load)
  • Auditor – 删除问题帐户,容器和对象,而后从别的服务器上拷贝过来(Delete problematic account, container or objects and replicate from other server);恢复数据库和文件数据错误(Recover dbs or files which have bit rot problem.

其中,Replicator 服务以可配置的间隔来周期性启动,默认是 30s,它以 replication 为最小单位,以 node 为范围,周期性地执行数据拷贝。详细过程请参考文末的参考文档。考虑到Swift 实现的是最终一致性而非强一致性,它不合适于须要数据强一致性的应用,好比银行存款和订票系统等。须要作 replication 的情形包括但不限于:

  • Proxy server 在写入第三份时失败,它依然会向客户端返回成功,后台服务会写第三份拷贝
  • 后台进程发现某个replication 数据出现损坏,它会在新的位置从新写入
  • 在跨 Region 的状况下,Proxy server 只会向它所在 Region 的存储上写入,远处 region 上的数据由后台进程复杂写入
  • 在更换磁盘或者添加磁盘的状况下,数据须要从新平衡时

2.2 Swift  是如何实现这些需求的:使用 Ring + 哈希算法

    Swift 根据由管理员配置的 Ring 使用相对简单直接的算法来肯定对象的存放位置。对象会以文件的形式保存在本地文件系统中,使用文件的扩展属性来保存对象的元数据,所以,Swift 须要支持扩展属性的文件系统,目前官方推荐是 XFS。

2.2.1 Ring 的内容和算法

    简单来讲,Swift 的 Proxy Server 根据account,container 和 object 各自的 Ring 来肯定各自数据的存放位置,其中 account 和 container 数据库文件也是被看成对象来处理的。

所以,Swift 须要 Ring 的配置文件分布在全部 Proxy节点上。同时,Consistency Servers 须要它来肯定后台对象拷贝的位置,所以也须要部署在全部存储节点上。Ring 以文件的形式保存:

  • object.ring.gz
  • container.ring.gz
  • account.ring.gz

在分析 Ring 是如何工做的以前,先来看看 Ring 的几个关键配置:

  • Region,zone 和 disk:前面说过了,略过
  • partition:Swift 再将每一个磁盘分红若干 partition (分区)。这是后端一致性检查服务处理拷贝(replication)的基本单位。
  • Replica:对象和拷贝的总份数,常规推荐值是 3。

管理员使用 Swift 提供的 ring 生成工具(swift-ring-builder,位于源码的bin目录下,是swift最基本的命令,它与swift/common/ring/下的文件一块儿实现ring文件建立,添加,平衡,等操做),加上各类配置参数,得出该ring的内容。以 Object ring 为例,

root@swift1:/etc/swift# swift-ring-builder object.builder
object.builder, build version 6
1024 partitions, 3.000000 replicas, 1 regions, 3 zones, 6 devices, 0.00 balance, 0.00 dispersion
The minimum number of hours before a partition can be reassigned is 1
The overload factor is 0.00% (0.000000)
Devices:    id  region  zone      ip address  port  replication ip  replication port      name weight partitions balance meta
             0       1     1   9.115.251.235  6000   9.115.251.235              6000      sdb1 100.00        512    0.00
             1       1     1   9.115.251.235  6000   9.115.251.235              6000      sdc1 100.00        512    0.00
             2       1     2   9.115.251.234  6000   9.115.251.234              6000      sdb1 100.00        512    0.00
             3       1     2   9.115.251.234  6000   9.115.251.234              6000      sdc1 100.00        512    0.00
             4       1     3   9.115.251.233  6000   9.115.251.233              6000      sdb1 100.00        512    0.00
             5       1     3   9.115.251.233  6000   9.115.251.233              6000      sdc1 100.00        512    0.00

该 Ring 的配置为:1 个 region,3 个 zone,3 个 node,6 个磁盘,每一个磁盘上 512 个分区。

内部实现上,Swift 将该 Ring 的配置保存在其 _replica2part2dev 数据结构中:

其读法是:

  • 行:将集群全部的分区都顺序编号,每一个分区有惟一的一个ID
  • 列:包含 Ring 中的 id,该 id 惟一肯定了一个 disk;和 replica 的编号。

所以,Swift 经过该数据结构能够方便地查到某个 replica 应该经过哪些节点上的存储服务放在哪一个 disk 上。

除了生成 Ring 外,对 Ring 的另外一个重要操做是 rebalance(再平衡)。在你修改builder文件后(例如增减设备),该操做会从新生成ring文件,使系统中的partition分布平衡。固然,在 rebalance 后,须要从新启动系统的各个服务。 详情能够参考 OpenStack Swift源码分析(二)ring文件的生成

2.2.2 数据放置和读取过程

当收到一个须要保存的 object 的 PUT 请求时,Proxy server 会:

  1. 根据其完整的对象路径(/account[/container[/object]])计算其哈希值,哈希值的长度取决于集群中分区的总数。
  2. 将哈希值的开头 N 个字符映射为数目同 replica 值的若干 partition ID。
  3. 根据 partition ID 肯定某个数据服务的 IP 和 port。
  4. 依次尝试链接这些服务的端口。若是有一半的服务没法链接,则拒绝该请求。
  5. 尝试建立对象,存储服务会将对象以文件形式保存到某个磁盘上。(Object server 在完成文件存储后会异步地调用 container service 去更新container数据库)
  6. 在3份拷贝中有两份被成功写入后, Proxy Server 就会向客户端返回成功。

 

当 Proxy server 收到一个获取对象的 GET 请求时,它:

(1)(2)(3)(4)同前面的 PUT 请求,肯定存放全部 replica 的 全部磁盘

(5)排序这些 nodes,尝试链接第一个,若是成功,则将二进制数据返回客户端;若是不成功,则尝试下一个。直到成功或者都失败。

应该说该过程蛮简单直接,这也符合Swift的整体设计风格。至于具体的哈希算法实现,有兴趣能够看相关论文。大体来讲,它实现的是 “unique-as-possible” 即 “尽可能惟一” 的算法,按照 Zone,Node 和 Disk 的顺序。对于一个 replica,Swift 首先会去选择一个没有该对象 replica 的 zone,若是没有这样的 zone,选择一个已使用 zone 中的没用过的 node,若是没有这样的 node,就选择已使用的 node 上的一个没使用过的 disk。

2.2.3 Hash 计算和对象位置查找

(1)存放的目录取决于哈希值

这里也代表,对象的存放目录和其名称是直接关联的。所以,在Swift中的,对对象重命名,意味着对象位置的修改,该过程会产生数据拷贝,并且在不少时候是须要跨节点的远程拷贝。在某些应用中,好比 Hadoop 大数据应用,若是采用 Swift 做为存储,在其mapreduce 过程当中,是会产生文件 rename 操做的,这在 Swift 中会带来严重的性能降低。

(2)获取某对象的存放路径

root@swift1:~/s1# swift-get-nodes /etc/swift/object.ring.gz AUTH_dea8b51d28bf41599e63464828102759/container1/1

Account         AUTH_dea8b51d28bf41599e63464828102759
Container       container1
Object          1
Partition       277
Hash            456a95e2e66aad55d72756c6b0cd3b75

Server:Port Device      9.115.251.235:6000 sdb1
Server:Port Device      9.115.251.234:6000 sdc1
Server:Port Device      9.115.251.233:6000 sdc1

curl -I -XHEAD "http://9.115.251.235:6000/sdb1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"
curl -I -XHEAD "http://9.115.251.234:6000/sdc1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"
curl -I -XHEAD "http://9.115.251.233:6000/sdc1/277/AUTH_dea8b51d28bf41599e63464828102759/container1/1"

(3)远程登陆后者 ssh 后能够看到保存对象的文件

root@swift1:~/s1# ls /srv/node/sdb1/objects/277/b75/456a95e2e66aad55d72756c6b0cd3b75 -l
total 8
-rw------- 1 swift swift 12 Nov  8 17:17 1447003035.84393.dataroot@swift1:~/s1# cat /srv/node/sdb1/objects/277/b75/456a95e2e66aad55d72756c6b0cd3b75/1447003035.84393.data
222222222222

2.2.4 对象分段

  Swift 对于小的文件,是不分段直接存放的;对于大的文件(大小阈值能够配置,默认是 5G),系统会自动将其分段存放。用户也能够指定分段的大小来存放文件。好比对于 590M 的文件,设置分段大小为 100M,则会被分为 6 段被并行的(in parallel)上传到集群之中:

root@controller:~/s1# swift upload container1 -S 100000000 tmpubuntu
tmpubuntu segment 5
tmpubuntu segment 2
tmpubuntu segment 4
tmpubuntu segment 1
tmpubuntu segment 3
tmpubuntu segment 0
tmpubuntu
root@controller:~/s1# swift list container1
1
admin-openrc.sh
cirros-0.3.4-x86_64-disk.raw
tmpubuntu

从 stat 中能够看出它使用一个 manifest 文件来保存分段信息:

root@controller:~/s1# swift stat container1 tmpubuntu
       Account: AUTH_dea8b51d28bf41599e63464828102759
     Container: container1
        Object: tmpubuntu
  Content Type: application/octet-stream
Content Length: 591396864
 Last Modified: Fri, 13 Nov 2015 18:31:53 GMT
          ETag: "fa561512dcd31b21841fbc9dbace118f"
      Manifest: container1_segments/tmpubuntu/1446907333.484258/591396864/100000000/
    Meta Mtime: 1446907333.484258
 Accept-Ranges: bytes
    Connection: keep-alive
   X-Timestamp: 1447439512.09744
    X-Trans-Id: txae548b4b35184c71aa396-0056462d72

可是 list 的时候依然只看到一个文件,缘由是由于 manifest 文件被保存到一个独立的 container (container1_segments)中。这里能够看到 6 个对象:

root@controller:~/s1# swift list container1_segments
tmpubuntu/1446907333.484258/591396864/100000000/00000000
tmpubuntu/1446907333.484258/591396864/100000000/00000001
tmpubuntu/1446907333.484258/591396864/100000000/00000002
tmpubuntu/1446907333.484258/591396864/100000000/00000003
tmpubuntu/1446907333.484258/591396864/100000000/00000004
tmpubuntu/1446907333.484258/591396864/100000000/00000005

每一个对象大小是100M(考虑到存储效率,不建议每一个对象大小小于100M):

root@controller:~/s1# swift stat container1_segments tmpubuntu/1446907333.484258/591396864/100000000/00000000
       Account: AUTH_dea8b51d28bf41599e63464828102759
     Container: container1_segments
        Object: tmpubuntu/1446907333.484258/591396864/100000000/00000000
  Content Type: application/octet-stream
Content Length: 100000000

并且用户能够单独操做好比修改某一段。Swift 只会负责将全部段链接为用户所见的大的对象。

关于大文件支持的更多细节,能够参考 官方文档 和 Rackspace 的文档。从上面的描述能够看出,Swift 对文件分段的支持是比较初级的(固定,不灵活),所以,已经有人提出 Object stripping (对象条带化)方案,好比下面的方案,不知道是否已经支持仍是将要支持。

2.3 Region

    经过将对象存放在不一样物理位置上的 Region 内,能够进一步加强数据的可用性。其基本原则是:对于 N 份 replica 和 M 个 region,每一个 region 中的 replica 数目为 N/M 的整数,剩余的 replica 在 M 个region 中随机选择。以 N = 3, M = 2 为例,一个 region 中有 1 个 replica,另外一个 region 中有两个 replica,以下图所示:

对于一个 PUT 操做来讲,Proxy server 只会将 replica 写入它所在的 region 中的 node,远端 region 中的 replica 由 replicator 写入。所以,Swift 的算法应该尽可能保证 proxy server 所在的 region 中的 replica 份数相对多一些,这也称为 replica 的 proxy server 亲和性。

显然,跨 region 的数据复制加剧了对网络带宽的要求。

两种形式的 Region:

(1)远端 region 实时写入 replica

(2)远端 region 的 replica 异步写入

2.4 Storage Polices (存储策略)

    上面的描述中,一个Swift 集群只支持一套 Ring 配置,这意味着整个机器的配置是惟一的。相似 Ceph 中 pool 的定义,Swift 在 2.0 版本(包含在 OpenStack Juno 版本中)中,添加了一个很是大的功能:Storage policy。在新的实现中,一个 Swift 能够由多套 Ring 配置,每套 Ring 的配置能够不相同。好比,Ring 1 保存 3 份对象拷贝,Ring 2 保存 2 份对象拷贝。几个特色:

  • Policy 被实如今 container 级别
  • 建立 container 时能够指定 policy。一旦被指定,不能够修改。
  • 一个 policy 能够被多个 container 共享使用

    经过应用该新的功能,Swift 用户能够制定不一样的存储策略,来适应不一样应用的存储需求。好比对关键应用的数据,制定一个存储策略使得数据被保存到 SSD 上;对于通常关键性的数据,指定存储策略使得数据只保存2份来节约磁盘空间。好比说:

详细信息,请参考 OpenStack 官方文档 和 SwiftStack 官方文档

3. 版本及主要功能

3.1 Juno以及以前主要版本和功能

 

(1)Large object support

(2)Static web hosting

(3) S3 compatible API

(4) Object expiration

(5) Temp url

(6) Global cluster

(7) Storage policy

3.2 Kilo 版本中的更新

新功能

纠删码(beta)

Swift如今支持纠删码(EC)存储策略类型。这样部署人员、以极少的RAW容量达到极高的可用性,如同在副本存储中同样。然而,EC须要更多的CPU和网络资源,因此并不适合全部应用场景。EC很是适合在一个独立的区域内极少访问的、大容量数据。

Swift纠删码的实现对于用户是透明的。对于副本存储和纠删码存储的类型,在API上没有任何区别。

为了支持纠删码,Swift如今须要依赖PyECLib和liberasurecode。liberasurecode是一个可插件式的库,容许在你选择的库中实现EC算法。

更详细文档请参阅 http://swift.openstack.org/overview_erasure_code.html

复合型令牌(Composite tokens)

复合型令牌容许其余OpenStack服务以客户端名义将数据存储于Swift中,因此不管是客户端仍是服务在更新数据时,都不须要双方彼此的受权。

一个典型的例子就是一个用户请求Nova存放一个VM的快照。Nova将请求传递给Glance,Glance将镜像写入Swift容器中的一组对象中。在这种场景下,用户没有来自服务的合法令牌时,没法直接修改快照数据。一样,服务自身也没法在没有用户合法令牌的状况下更新数据。可是数据的确存在于用户的Swift帐户中,这样使得帐户管理更简单。

更详细的文档请参阅http://swift.openstack.org/overview_backing_store.html

更小规模、不平衡集群的数据位置更新

Swift数据的存放位置如今根据硬件权重决定。当前,容许运维人员逐渐的添加新的区域(zones)和地域(regions),而不须要当即触发大规模数据迁移。同时,若是一个集群是非平衡的(例如,在一个区域(zones)的集群中,其中一个的容量是另一的两倍),Swift会更有效的使用现有空间而且当副本在集群空间不足时发出警告。

全局性集群复制优化

区域(regions)之间复制时,每次复制只迁移一个副本。这样远程的区域(region)能够在内部复制,避免更多的数据在广域网(WAN)拷贝。

已知问题

  • 做为beta更新,纠删码(EC)的功能接近完成,可是对于某些功能仍然不完整(像多范围(multi-range)读取),而且没有一个完整的性能测算。这个功能为了持久性依赖于ssync。部署人员督促咱们作更大规模的测试,而且不要在生产环境部署中使用纠删码存储策略。

升级提示

像往常同样,你能在不影响最终用户体验的前提下,升级到这个版本的Swift。

  • 为了支持纠删码,Swift须要一个新的依赖PyECLib(和liberasurecode等)。而且eventlet的最低版本要求也升高了。

3.3 Liberty 版本中的更新

L版本中Swift 没有加入大的新功能,详细状况能够参考 官方文档

3.4 优点

 

 

其它参考文档:

http://www.florentflament.com/blog/openstack-swift-ring-made-understandable.html

https://www.mirantis.com/blog/configuring-multi-region-cluster-openstack-swift/

OpenStack Swift源码分析

相关文章
相关标签/搜索