Swift 深度解析:OpenStack 对象存储原理与实践

Swift 深度解析:OpenStack 对象存储原理与实践

定位与职责

Swift 是 OpenStack 的对象存储服务,设计目标是存储海量非结构化数据:

  • 存储和检索任意大小的对象(文件)
  • 高可用、高持久性(多副本)
  • 最终一致性模型(AP 系统)
  • 兼容 S3 API(通过 swift3 中间件)
  • 典型用途:镜像存储、备份、日志归档、静态资源

架构总览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
客户端请求


swift-proxy(代理层,无状态,可水平扩展)

├── 认证中间件(Keystone)
├── 速率限制中间件
└── 路由层(一致性哈希环)

├── swift-account-server ← 账户元数据
├── swift-container-server ← 容器元数据(对象列表)
└── swift-object-server ← 对象数据存储

└── 后台进程
├── swift-object-replicator ← 副本同步
├── swift-object-auditor ← 数据完整性检查
└── swift-object-expirer ← 过期对象清理

核心概念

三层命名空间

1
2
3
4
5
6
Account(账户)
└── Container(容器,类似目录)
└── Object(对象,文件 + 元数据)

URL 格式:
https://swift.example.com/v1/{account}/{container}/{object}

存储策略(Storage Policy)

1
2
3
4
5
# 不同容器可以使用不同的存储策略
# 策略 0:3 副本(默认)
# 策略 1:纠删码(Erasure Coding,节省空间)

openstack container create --storage-policy ec-policy my-container

一致性哈希环(Ring)

这是 Swift 最核心的设计,解决了分布式存储中数据定位问题。

哈希环原理

1
2
3
4
5
6
7
哈希空间:0 ~ 2^32 - 1(约 43 亿)

将哈希空间均匀分成 2^部分数 个分区(partition
每个分区分配到具体的存储节点(device)

对象定位:
MD5(account/container/object) → 哈希值 → 分区 → 节点
1
2
3
4
5
6
7
8
9
10
# swift/common/ring/ring.py

class Ring:
def get_nodes(self, account, container=None, obj=None):
"""返回存储该对象的节点列表(副本数个节点)"""
key = hash_path(account, container, obj)
# 通过哈希值找到分区
part = bisect_left(self._part_shift, key) >> self._part_shift
# 返回该分区对应的所有副本节点
return part, self._get_part_nodes(part)

副本放置策略

1
2
3
4
5
6
7
分区 P 的 3 个副本放置规则:
- 副本 1:节点 A(zone 1, region 1
- 副本 2:节点 B(zone 2, region 1) ← 不同 zone
- 副本 3:节点 C(zone 1, region 2) ← 不同 region(如果有)

Zone 隔离:不同机架/机柜
Region 隔离:不同数据中心

节点扩容(Ring 重平衡)

1
2
3
4
5
6
7
8
9
10
# 添加新节点到 Ring
swift-ring-builder object.builder add \
--region 1 --zone 1 --ip 10.0.0.5 --port 6200 \
--device sdb --weight 100

# 重平衡(计算新的分区分配)
swift-ring-builder object.builder rebalance

# 分发新的 Ring 文件到所有节点
rsync object.ring.gz all-nodes:/etc/swift/

扩容时只有部分分区需要迁移,不会全量重新分配(一致性哈希的优势)。


数据写入流程

1
2
3
4
5
6
7
8
9
10
11
12
13
客户端 PUT /v1/account/container/object


swift-proxy
1. 计算哈希,找到 3 个目标节点
2. 并发向 3 个节点发送写请求

├──► Node-1: 写入成功
├──► Node-2: 写入成功
└──► Node-3: 写入超时(网络问题)

▼ 2/3 节点写入成功 → 返回客户端 201 Created
(最终一致性:Node-3 稍后通过 replicator 同步)

写入仲裁(Quorum)

1
2
3
4
5
6
7
# swift/proxy/controllers/obj.py

# 写入成功的最小节点数 = floor(副本数 / 2) + 1
# 3 副本 → 需要 2 个节点成功
# 5 副本 → 需要 3 个节点成功

min_conns = quorum_size(self.app.object_ring.replica_count)

数据一致性保障

Replicator(副本同步)

1
2
3
4
5
6
7
8
9
10
11
# swift/obj/replicator.py

class ObjectReplicator:
def replicate(self):
# 遍历本节点所有分区
for partition in self.get_local_partitions():
# 找到该分区的其他副本节点
nodes = self.ring.get_part_nodes(partition)
# 与其他节点同步(rsync 或 SSYNC 协议)
for node in nodes:
self.sync(partition, node)

Auditor(数据审计)

1
2
3
4
5
6
7
8
9
10
11
12
13
# swift/obj/auditor.py

class ObjectAuditor:
def audit_all_objects(self):
# 遍历所有对象文件
for obj_path in self.get_all_objects():
# 计算 MD5 校验和
computed_md5 = md5_of_file(obj_path)
stored_md5 = get_stored_etag(obj_path)
if computed_md5 != stored_md5:
# 数据损坏,标记为隔离(quarantine)
self.quarantine(obj_path)
# Replicator 会从其他副本恢复

纠删码(Erasure Coding)

EC 策略用更少的存储空间实现相同的持久性:

1
2
3
4
5
6
3 副本:存储开销 3x,可容忍 1 节点故障
EC 10+4:存储开销 1.4x,可容忍 4 节点故障

EC 原理:
原始数据 → 分成 10 个数据片段 + 4 个校验片段
任意 10 个片段可以恢复完整数据
1
2
3
4
5
6
7
8
# 创建 EC 存储策略
# /etc/swift/swift.conf
[storage-policy:1]
name = ec-policy
policy_type = erasure_coding
ec_type = liberasurecode_rs_vand
ec_num_data_fragments = 10
ec_num_parity_fragments = 4

大对象支持

Swift 单个对象默认最大 5GB,大文件通过分段上传:

1
2
3
4
5
6
7
8
9
# 静态大对象(SLO)
# 1. 分段上传
swift upload mycontainer --segment-size 1G largefile.tar.gz

# 2. 创建 manifest 文件(记录所有分段)
# 自动生成:mycontainer_segments/largefile.tar.gz/timestamp/size/

# 动态大对象(DLO)
# 通过 X-Object-Manifest header 指定分段前缀

中间件体系

Swift 的功能通过 WSGI 中间件栈扩展:

1
2
3
4
5
6
7
8
9
# /etc/swift/proxy-server.conf
[pipeline:main]
pipeline = catch_errors gatekeeper healthcheck \
proxy-logging cache listing_formats \
bulk tempurl ratelimit authtoken \
keystoneauth staticweb copy \
container-quotas account-quotas \
slo dlo versioned_writes symlink \
proxy-server
中间件 功能
authtoken Keystone Token 验证
ratelimit 请求速率限制
slo 静态大对象支持
tempurl 临时 URL(无需认证的临时访问)
staticweb 静态网站托管
versioned_writes 对象版本控制

生产部署要点

1
2
3
4
5
6
7
8
9
10
11
12
13
# 磁盘准备(每块磁盘独立挂载,不做 RAID)
mkfs.xfs -f -i size=1024 /dev/sdb
mount -o noatime,nodiratime,nobarrier /dev/sdb /srv/node/sdb

# Swift 推荐使用 XFS,不建议 ext4
# nobarrier 提升写入性能(需要 UPS 保障)

# 监控关键指标
# 磁盘使用率(每个 device 独立监控)
# Replication 延迟(副本同步是否及时)
# Quarantine 数量(损坏对象数量)
# Async pending(异步更新积压)
swift-recon --all # 查看集群健康状态