1. Swift概述
Swift 最初是由Rackspace公司开发的高可用分布式对象存储服务,并于2010年贡献给OpenStack开源社区作为其最初的核心子项目之一,为其Nova子项目提供虚机镜像存储服务。Swift构建在比较便宜的标准硬件存储基础设施之上,无需采用 RAID(磁盘冗余阵列),通过在软件层面引入一致性散列技术和数据冗余性,牺牲一定程度的数据一致性来达到高可用性和可伸缩性,支持多租户模式、容器和对象读写操作,适合解决互联网的应用场景下非结构化数据存储问题。Swift在OpenStack系统中不依赖于任何服务,可以独立部署为其他系统提供分布式对象存储服务。而在OpenStack的应用中,其Proxy Server往往由Keystone节点兼任,由Keystone来完成服务访问的安全认证。
Swift是业务提供时,使用普通的服务器来构建冗余的、可扩展的分布式对象存储集群,存储容量可达PB级。通过统一REST API进行友好访问,不仅易于扩展,且无中心数据库,避免单点故障或单点性能瓶颈。Swift主要通过Account、Container和Object三个表单结构来完成存储对象的存储、查询、获取和上传等功能,通过数据存储的多副本机制实现数据的高可用。
2. Swift的架构和组件
Swift的架构是一种完全对称、面向资源的分布式系统架构,所有组件都可扩展,避免因单点失效而影响整个系统运转。通信方式采用非阻塞式 I/O 模式,提高了系统吞吐和响应能力,如下图所示。系统架构整体上采用分层的理念设计,共分为两层:访问层和存储层。Controller的Ring以上部分属于访问层,接收外部REST API的访问,实现负载均衡和访问安全验证,并定位对象数据存储的位置。后端的Server部分属于存储层,用来分别存储不同的对象数据:Account、Container和Object。
3. Swift中的数据结构原理
Swift中最重要的算法就是一致性哈希(Consistent Hashing),它是Swift实现海量数据存储,并能实现数据均衡度和可扩展性兼容的保证,可以不过分的认为一致性哈希算法是所有分布式存储的灵魂,不仅Swift中有它的影子,在开源分布式存储Ceph以及华为分布式存储FusionStorage中同样有它的影子。在面对海量级别的对象,需要存放在成千上万台服务器和硬盘设备上,首先要解决寻址问题,即如何将对象均匀地分布到这些设备地址上。这也是Swift中的一致性哈希首先要解决的问题,算法的基本思路是:通过计算可将对象均匀分布到虚拟空间的虚拟节点上,在增加或删除节点时可大大减少需移动的数据量;虚拟空间大小通常采用2的n次幂,便于进行高效的移位操作;然后通过独特的数据结构 Ring(环)再将虚拟节点映射到实际的物理存储设备上,完成寻址过程。
4. 对象存储服务
(1)查看服务状态
在openstack平台中使用命令“swift stat”查看对象存储服务状态,执行命令如下所示:
[root@controller ~]# swift stat
Account: AUTH_bf368e64a3e64d9c9ae695253f1f3879
Containers: 0
Objects: 0
Bytes: 0
X-Put-Timestamp: 1719219141.22226
X-Timestamp: 1719219141.22226
X-Trans-Id: tx7f8f26c7fc1049daa7639-00667933c3
Content-Type: text/plain; charset=utf-8
X-Openstack-Request-Id: tx7f8f26c7fc1049daa7639-00667933c3
(2)创建容器
通过“openstack container create”命令创建容器,命令格式如下所示:
[root@controller ~]# openstack help container create
usage: openstack container create [-h] [-f {csv,json,table,value,yaml}]
[-c COLUMN] [--max-width ]
[--fit-width] [--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}]
[--sort-column SORT_COLUMN]
[ ...]
使用命令创建容器,名称为“test”,操作命令如下:
[root@controller ~]# openstack container create test
+---------------------------------------+-----------+------------------------------------+
| account | container | x-trans-id |
+---------------------------------------+-----------+------------------------------------+
| AUTH_bf368e64a3e64d9c9ae695253f1f3879 | test | tx775dbbdee99344318533f-00667933f6 |
+---------------------------------------+-----------+------------------------------------+
(3)查看容器
使用命令查询容器列表信息,命令如下所示:
[root@controller ~]# openstack container list
+------+
| Name |
+------+
| test |
+------+
使用命令查询容器详细信息,命令如下所示:
[root@controller ~]# openstack container show test
+--------------+---------------------------------------+
| Field | Value |
+--------------+---------------------------------------+
| account | AUTH_bf368e64a3e64d9c9ae695253f1f3879 |
| bytes_used | 0 |
| container | test |
| object_count | 0 |
+--------------+---------------------------------------+
(4)创建对象
创建完容器后,可以创建对象,通过使用命令“openstack object create”在对象中创建对象。命令格式如下所示:
[root@controller ~]# openstack help object create
usage: openstack object create [-h] [-f {csv,json,table,value,yaml}]
[-c COLUMN] [--max-width ]
[--fit-width] [--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}]
[--sort-column SORT_COLUMN] [--name ]
[ ...]
在使用命令创建对象前,需要将上传后的目录结构在本地创建。在本地创建名为“test”的目录“/root/test”,将/root/anaconda-ks.cfg文件复制至“/root/test”目录中。命令代码如下所示:
[root@controller ~]# mkdir test
[root@controller ~]# cp anaconda-ks.cfg test/
创建对象的过程也是向容器中上传文件,使用命令创建“test/anaconda-ks.cfg”对象。操作命令如下所示:
[root@controller ~]# openstack object create test test/anaconda-ks.cfg
+----------------------+-----------+----------------------------------+
| object | container | etag |
+----------------------+-----------+----------------------------------+
| test/anaconda-ks.cfg | test | d2e8f949c7901359529b549c8bdf4555 |
+----------------------+-----------+----------------------------------+
(5)查看对象
创建完对象后,通过命令查看容器中对象信息,使用命令“openstack object list”查看对象信息,命令格式如下所示:
[root@controller ~]# openstack help object list
usage: openstack object list [-h] [-f {csv,json,table,value,yaml}] [-c COLUMN]
[--max-width ] [--fit-width]
[--print-empty] [--noindent]
[--quote {all,minimal,none,nonnumeric}]
[--sort-column SORT_COLUMN] [--prefix ]
[--delimiter ] [--marker ]
[--end-marker ]
[--limit ] [--long] [--all]
使用命令查看容器“test”中所有对象信息,操作命令如下:
[root@controller ~]# openstack object list test
+----------------------+
| Name |
+----------------------+
| test/anaconda-ks.cfg |
+----------------------+
通过查询命令可以看出,在通过命令上传对象时,本地路径即为容器内对象路径。使用命令“openstack object show”查询“test”容器中“test/anaconda-ks.cfg”对象详细信息,命令如下所示:
[root@controller ~]# openstack object show test test/anaconda-ks.cfg
+----------------+---------------------------------------+
| Field | Value |
+----------------+---------------------------------------+
| account | AUTH_bf368e64a3e64d9c9ae695253f1f3879 |
| container | test |
| content-length | 1577 |
| content-type | application/octet-stream |
| etag | d2e8f949c7901359529b549c8bdf4555 |
| last-modified | Mon, 24 Jun 2024 08:56:21 GMT |
| object | test/anaconda-ks.cfg |
+----------------+---------------------------------------+
(6)下载对象
存储在容器中的对象,可以在需要使用时,通过“openstack object save”命令进行下载至本地,命令格式如下所示:
[root@controller ~]# openstack help object save
usage: openstack object save [-h] [--file ]
Save object locally
使用命令将“test”容器中“test/anaconda-ks.cfg”对象下载至本地/opt/目录下。操作命令如下所示:
[root@controller ~]# cd /opt/
[root@controller opt]# openstack object save test test/anaconda-ks.cfg
[root@controller opt]# ls test/
anaconda-ks.cfg
(7)删除对象
使用“openstack object delete”命令删除容器内的对象,命令格式如下所示:
[root@controller ~]# openstack help object delete
usage: openstack object delete [-h] [ ...]
使用删除对象命令将“test”容器内“test/anaconda-ks.cfg”删除,查看“test”容器中对象列表信息。操作命令如下所示:
[root@controller ~]# openstack object delete test test/anaconda-ks.cfg
[root@controller ~]# openstack object list test
(8)删除容器
使用“openstack container delete”命令删除容器,命令格式如下所示:
[root@controller ~]# openstack help container delete
usage: openstack container delete [-h] [--recursive]
[ ...]
使用删除容器命令将“test”容器删除,当前为容器内无对象可以直接删除。
[root@controller ~]# openstack container delete test
[root@controller ~]# openstack container list
如下为容器内有对象,无法直接删除。
[root@controller ~]# openstack container delete test
Conflict (HTTP 409) (Request-ID: txdd46d0c317014b70ade23-0066793735)
[root@controller ~]# openstack object list test
+-----------------+
| Name |
+-----------------+
| anaconda-ks.cfg |
+-----------------+
需要添加“–recursive”参数将容器内部对象一起删除,才可以删除“test”容器,查看容器列表信息。操作命令如下:
[root@controller ~]# openstack container delete --recursive test
[root@controller ~]# openstack container list
5. 分片存储案例
(1)创建容器
使用命令创建一个容器test并查看容器的状态信息,命令如下:
[root@controller ~]# swift post test
[root@controller ~]# swift stat test
Account: AUTH_bf368e64a3e64d9c9ae695253f1f3879
Container: test
Objects: 0
Bytes: 0
Read ACL:
Write ACL:
Sync To:
Sync Key:
Accept-Ranges: bytes
X-Storage-Policy: Policy-0
Last-Modified: Mon, 24 Jun 2024 09:09:27 GMT
X-Timestamp: 1719219192.85910
X-Trans-Id: tx0ab38be98b634aa98a829-00667937d1
Content-Type: application/json; charset=utf-8
X-Openstack-Request-Id: tx0ab38be98b634aa98a829-00667937d1
(2)上传镜像并分片存储
将提供的cirros-0.6.2-x86_64-disk.img镜像上传至controller节点的/root目录下,并使用命令上传至test容器中,进行分片存储,每个片段的大小为10M,命令如下:
[root@controller ~]# ll
total 20936
-rw-------. 1 root root 1577 Oct 23 2023 anaconda-ks.cfg
-rw-r--r--. 1 root root 21430272 Jun 20 17:47 cirros-0.6.2-x86_64-disk.img
-rw-r--r--. 1 root root 101 Jun 20 16:01 logininfo.txt
drwxr-xr-x 2 root root 29 Jun 24 16:55 test
上传镜像至容器并进行分片:
[root@controller ~]# swift upload test -S 10000000 cirros-0.6.2-x86_64-disk.img
cirros-0.6.2-x86_64-disk.img segment 2
cirros-0.6.2-x86_64-disk.img segment 0
cirros-0.6.2-x86_64-disk.img segment 1
cirros-0.6.2-x86_64-disk.img
查看cirros镜像的存储路径:
[root@controller ~]# swift stat test cirros-0.6.2-x86_64-disk.img
Account: AUTH_bf368e64a3e64d9c9ae695253f1f3879
Container: test
Object: cirros-0.6.2-x86_64-disk.img
Content Type: application/octet-stream
Content Length: 21430272
Last Modified: Mon, 24 Jun 2024 09:11:02 GMT
ETag: "e5c616113b5ad131acefa934a62d0593"
Manifest: test_segments/cirros-0.6.2-x86_64-disk.img/1718876837.659604/21430272/10000000/
Meta Mtime: 1718876837.659604
Accept-Ranges: bytes
X-Timestamp: 1719220261.38907
X-Trans-Id: tx8617f11598864c119256e-006679385b
X-Openstack-Request-Id: tx8617f11598864c119256e-006679385b
查看存储路径中的数据片:
[root@controller ~]# swift list test_segments
cirros-0.6.2-x86_64-disk.img/1718876837.659604/21430272/10000000/00000000
cirros-0.6.2-x86_64-disk.img/1718876837.659604/21430272/10000000/00000001
cirros-0.6.2-x86_64-disk.img/1718876837.659604/21430272/10000000/00000002
可以看到,cirros镜像在上传至swfit对象存储中被分片存储了,单个存储片的大小为10M,因为该镜像大小为21M左右,所有分成了三个存储片。