
一个社交应用,可能需要根据用户的网络情况和设备情况,加载不同分辨率的图片;或者对用户分享的图片进行亮度或者对比度调节,增强显示效果。
一个图片分享网站,可能需要对用户上传的图片进行再加工。比如将图片进行虚化处理,突出照片中的主体;或者需要将彩色图片变换成黑白图片,增加艺术效果;也可能需要对图片的质量、锐度进行调整;或者对图片进行裁切等操作,避免存储空间无限增长。
一些设计网站,基于版权原因,可能需要给图片添加水印,也可能需要对图片进行格式转换,以适应不同的工作流程。
▲图 1 基于 Lambda Function 的架构
▲图 2 基于 ECS Fargate 的架构
方案部署后,会产生以下系统资源:
Cloudfront Distribution:为整个方案提供缓存服务,降低请求响应的延迟和整个方案的使用成本。
API Gateway:将没有命中缓存的 HTTP 请求转换为 Lambda Function 的事件,从而实现 Lambda Function 的调用。
Lambda Function:根据请求的内容判断图片是否需要处理,无需处理的,直接从 S3 存储中加载图片返回给用户,需要处理的,调用相关代码进行用户要求的图片处理,然后将结果返回给用户。
S3 Bucket:方案中涉及两个存储桶,一个用来存储图片处理的日志数据,另一个是用户指定的先前创建好的 bucket,用来存放原始图片数据。
该实现方式在特殊情况下会受限于 Lambda Function 本身所带来的限制,如处理后图片的大小必须小于 6MB,图片处理时间也有时长限制(Lambda Function 目前最长运行时间为 15 分钟),具体请复制下方链接至浏览器见 Lambda quotas。
https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html
Cloudfront Distribution:为整个方案提供缓存服务,降低请求响应的延迟和整个方案的使用成本。
Application Load Balancer:将没有命中缓存的 HTTP 请求转发到后台的容器,并对 HTTP 请求进行负载均衡。
ECS Fargate:相关的图片处理逻辑会被打包成 docker image,并在 ECS Fargate 上生成相应的容器,响应前端图片处理请求。
S3 Bucket:方案中涉及两个存储桶,一个用来存储图片处理的日志数据,另一个是用户指定的先前创建好的 bucket,用来存放原始图片数据。
● 前置条件
安装 Node.js,且 nodejs 版本 >= 12.0.0
安装 docker Get Docker | Docker Documentation
安装 YARN Installation | Yarn - Package Manager
安装 CDK,Getting startedwith the Amazon CDK
执行 CDK Bootstrap,Bootstrapping
以上组件安装详细步骤读者可查看各组件官方文档。
获取方案代码(可联系我们获得具体代码库地址)
进入上一步下载的文件夹后,执行 cd source/constructs
yarn
yarn test
执行下述命令之一进行部署
■ CDK_DEPLOY_REGION=us-west-2 yarn deploy serverless-ecs-image-handler-stack -c use_vpc_id=xxxxx(此命令会在一个已有的 VPC 中进行部署,请将 xxxxx 替换成您自己的 VPC ID,将 us-west-2 替换成您的 region)。
如果要删除部署的方案,请执行 yarn destroyserverless-ecs-image-handler-stack,如果要继续使用部署的方案,此步无需执行。
● 部署结果
当部署完成后,在命令行界面,会有类似如下的输出:
serverless-ecs-image-handler-stack.serverlessecrimagehandlerstackCFDistributionUrl1454FE90= https://ABCDEFGH.cloudfront.net
serverless-ecs-image-handler-stack.serverlessecrimagehandlerstackServiceLoadBalancerDNSDB026A6D= serve-serve-ABCDEF.us-west-2.elb.amazonaws.com
serverless-ecs-image-handler-stack.serverlessecrimagehandlerstackServiceServiceURLE05B511A= http://serve-serve-ABCDEF.us-west-2.elb.amazonaws.com
serverless-ecs-image-handler-stack.serverlessecrimagehandlerstackSrcBucketS3Url593801C5= s3://serverless-ecr-image-han-serverlessecrimagehandle-ABCDE
有的时候,你也许在方案中找不到你希望的图片处理操作,这个时候你可以考虑进行二次开发对功能进行扩展。你可以按如下形式开发新的图片处理方法:
请联系我们获取代码库,并 fork 代码
在 new-image-handler 项目的 image 文件夹下创建你的代码文件,文件名称为你的图像处理名称
继承接口 IImageAction .
实现 接口的 name 属性,该属性定义了操作的名称
实现接口 IImageAction 方法 validate, 该方法 主要负责对传入的参数进行验证。传入的参数满足 <attribute name>_<attribute value> 的格式,例如 size_10,它的含义是参数 size 的值为 10
实现接口 IImageAction 方法 process, 该方法 主要负责完成实际的图片处理逻辑。该方法的参数 ctx 的 image 对象是待处理图片的 sharp.js 对象。所以您可以在process 方法利用 sharp.js 的 api 对图片进行操作
在 index.ts 文件中通过 ImageProcessor.getInstance() 注册您的处理对象
修改代码根目录下的 Dockerfile, 将 ENV NODE_ENV=production
# 修改为
ENV NODE_ENV=dev取消 Dockerfile 第 61 行的注释。这行代码会把一些测试图片复制到docker容器中,供测试使用。 # COPY test/fixtures app/lib/test/fixtures
blend:图片的混合方式,默认值为 'over',还有其他常用的值为 'overlay','out'。不同的值有不同的混合效果,需要通过尝试选择你需要的混合方式
gravity:水印图片/或文字相对底图的布局方式,默认为 center, 另外常用的值有 north,northwest
top,left:分别是相对于上边和左边的像素偏移量
tile:水印图片/或文字是否需要重复,默认值 false
const sharp = require('sharp');
(async () => {
let watermarkImg = sharp('panda.png');
const overlay = await watermarkImg.toBuffer()
const background = sharp('aws.png')
let u = await background
.composite([
{ input: overlay, blend: 'over'}
]).toFile('./output/o4.png');
})().catch(console.error)
纯文字水印的实现要依赖 svg:
const color = `#FFFF66`;
const opacity = 0.8
const text = 'hello, 伟大的祖国'
const svg = `<svg xmlns="http://www.w3.org/2000/svg"viewBox="0 0 600 80" text-anchor="middle">
<text font-size='60' x="300" y="60"fill="${color}" transform="rotate(10)"opacity="${opacity}">${text}</text>
</svg>`;
(async () => {
const overlay = Buffer.from(svg);
const background = sharp('aws.png')
let u = await background
.composite([
{ input: overlay, blend: 'over',gravity: 'northwest', top: 10, left: 20 }
]).toFile('./output/o7.png');
})().catch(console.error)
const color = `#FFFF66`;
const opacity = 0.8
const text = 'hello, 伟大的祖国'
const svg = `<svg xmlns="http://www.w3.org/2000/svg"viewBox="0 0 600 80" text-anchor="middle">
<text font-size='60' x="300" y="60"fill="${color}"opacity="${opacity}">${text}</text>
</svg>`;
(async () => {
const overlay = Buffer.from(svg);
let overlapImg = sharp({
create: {
width: 600, 这里需要保证转换后的图片和文字对应的svg尺寸一致
height: 80,
channels: 4,
background: { r: 0, g: 0, b: 0,alpha: 0 },
},
}).composite([{ input: overlay }]);
const overlapImgBuffer = await overlapImg.png().toBuffer();
overlapImg = sharp(overlapImgBuffer).png();
overlapImg = overlapImg.rotate(10, { background: '#00000000'});
const watermarkImgBuffer = await overlapImg.toBuffer();
const background = sharp('aws.png')
let u = await background
.composite([
{ input: watermarkImgBuffer,blend: 'over', gravity: 'northwest', top: 10, left: 20 }
]).toFile('./output/o7.png');
})().catch(console.error)
const opacity = 0.8
overlapImg.removeAlpha().ensureAlpha(opacity);
const sharp = require('sharp');
const opacity = 0.5;
(async () => {
let watermarkImg = sharp('panda.png').png();
const bt = await watermarkImg.convolve({
width: 3,
height: 3,
kernel: [
0, 0, 0,
0, opacity, 0,
0, 0, 0
]
}).png().toBuffer();
const background = sharp('aws.png')
let u = await background
.composite([
{ input: bt, blend: 'over' }
]).toFile('./output/o3.png');
})().catch(console.error)
每月新增图片数量分别为 10,0000、100,0000、500,0000,每张图片大小为 1MB。
每次 Lambda Function 调用运行时间 2 秒,运行内存大小 1GB,无预置并发。
每张图片上传 S3 存储桶后,会被用户请求 10 次,其中第 1 次处理回源,后 9 次命中缓存。
Fargate 计费时间单位为秒,不足一分钟按一分钟计。
基于亚马逊云科技的若干基础服务,如 S3、API Gateway、CloudFront、ECS Fargate 等,我们构建了一套图片处理的 API 解决方案,使得用户在使用可靠的对象存储服务的时候,能够获得更多更高的附加值。在诸如在线家居设计、在线多媒体文件制作、在线游戏等领域,用户使用该方案可以更加快速、经济、可靠地构建自己的产品。
本方案方案基于 Amazon Lambda、Amazon API Gateway、ECS Fargate 等无服务架构,用户无需担心在云中或本地管理和运行服务器或运行时,只需按实际使用量支付费用,这也极大的减轻了客户的运维负担。
基于 CloudFront 进行用户请求的响应,也使得方案可以快速地服务全球不同地理分布的终端用户,使得产品具有更好的用户体验。
方案设计时也参考了市场上相关竞品,使得最终的方案也可以很好地服务从别的云平台迁移过来用户,减少他们的迁移工作量和上手适应时间,能够集中精力开发自己的新业务。未来该方案还会持续演进,敬请关注。
作者介绍
宋孜攀
西云数据解决方案架构师
许庭新
西云数据解决方案架构师
评论
