华为云OBS大文件上传调优实战

举报
yd_221506059 发表于 2026/10/13 00:18:04 2026/10/13
【摘要】 一个 20 GB 的备份文件往 OBS 传要 3 小时,把并发从 5 拉到 32 后速度反而掉了一半,重试率飙到 7%。本文用阶梯压测定位并发平台期,解释重试风暴为何是负反馈,并给出分片大小的两条下限公式(10000 分片上限与带宽时延积估算)。文末还提醒一个容易忽略的成本坑:未完成的分段上传会持续计费,需要配生命周期规则清理。

华为云 OBS 大文件上传调优:为什么并发从 8 调到 32 反而更慢

一个 20 GB 的备份文件往 OBS 传,默认参数要 3 小时。直觉是"加并发",于是把并发从 5 一路拉到 32——结果速度下降了一半,重试率飙到 7%。这篇文章把分段上传的参数、带宽积、重试风暴串起来,给出一套可以照着做阶梯压测的方法。

一、先把问题量化

压测对象:单文件 20 GB,从本地机房经公网传到 OBS,客户端 8 核 16 GB,出口带宽 1 Gbps(理论峰值 125 MB/s)。

第一轮把并发数当唯一变量,阶梯式拉高:

并发数 平均吞吐 重试率 客户端 CPU
1 18 MB/s 0% 15%
4 62 MB/s 0.2% 35%
8 96 MB/s 0.5% 62%
16 104 MB/s 1.8% 88%
32 71 MB/s 7.4% 97%
64 43 MB/s 21% 99%

曲线是标准的"先升后降":平台期在 8~16 之间,超过 16 之后吞吐掉头向下,同时重试率从 0.5% 涨到 7.4%。

二、为什么加并发会变慢

三个原因,任何一个先撞到天花板,继续加并发都只会制造重试:

① 出口带宽已经饱和。 1 Gbps 网卡的实际上限约 115~120 MB/s,实测 104 MB/s 已经是 90% 利用率。此时再开更多连接,不会带来更多带宽,只会让每个连接分到的带宽变少、单分片传输时间变长,进而更容易触发超时。

② 重试风暴是负反馈。 超时的分片会重传,重传又占用本已饱和的带宽,导致更多分片超时。重试率从 0.5% 到 7.4% 不是线性恶化,而是跨过临界点后的雪崩。

③ 客户端 CPU 成为次生瓶颈。 并发 32 时客户端 CPU 到 97%,分片校验(CRC/MD5 计算)和内存拷贝抢不到 CPU,进一步拉长单分片耗时。

结论:并发数不是"越大越好"的旋钮,而是有明确平台期的参数,且平台期位置由最窄的那一段决定——带宽、CPU、还是对端限速。

三、分片大小:先算约束,再谈调优

分段上传有两个硬约束(与 S3 协议一致):

  • 单个分片 100 KB ~ 5 GB
  • 分片总数 不超过 10000

由此得到分片大小的下限公式:

partSize ≥ 文件大小 / 10000

20 GB 的文件,分片至少要 2 MB 才能装下。但"能装下"离"跑得快"还很远。

分片太小的代价:请求数爆炸、每次请求的签名/建连/TLS 开销占比上升、服务端小请求处理效率低。

分片太大的代价:单个分片重传的成本剧增。一次分片失败就要重传整个分片——100 MB 的分片重传一次,等于白传 100 MB。

更靠谱的下限来自带宽时延积(BDP):

单连接吞吐 ≈ 窗口大小 / RTT

跨地域公网 RTT 通常在 20~50 ms,单连接很难跑满高带宽,必须靠多连接叠加。经验取值是让单分片的传输时间远大于 RTT(至少 10 倍以上),否则 TCP 慢启动还没结束,分片就传完了,连接利用率极低。

按 RTT 30 ms、单连接目标 15 MB/s 估算:

partSize ≥ 15 MB/s × 0.03 s × 10 ≈ 4.5 MB

实测下来,16~64 MB 是公网跨地域上传的甜点区间:20 GB 文件切成 32 MB 分片是 640 片,远低于 10000 的上限,单个分片重传的代价也可接受。

