常用 S3 操作
把 endpoint、AK、SK 准备好后,aws-cli 的常用命令可以直接使用。区域可以填任意值,服务端按签名与桶配置处理。
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=us-east-1
E=http://127.0.0.1:9000
aws --endpoint-url $E s3 mb s3://photos
aws --endpoint-url $E s3 cp ./cover.jpg s3://photos/cover.jpg
aws --endpoint-url $E s3 ls s3://photos/
aws --endpoint-url $E s3 presign s3://photos/cover.jpg --expires-in 3600
aws --endpoint-url $E s3 rm s3://photos/cover.jpg
大文件会自动走 multipart。Range GET、x-amz-meta-*、Storage Class 与对象标签都按 S3 语义处理。
Multipart、partNumber 与 Range
除普通分块上传外,还支持从已有对象复制分段、列举未完成上传,以及按段读取。
# 从源对象复制一段作为 part(区间为闭区间)
aws --endpoint-url $E s3api upload-part-copy --bucket photos \
--key big.bin --upload-id <upload-id> --part-number 2 \
--copy-source photos/source.bin --copy-source-range bytes=0-5242879
# 列举未完成的分块上传
aws --endpoint-url $E s3api list-multipart-uploads --bucket photos
# 读取第 2 段
aws --endpoint-url $E s3api get-object --bucket photos --key big.bin \
--part-number 2 part2.bin
- ListObjects v1 已实现:
aws s3api list-objects支持 marker / delimiter / max-keys。 - HEAD 支持单区间 Range;多区间 GET 不返回
multipart/byteranges,服务端会剥离 Range 并返回 200 整对象。 - 若客户端把 Range 计入 SigV4 SignedHeaders,剥离后验签会失败(403
SignatureDoesNotMatch);预签名 URL 不受影响。
控制台
控制台是 React 19 + antd 的单页应用,覆盖桶、对象、用户、访问密钥、权限、访问点、作业、Inventory、分层与 Raft 集群状态。
- 开发模式:后端
9000,前端5173。 - Compose 模式:控制台由 nginx 提供,默认
8080。 - 登录后先创建访问密钥,再让 aws-cli 或 SDK 使用。
控制台里的桶模式、版本控制、生命周期与访问点操作,最终都会走同一套控制面命令。单机是本地 SQLite,强一致模式经 Raft 提交。
版本与生命周期
版本控制支持 Off / Enabled / Suspended 三态。开启后删除对象会生成 delete marker,旧版本仍可读取与恢复;Suspended 下只替换 null 版本。
aws --endpoint-url $E s3api put-bucket-versioning \
--bucket photos --versioning-configuration Status=Enabled
aws --endpoint-url $E s3api list-object-versions --bucket photos
aws --endpoint-url $E s3api get-object --bucket photos --key cover.jpg \
--version-id <version-id> cover.old.jpg
生命周期规则可在控制台配置,也可以走 S3 API。支持 tag / size / And Filter、Expiration.Date、ExpiredObjectDeleteMarker、多转换、noncurrent expiration / transition 与分层 Restore。对象生命周期图如下。
加密与对象锁
oss 支持 SSE-S3 与 SSE-KMS 两种服务端加密模式,密钥库启用后访问密钥的 SK 也会加密落库。对象锁需要桶在创建时开启,开启后按保留策略阻止覆盖与删除。
# 服务端加密上传
aws --endpoint-url $E s3api put-object \
--bucket photos --key secret.bin \
--body ./secret.bin --server-side-encryption AES256
# 对象锁桶需要创建时开启
aws --endpoint-url $E s3api create-bucket \
--bucket legal --object-lock-enabled-for-bucket
STS 临时凭据分为 AssumeRole 与 GetSessionToken。AssumeRole 只允许管理员调用,避免子账户自铸管理员会话。
保留期与匿名访问
对象锁桶可对指定版本设置保留期。COMPLIANCE 到期前不可缩短或清除;GOVERNANCE 需要 x-amz-bypass-governance-retention 才能缩短。控制台对象列表会显示 retention / legal-hold 状态。
aws --endpoint-url $E s3api put-object-retention \
--bucket legal --key doc.pdf --version-id <version-id> \
--retention 'Mode=COMPLIANCE,RetainUntilDate=2027-01-01T00:00:00Z'
aws --endpoint-url $E s3api get-object-retention \
--bucket legal --key doc.pdf --version-id <version-id>
匿名访问只对数据面对象操作生效,且必须由桶策略显式 Allow;控制面、桶级操作、对象锁头一律拒绝。示例策略:
{
"Statement": [{
"Effect": "Allow",
"Principal": {"AWS": "*"},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::photos/*"
}]
}
配置后可用无签名请求读取:curl $E/photos/cover.jpg -o cover.jpg。传输层加密(监听器、Raft/mesh、site/repl/tier、Kafka)见 安装页的 TLS 章节。
事件与复制
事件通知通过 oss.toml 配置 Kafka 目标,桶上再写通知配置。S3 Select 走事件与查询路径,桶复制与多站点复制负责把版本送到另一个位置。
- 事件:桶事件写入
event_outbox,worker 投递到 Kafka,失败重试与死信可查。 - Select:支持 CSV / JSON 查询,结果流式返回,限制在内存预算内。
- 复制:每桶规则、PENDING 到 COMPLETED 状态、停机积压追平与 marker 处理。
强一致
强一致模式把控制面放到 Raft 上,并把跨站点数据面分成两种模式。两者互斥,按桶或按集群选择。
| 模式 | 写语义 | 适合 |
|---|---|---|
| sync 桶 | 远端先确认,再提交本地;远端不可达返回 503,不静默降级 | 合规桶、小对象、跨站点强一致 |
| stretch 2×6 | 两站点各 6 盘,EC 8+4,单站点 fail-closed | 双站点数据面,不依赖 witness |
| 3-voter Raft | A/B 数据站点 + C witness,quorum 2 | 控制面高可用、成员变更与恢复 |
sync 桶通过控制台创建时选择 sync 模式,或调用控制面 API:
curl -s -X POST http://127.0.0.1:9000/api/v1/buckets \
-H "authorization: Bearer <token>" \
-H 'content-type: application/json' \
-d '{"name":"compliance","replication_mode":"sync"}'
强一致的成员变更、witness 部署、cutover 与 force recovery 是运维动作,按 README 的 runbook(随发布同步)执行。不要在运行中的集群手改 raft.db。
控制面滚动升级
控制面可以逐节点替换:保持 [raft].feature_level = 1(默认),先升级所有 voter 与 learner;leader 的生效级别取当前 voter/learner 的最小值。全部节点都升级后,再把 feature_level 改为 2 或 3(范围 1..=3)并重启,激活会写入 schema_meta.raft_feature_level。级别 3/OSSCTL3 当前承载账户、运行态扩展与 Ext 容器,生产 Ext registry 为空。
- 回滚只在激活前可行(停集群、换回旧二进制、删除
feature_level键后启动);激活后必须换回支持该级别的二进制。 - 成员 add/promote 会预检目标节点的 wire/feature 级别,混合版本时返回 409 并拒绝。
- 数据面自 v1.19.0 起为 DP-1 混版门控(NodeHealth wire/epoch/hash;ListObjects V1 带
x-oss-degraded: list-marker、LMU 带mpu-union,ListObjectVersions 与 MPU 转发对旧对端 fail-closed);v1.20.0 起 mesh gRPC 入站支持 TLS 物料热轮换(新连接取新配置,旧连接保持旧物料),并已有同版本 3 节点与 v1.13.1 旧二进制的滚动 e2e 通过;生产升级仍需维护窗口。
运维命令
服务端二进制自带巡检、修复、扩容与清理命令。建议先用只读或 dry-run 看报告,再执行写操作。
oss-server clean 1 # 回收 1 天前的 tmp/trash 残骸
oss-server fsck # 全盘巡检,报告落 .oss.sys/fsck/
oss-server fsck --repair # 最小修复:删孤儿 + 读时修
oss-server heal # fsck --repair + 桶目录补建
oss-server scrub # 深度巡检,逐块对偶校验
oss-server rebalance --dry-run
oss-server rebalance --apply
oss-server cluster-shrink plan --to shrink.toml --json # 只读规划
oss-server cluster-shrink apply --plan plan.json --yes # 离线拷贝
oss-server cluster-shrink verify --plan plan.json # 校验
oss-server cluster-shrink commit --plan plan.json --yes # 写 topo v4
oss-server cluster-shrink rollback --plan plan.json --yes # commit 前回滚
巡检与修复不要和在途上传、写入并跑。每节点各自执行,远端孤儿只由该节点自己回收。
能力边界
以下能力仍是明确非目标,或需要单独的架构工作;调用会 fail-closed 或返回 501:
| 边界 | 现状 |
|---|---|
| AP 匿名 / SourceVpc | 已支持(策略 Principal:"*" ∩ 桶策略;SourceVpc 为来源证明) |
| AP 跨账户 / SourceVpce | 已支持账户根 principal、aws:SourceVpce 来源证明与静态端点 registry(注册断言,端点为 active 且归属账户匹配);HTTP 信任链 E2E 已覆盖(重复/畸形头、非可信 peer、缺 ConnectInfo fail-closed);VPC 端点真实 PrivateLink 身份仍不做 |
| 多租户账户 MVP | 已支持(账户/成员/状态/桶数配额(Raft leader append 前/standalone 写锁内原子);账户写已走 Raft;软字节配额仅告警;管理员 UI 已交付;硬字节/对象数配额仍不做) |
| M7 未映射 REPLICA 对账 | 已支持(管理员列出/点名删除;默认 dry-run,绝不按内容匹配) |
| DP-1 数据面混版 | 已支持门控(NodeHealth wire/epoch/hash;V1 列表 list-marker、LMU mpu-union 降级;ListObjectVersions/MPU 转发 fail-closed);DP-2 mesh 入站 TLS 热轮换已交付;滚动 e2e 已在同版本与 v1.13.1 旧二进制上通过 |
| M3 缩容(shrink) | plan/apply/verify/commit/rollback 已交付(离线、全节点 maintenance、显式 slot 目标;commit 写 topology v4 作回退防线);4→3 真进程 loopback e2e 已交付;单机→集群仍为重新灌入 |
| Level C / OSSCTL3 | 地基(feature level 1..3;OSSCTL3 扩展区;Ext 容器 registry 为空);v1.20.1 ↔ v1.21.1 控制面混版已验证(147/0/0);v1.13.1 旧端不支持;生产 Ext 命令与完整双向混写未交付 |
| Raft 租户账户 | 账户/成员写路径已改走 Raft 命令(8 个 level-3 ControlCommand,按 username 自然键;OSSCTL3 快照含账户行);软字节配额已交付(只告警不阻写);跨账户共享与 canonicalization worker 未交付 |
| 账户软字节配额 | 已支持(GET /accounts/{id}/usage + PUT /accounts/{id}/soft-quota;仅告警不阻写;用量为全量列举,集群丢 peer 时 complete=false/头 partial;硬字节与对象数配额不做) |
| M8 多节点运行时 | jobs/job_tasks 与 Restore 受理行(feature 4)、inventory 三表与 lifecycle 游标(feature 5)经 Raft 复制;全 peer 达标才启用(旧节点单向门);schedule lease/worker takeover 与 tier restore 后续状态未交付 |
| Inventory 增量 / 跨账户目标 | 已支持(增量水位为节点本地;跨账户目标仅管理员可配置) |
| AbortIncompleteMultipartUpload | 已支持(生命周期规则) |
| Batch 抢占 / 跨账户清单 | 已支持(同提交者协作抢占;跨账户清单仅管理员;跨账户通知仍不做) |
| tier 直读(含 Range) | 已支持(OSS_TIER_DIRECT_READ=1 默认关;分块 SHA-256 校验,无表/漂移 fail-closed;归档/直读绑定源整对象 SHA-256;非 Range 仍先 Restore) |
| Select BZIP2 | 已支持(CSV/JSON 输入;Parquet 仍要求 CompressionType=NONE) |
| MPU 跨节点 | 已支持(新 upload_id 属主路由/流式转发;存量裸 UUID 仍粘原节点) |
| CMK 删除 / rewrap | 已支持(删除有引用即 409;rewrap 默认 dry-run,本地节点口径) |
AssumeRoleWithWebIdentity | 已支持(默认关闭;本地 JWKS,需配置 issuer/audience/roles) |
| 任意双向混合版本 / 数据面滚动 | 不做;仅控制面滚动升级窗口;OSSCTL2/3 已支持 level-2/3 快照 |
已知限制:复制/tier 摄入已透传 part_sizes;签名内的多区间 Range 返回确定性 400 InvalidArgument;MPU 存量裸 UUID 仍粘原节点;tier 直读默认关闭且仅支持 Range;未映射 legacy 副本需管理员对账;AP 转发头只在 TLS 监听器 + 可信对端 CIDRS 下采信;DP-1 混版窗口的 ListObjects V1/LMU 可能重复或缺项(降级头标记),ListObjectVersions 与 MPU 转发对旧对端 fail-closed。完整清单见 README 与版本日志。