用 FunctionGraph + OBS 打造图片自动压缩归档流水线
一、为什么用无服务器做图片处理
内容型业务里,商品图、用户头像、活动素材每天都在增长,原图单张动辄两三 MB,既吃存储成本,又拖慢 CDN 回源。传统做法是写一个常驻压缩服务,但图片处理是典型的突发型负载:白天高峰每秒几十个请求,深夜几乎为零。本文用华为云 OBS 加函数工作流 FunctionGraph,搭一条"上传即压缩、压缩即归档"的流水线。
二、方案设计
链路分四步:原图上传到 OBS 桶的 incoming/ 前缀;OBS 配置 ObjectCreated 事件通知触发函数;函数按长边 1280px 等比缩放并转 WebP;结果写回 processed/,原图移入 archive/ 并配置 30 天生命周期转低频。业务侧只改一个上传地址,处理完全解耦。
三、落地步骤
创建桶 demo-image-pipeline,建立 incoming/、processed/、archive/ 三个前缀。FunctionGraph 的 Python 3.9 自带 OBS SDK,但不含 Pillow,需要把 Pillow 打成 zip 上传到同区域 OBS 桶后引用。函数选事件函数,内存 256MB、超时 30 秒,委托选带 OBS 读写权限的;触发器前缀填 incoming/,后缀 .jpg,.png。
四、核心代码
去掉样板代码后,处理逻辑只有四步:
img = Image.open(io.BytesIO(client.getObject(BUCKET, key).body))
img.thumbnail((1280, 1280))
client.putContent(BUCKET, 'processed/' + name + '.webp', encode(img, 'WEBP'))
client.deleteObject(BUCKET, key)
五、四个必须注意的坑
第一,事件通知是"至少一次"语义,会重复投递,函数必须幂等:写 processed/ 前先 headObject 判断目标是否存在。第二,事件前缀必须限定在 incoming/,不能覆盖 processed/ 和 archive/,否则函数写回结果时会再次触发自己,形成无限循环。第三,大图容易内存溢出,若有 RAW 或超长图,把内存提到 512MB,或对象超过 20MB 直接跳过。第四,超时从默认 3 秒调到 30 秒,能明显降低大图处理失败率。
六、效果
按每天 5000 张、平均 2.5MB 原图计算,压缩后平均约 220KB,存储成本下降九成以上;函数平均执行 800 毫秒,每月计算费用不到 10 元。无服务器的价值不在于省下一台服务器,而在于把图片处理从运维问题变成配置问题。
- 点赞
- 收藏
- 关注作者
评论(0)