四、可落地的配置

1. 用 obsutil 批量上传

obsutil 的并发与分片相关配置项(键名以 obsutil help 的实际输出为准,不同版本略有差异):

# 查看当前配置
./obsutil help

# 关键配置项大致对应:
#   defaultBigfileThreshold  超过该值才走分段上传
#   defaultPartSize          分片大小(MB)
#   defaultParallels         并发数

调完再跑,务必带断点续传相关参数,失败后只补缺口,不重传全量:

./obsutil cp /data/backup.tar.gz obs://my-bucket/backup/ -f -u

2. 用 SDK 时显式指定分片与并发

from obs import ObsClient

client = ObsClient(
    access_key_id=AK,
    secret_access_key=SK,
    server="https://obs.cn-north-4.myhuaweicloud.com",
)

resp = client.putFile(
    bucketName="my-bucket",
    objectKey="backup/backup.tar.gz",
    file_path="/data/backup.tar.gz",
    partSize=32 * 1024 * 1024,   # 32 MB
    taskNum=8,                   # 并发 8,取平台期的 70%
)

注意 partSize 和 taskNum 的乘积决定了内存水位:32 MB × 8 = 256 MB 的缓冲区,在内存吃紧的机器上要一起算进去。

3. 并发数按阶梯压测取平台期的 70%

不要拍脑袋定并发。方法很简单:从 4 开始翻倍,每次跑 2~3 分钟,记录吞吐和重试率,在吞吐首次不再显著上升(涨幅 < 10%)时停止,然后回退到该值的 70%。回退这一步是为了给突发重试留出余量——压测环境干净,线上不一定。

4. 多文件并发要统一限流

最容易踩的坑:为了传 100 个小文件,起 100 个线程,每个线程内部又开 8 个分片并发 = 800 并发,直接把网卡和 CPU 打爆。

正确做法:全局限流。 用一个信号量控制整个进程的总并发,而不是每个文件各自开池。

from concurrent.futures import ThreadPoolExecutor

GLOBAL_PARALLEL = 8   # 全局总并发,不是每文件
with ThreadPoolExecutor(max_workers=GLOBAL_PARALLEL) as pool:
    futures = [pool.submit(upload_one, f) for f in files]

五、一个容易被忽略的存储成本坑:未完成的分段上传

分段上传如果中途失败或被中断,已经上传的分片会留在桶里并持续计费,但在控制台的"对象列表"里看不到——因为它们还不是一个完整对象。

上传失败的次数多了,这部分"碎片"会悄悄累积。解决办法是配一条生命周期规则,自动清理未完成的分段上传:

规则类型:清理未完成的分段上传
生效范围:整个桶(或指定前缀)
过期天数:7 天

配好之后,超过 7 天仍未完成的分段上传会被自动回收。这条规则建议所有用分段上传的桶都加上。

六、验证口径

调优前后必须用同一套口径,否则数据没意义:

指标 含义 采集方式
平均吞吐 总字节 / 总耗时 上传工具输出
重试率 重试分片数 / 总分片数 客户端日志统计
分片耗时 P99 单分片从发起到完成 客户端埋点
客户端 CPU / 内存峰值 判断是否成为瓶颈 系统监控

重点看分片耗时 P99,而不是平均值。 平均值好看但 P99 很高,说明已经在临界点附近,线上流量一抖就会雪崩。

七、小结

四句话:

  1. 并发数有平台期,位置由最窄的一段决定(带宽 / CPU / 对端限速),超过平台期加并发只会制造重试风暴。
  2. 分片大小先算下限再选甜点:文件大小 / 10000 是硬下限,BDP 估算给出可用下限,公网跨地域场景 16~64 MB 比较稳。
  3. 多文件场景必须全局限流,别让每个文件各自开线程池,否则并发数是乘法不是加法。
  4. 给桶配一条清理未完成分段上传的生命周期规则,否则失败的分片会一直计费。

如果只记一句:上传慢的时候,先看出口带宽和 CPU 是不是已经满了,再决定要不要加并发。


建议标签:对象存储 OBS、云存储、性能优化、数据传输

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。