返回列表

构建基于 AWS Serverless 的自动化图像处理流水线

发布时间:2025-11-15 02:40

1. 背景与需求

在现代 Web 应用和移动应用开发中,图片上传是一个非常常见的功能。然而,用户上传的图片往往尺寸不一、格式各异。直接将原始大图展示给终端用户会导致加载缓慢、流量浪费。


痛点:

  • 传统服务器处理图片需要维护 EC2 实例,应对流量波峰波谷时缺乏弹性。
  • 手动压缩或裁剪图片效率低下。


解决方案:

利用 AWS 的 Event-Driven(事件驱动) 架构。当用户将图片上传到 S3 存储桶时,自动触发 Lambda 函数进行缩略图生成,并将处理后的图片存入另一个存储桶。全程无需管理服务器,按调用次数付费。


2. 架构设计

我们将使用以下 AWS 服务:

服务

核心作用

架构关键点

Amazon S3 (Simple Storage Service)

用于存储原始图片和处理后的图片

双存储桶策略:使用两个不同的存储桶(源和目标)来防止 Lambda 触发无限循环

AWS Lambda

运行 Python 代码,执行图像缩放逻辑
使用 Layers:通过 Lambda Layers 引入 Pillow 等第三方图像处理库

IAM (Identity and Access Management) 

管理权限,确保 Lambda 有权读写 S3
最小权限原则:仅授予 Lambda 读源 S3 和写目标 S3 的权限

架构图

(下图展示了自动化图像处理流水线的事件驱动架构)


架构关键点: 为了防止“无限循环”(Infinite Loop),务必使用两个不同的 S3 存储桶(一个用于源,一个用于目标),或者使用不同的文件夹前缀。本文采用两个存储桶的方案。


3. 实施步骤

3.1. 第一步:创建 S3 存储桶

登录 AWS 控制台,进入 S3 服务。

创建两个存储桶(名称需全球唯一,以下仅为示例):

  •   源存储桶: `my-app-upload-source`
  •   目标存储桶: `my-app-upload-resized`

保持默认设置(在该演示中不需要公开访问权限)。


3.2. 第二步:创建 IAM 角色 (Execution Role)

Lambda 需要权限来读取源存储桶并写入目标存储桶,同时需要写 CloudWatch Logs。

1.  进入 IAM 控制台 -> Roles -> Create role。

2.  选择 AWS Service -> Lambda。

3.  添加权限策略。关联 `AWSLambdaBasicExecutionRole` 并附加以下 JSON 策略(请将存储桶名称替换为您的实际名称):


```json

{

   "Version": "2012-10-17",

   "Statement": [

       {

           "Effect": "Allow",

           "Action": [

               "s3:GetObject"

           ],

           "Resource": "arn:aws:s3:::my-app-upload-source/"

       },

       {

           "Effect": "Allow",

           "Action": [

               "s3:PutObject"

           ],

           "Resource": "arn:aws:s3:::my-app-upload-resized/"

       }

   ]

}

```


3.3. 第三步:编写 Lambda 函数

由于 Python 原生库不支持复杂的图像处理,我们需要使用 Pillow (PIL) 库。在 AWS Lambda 中,推荐使用 Lambda Layers 来引入第三方库。

1.  进入 Lambda 控制台 -> Create function。

2.  名称: `ImageResizer`,运行时选择 Python 3.9 或更新版本。

3.  权限: 选择刚才创建的 IAM 角色。

4.  添加 Layer: 引入 Pillow 库。

5.  代码实现 (`lambda_function.py`):


```python

import boto3

import os

import uuid

from urllib.parse import unquote_plus

from PIL import Image

import PIL.Image


目标 Bucket 名称 (建议通过环境变量配置,此处为演示直接硬编码)

DEST_BUCKET = 'my-app-upload-resized'

s3_client = boto3.client('s3')


def resize_image(image_path, resized_path):

   """生成缩略图,最大尺寸 128x128"""

   with Image.open(image_path) as image:

       image.thumbnail((128, 128))

       image.save(resized_path)


def lambda_handler(event, context):

   for record in event['Records']:

       bucket = record['s3']['bucket']['name']

       key = unquote_plus(record['s3']['object']['key'])

       

        定义临时路径,Lambda 只能在 /tmp 目录下进行文件操作

       download_path = '/tmp/{}{}'.format(uuid.uuid4(), key)

       upload_path = '/tmp/resized-{}'.format(key)

       

       print(f"Processing file: {key} from bucket: {bucket}")

       

       try:

            1. 下载图片

           s3_client.download_file(bucket, key, download_path)

           

            2. 处理图片

           resize_image(download_path, upload_path)

           

            3. 上传回目标 Bucket

           s3_client.upload_file(upload_path, DEST_BUCKET, key)

           

           print(f"Successfully resized {key} and uploaded to {DEST_BUCKET}")

           

       except Exception as e:

           print(f"Error processing object {key}: {e}")

            抛出异常,以便 CloudWatch Logs 记录错误

           raise e

           

   return {

       'statusCode': 200,

       'body': 'Image processed successfully'

   }

```


3.4. 第四步:配置 S3 触发器

这是连接架构的关键一步。

1.  在 Lambda 函数页面概览图部分,点击 Add trigger。

2.  选择 S3。

3.  Bucket 选择: `my-app-upload-source` (源存储桶)。

4.  Event type: `All object create events` (所有对象创建事件)。

5.  Suffix (可选): `.jpg` 或 `.png` (限制仅触发特定格式)。

6.  勾选 "I acknowledge..." 并点击 Add。


4. 测试与验证

现在,让我们见证奇迹的时刻:

1.  准备一张名为 `test-image.jpg` 的大图。

2.  进入 S3 控制台,打开 `my-app-upload-source` 存储桶。

3.  点击 Upload 上传图片。

4.  等待几秒钟。

5.  转到 `my-app-upload-resized` 存储桶。

6.  验证: 您应该能看到同名的文件,下载查看,你会发现它的尺寸已经被压缩到了 128x128 像素以内。


故障排查 (Troubleshooting)

  • 查看 CloudWatch Logs: 进入 Lambda 的 Monitor 选项卡,点击 View logs in CloudWatch。查看是否有 `Permission Denied` 或 `ImportError` (Pillow 库缺失) 错误。
  • 检查超时设置: 如果是超大图片,可能需要将 Lambda 的 Timeout 从默认的 3秒调整为 10秒或更多。


5. 总结与优化建议

通过这个方案,我们构建了一个全自动、高可用、零维护的图像处理服务。


成本分析:


  • S3: 按存储量和请求数收费(非常低廉)。
  • Lambda: 每月前 40万 GB-秒 的计算时间是免费的(Free Tier),对于中小型应用几乎零成本。



进阶优化方向:


  • S3 Lifecycle Policy: 在源存储桶设置生命周期规则,自动删除 1 天后的原始图片以节省成本。
  • SNS/SQS 集成: 如果处理失败,将事件发送到死信队列(DLQ)进行后续重试或报警。
  • Metadata 提取: 修改代码,利用 Amazon Rekognition 识别图片内容(如:识别图片中是否包含违规内容)后再决定是否发布。



如果您觉得这篇文章对您有帮助,欢迎转发或在下方留言交流 AWS 技术心得!

顶部