基于 Huawei Cloud FunctionGraph 构建弹性图片处理服务的实践
基于 Huawei Cloud FunctionGraph 构建弹性图片处理服务的实践
一、为什么选择 Serverless
在传统的图片处理架构中,我们通常需要长期运行一台或多台 ECS 来承载图片压缩、缩略图生成、水印添加等任务。这类业务的典型特点是突发性强、单次耗时短:白天流量高峰可能瞬间涌来数千个处理请求,深夜却几乎为零。为峰值配置资源,意味着大部分时间服务器处于空转状态,成本浪费严重。
华为云函数工作流 FunctionGraph(Serverless 函数计算服务)为这类场景提供了理想解法:按需执行、按量计费、自动弹性。函数只在请求到达时被拉起,执行结束即释放,配合 OBS 事件触发器,可以实现"图片上传即处理"的事件驱动架构。
二、整体架构设计
架构分为三层:
- 存储层:OBS 桶存放原始图片,按日期分目录组织;
- 计算层:FunctionGraph 函数订阅 OBS 的对象创建事件(OBS的事件通知),收到事件后自动拉取图片进行处理;
- 结果层:处理完成的缩略图回写至另一个 OBS 桶(或同桶不同前缀),并通过 CDN 对外分发。
整个链路无需任何常驻服务器,事件通知由华为云内部完成投递,端到端延迟通常在秒级。
三、核心代码示例
以下是一个基于 Python 运行时的缩略图生成函数核心逻辑:
# -*- coding:utf-8 -*-
import json
import obs_sdk # FunctionGraph 内置 OBS 依赖
def handler(event, context):
src_bucket = event['Records'][0]['s3']['bucket']['name']
src_key = event['Records'][0]['s3']['object']['key']
obs = obs_sdk.get_client(context)
resp = obs.getObject(bucket=src_bucket, key=src_key)
raw = resp['body'].read()
# 生成 300px 宽度的缩略图
from PIL import Image
import io
img = Image.open(io.BytesIO(raw))
ratio = 300 / img.width
thumb = img.resize((300, int(img.height * ratio)))
buf = io.BytesIO()
thumb.save(buf, format='JPEG', quality=85)
dst_key = 'thumbs/' + src_key.rsplit('/', 1)[-1]
obs.putContent(bucket='processed-bucket', key=dst_key,
content=buf.getvalue())
return json.dumps({"status": "ok", "output": dst_key})
代码要点说明:
event中携带了触发事件源(OBS 上传对象)的桶名与对象键,无需轮询;context提供了临时访问凭证与 OBS 客户端,函数无需硬编码密钥,安全性更好;- 缩略图统一写入独立前缀,避免再次触发自身造成事件循环。
四、实践要点与踩坑经验
1. 合理设置内存与超时。图片解码对内存消耗较大,实测 5MB 以上大图建议配置 1024MB 以上内存,超时设为 10-30 秒,避免冷启动叠加解码时间导致失败。
2. 防止事件循环。若处理结果写回同一个桶且同源前缀,函数会被自己触发。务必使用独立桶或独立前缀,并在桶的事件通知规则中排除目标前缀。
3. 借助并发限流保护下游。FunctionGraph 默认弹性无上限,如果下游服务(如数据库、第三方 API)承压能力有限,应配置最大并发数,平滑流量洪峰。
4. 日志与观测。开启函数的云日志(LTS)采集,结合请求耗时指标观察冷启动占比;对耗时敏感的业务可开启预留实例,消除冷启动延迟。
5. 成本收益。按每日约 5000 次处理请求估算,Serverless 方案的费用仅为同规格常驻 ECS 方案的十分之一左右,且免去了运维巡检的工作量。
五、总结
FunctionGraph + OBS 的事件驱动组合,把"图片处理"这类典型异步任务从"养服务器"变成了"养函数"。开发者只需聚焦业务逻辑本身,弹性、容错、计费全部交给平台。对于音视频转码、数据清洗、定时报表等同样具有突发特征的场景,这套模式都可以低成本快速复制,是云原生时代值得优先考虑的架构选择。
- 点赞
- 收藏
- 关注作者
评论(0)