Category: 大数据


基于S3的图片处理服务

作者:高寅敬 徐榆

1.背景介绍

随着移动互联网的快速发展,各种移动终端设备爆发式的增长,社交类APP 或者电商网站为了提升访问速度、提高用户体验,必须根据客户端的不同性能,不同屏幕尺寸和分辨率提供适当尺寸的图片。这样一来开发者通常需要预先提供非常多种不同分辨率的图片组合,而这往往导致管理难度的提升和成本的增加。

在这篇博客中,我们将探讨一种基于S3的图片处理服务,客户端根据基于HTTP URL API 请求实时生成不同分辨率的图片。

2.解决方案架构

为了保证图片服务的高可用,我们会把所有的图片(包括原图和缩率图)储存于AWS 的对象储存服务S3中,把图片处理程序部署于AWS EC2 中。大部分的图片请求都会直接由AWS S3返回,只有当S3中不存在所需缩率图时才会去请求部署于EC2 上的图片处理服务来生成对应分辨率图片。

业务流程:

  1. 用户客户端(通常是浏览器或者APP)发起请求200×200像素的图片
  2. S3中未存在该尺寸缩率图,于是返回HTTP 302 Redirect到客户端
  3. 客户端根据 HTTP 302响应,继续请求部署于 EC2 上的图片处理服务
  4. 部署于EC2的图片处理服务,会从 S3 获取源图
  5. 图片处理服务,根据请求参数生成对应尺寸图片缩率图
  6. 图片处理服务将对应的图片返回给客户端
  7. 图片处理服务把缩率图存回到S3中,加速下一次客户访问

3.架构特点

相较于预先生成所有所需分辨率图片和传统的基于独立图片处理服务器,这种新的处理方式包含以下优点:

更高的灵活性:

当我们的前端开发人员对界面进行改版时,时常会涉及到修改图片尺寸。对所有原始图片进行缩放的批处理是十分耗时,高成本且易出错的。利用这种基于URL API的实时处理方式,前端开发者指定新的尺寸后,立即就能生成符合客户访问新的网页和应用对应的图片,提高了前端开发人员的开发效率。

更低的储存成本:

对于传统图片处理方式,在未使用之前预先批量生成所需分辨率图片,占用大量的储存空间,而且利用率并不高。

以按需方式生成图片,能减少不必要的储存空间,降低储存成本。

相对于独立图片处理服务器把图片完全储存于EC2的EBS卷,储存于S3 的成本也更低。

我们知道缩率图是属于可再生数据,所以我们在程序上 会把缩率图储存为 S3的去冗余储存类型,再次降低约13% 的存储成本。

更高的服务可用性:

我们可以看到,独立地部署单台图片服务器,无法支持大并发负载。同时存在单点故障 无法保证服务的高可用性,高可扩展性。

而基于S3的解决方案,大量的图片请求,由AWS S3 来完成,S3 会自动扩展性能,因此应用程序的运行速度在数据增加时不会减慢。

只有少量的未生成的图片尺寸才会用到部署于EC2 的图片服务器,并且我们图片逻辑服务器与图片储存S3是解耦合关系,我们还可以针对 基于EC2的图片处理服务 进行横向扩展,比如把图片服务程序 加入到 Web服务器层,配合 负载均衡器 ELB、自动伸缩组 AutoScaling 来实现自动伸缩。

4.服务部署

为了服务部署能更接近生产环境,我们以下所有步骤将以创建一个以域名为 images.awser.me 的图片服务为例,来详细介绍如何基于AWS 来部署。

 

在EC2上部署图片处理服务

1.创建一台EC2服务器,并赋予 具有S3 访问权限的IAM 角色,配置正确的安全组开启 HTTP 80端口访问权限。

2.  示例程序基于PHP,所以需要确保服务器安装了 Apache 2.4 和PHP 7.0 以上。以及PHP 图片处理的相关的组件:ImageMagick、ImageMagick-devel 。

参考 基于Amazon Linux 的安装命令:

yum -y install httpd24 php70 ImageMagick  ImageMagick-devel php70-pecl-imagick php70-pecl-imagick-devel

3.  从 github 或者 从S3 下载图片处理程序,修改 根目录 resize.php 文件,bucketName 变量为你的域名或者是你的储存桶名称,例如:$bucketName=’images.awser.me’。

将程序部署于你的 web 目录底下,并且确保 能通过EC2 公网IP  进行访问。

例如:http://52.80.80.80/resize.php?src=test_200x200.jpg

最好为你的图片服务器设置一个域名,我们这里设置了 imgpro.awser.me。

例如: http://imgpro.awser.me/resize.php?src=test_200x200.jpg

这里记录下你的 EC2 Web 访问地址,在下一步的 S3 储存桶配置中会用到。

创建和配置S3储存桶

1.  创建储存桶

由于我们在生产环境中,需要使用指定的域名来访问S3资源。所以我们需要在S3 控制台 创建储存桶时,把储存桶名称设置为我们的域名,如: images.awser.me。

2.  储存桶权限控制

在刚刚创建的S3 储存桶,权限选项卡中 选择储存桶策略填写如下内容(注意修改 images.awser.me 为你的域名 或者 储存桶名称) 开启匿名访问

{

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

  "Statement":[

    {

      "Sid":"AddPerm",

      "Effect":"Allow",

      "Principal": "*",

      "Action":["s3:GetObject"],

      "Resource":["arn:aws-cn:s3:::images.awser.me/*"]

    }

  ]

}

3.  开启静态网站托管

在刚刚创建的S3储存桶,属性选项卡中 开启 静态网站托管 ,并配置 重定向规则 为以下示例内容(请修改HostName 为上一步骤 所创建的EC2 Web访问地址):

<RoutingRules>

  <RoutingRule>

    <Condition>

      <KeyPrefixEquals/>

      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>

    </Condition>

    <Redirect>

      <Protocol>http</Protocol>

      <HostName>imgpro.awser.me</HostName>

      <ReplaceKeyPrefixWith>resize.php?src=</ReplaceKeyPrefixWith>

      <HttpRedirectCode>302</HttpRedirectCode>

    </Redirect>

  </RoutingRule>

</RoutingRules>

记录终端节点名称 例如:images.awser.me.s3-website.cn-north-1.amazonaws.com.cn

在DNS 服务商 添加一个CNAME记录 ,把你的自定义域名 如images.awser.me 解析到 该终端节点上。

4.  配置S3 存储桶生命周期,自动清理缩率图

随时时间推移,我们会发现我们保存着在大量过时的缩率图,造成储存空间的浪费。其实我们可以利用S3存储桶的生命周期功能,来实现一定时间范围以外的缩率图自动清理。

在S3储存桶管理选项卡中,选择 添加生命周期规则

由于我们在图片缩放程序中,产生缩率图的过程,已经给所有缩率图打上了一个特殊标签 thumbnail = yes,那么我们就可以在生命周期规则中,把该标签作为过滤条件,这样才不会影响储存桶中的其他资源(如原图)。

然后在过期选项中设置,过期时间为30天。

这样配置完以后,所有缩率图生成三十天后会自动清理,来节省储存和管理成本。

5.测试图片缩放

首先上传一张测试图片至S3存储桶,我们选择一张经典的地球图片作为测试 命名为earth.jpg。

1.测试使用 S3 终端节点访问,测试储存桶 权限是否配置正确:

http://images.awser.me.s3-website.cn-north-1.amazonaws.com.cn/earth.jpg

2.测试使用 自定义域名访问,测试储存桶命名以及DNS 配置是否正确

http://images.awser.me/earth.jpg

3.测试图片缩放功能是否正常,尝试请求一张 200×200 像素的图片:

http://images.awser.me/earth_200x200.jpg    

如果一切正常,我们可以看到浏览器 会自动跳转访问

http://imgpro.awser.me/resize.php?src=earth_200x200.jpg

并返回200×200 像素的图片。

4.测试S3 缓存是否生效,当我们第二次访问

http://images.awser.me/earth_200x200.jpg                                                                                                                     如果一切正常,我们可以观察到 浏览器 没有做跳转。

6.总结

以上内容是对基于S3的图片处理服务解决方案的一个简单实现,也提到一部分生产环境可能遇到的问题,比如图片服务器的自定义域名、使用S3 低冗余储存类型来降低成本、缩率图的自动清理等。

其实实际生产环境还可以对成本进行进一步优化,比如可以分析S3 产生的访问日志,找出访问记录比较久远的对象 、调用S3 API 对长久未使用的缩率图进行定时清理,甚至可以根据日志做分析 找出热门的图片格式需求,提前针对热门图片生产缩率图,提高用户体验。

另外通过以上的架构描述可以看出,由于AWS 所提供的所有云服务都有丰富的API 接口 和详细的配置选项,它就像一个乐高玩具一般,开发人员或者架构师可以脑洞大开随意去组合它成为自己想要的产品。

 

作者介绍:

高寅敬,AWS解决方案架构师,负责基于AWS云计算方案架构的咨询和设计,在国内推广AWS云平台技术和各种解决方案。在加入AWS之前就职于美国虚拟运营商Seawolf海狼通讯,超过7年的互联网通信应用系统开发和架构经验。
超过5年的AWS实践经验, 精通基于AWS全球分布式VoIP系统的开发、运营及部署,深度理解AWS核心的计算、网络、存储以及云计算的弹性伸缩。

徐榆,AWS实习架构师,研究生一年级对云计算/大数据和人工智能有一定研究。

新增:Amazon Kinesis Streams 服务器端加密

在这个智能家居、大数据、物联网设备、手机、社交网络、聊天机器人和游戏机的时代,流媒体数据场景无处不在。利用 Amazon Kinesis Streams,您可以构建自定义应用程序,以便从数千个流媒体数据源捕获、处理、分析和存储每小时数 TB 的数据。由于 Amazon Kinesis Streams 允许应用程序从同一个 Kinesis 流并发处理数据,因此您可以构建并行处理系统。例如,您可以将处理后的数据发送到 Amazon S3,使用 Amazon Redshift 执行复杂分析,甚至使用 AWS Lambda 构建强大的无服务器流媒体解决方案。

Kinesis Streams 为消费者提供了多种流媒体使用案例,现在我们通过为 Kinesis Streams 添加服务器端加密 (SSE) 支持,让服务能够更有效地保护您的传输中数据。借助 Kinesis Streams 的这一新功能,现在您可以提高数据安全性和/或满足任何法规和合规性要求,以符合组织的任何数据流式处理需求。
事实上,Kinesis Streams 现在是支付卡行业数据安全标准 (PCI DSS) 合规性计划涵盖的 AWS 服务之一。PCI DSS 是由主要金融机构成立的 PCI 安全标准委员会管理的专有信息安全标准。PCI DSS 合规性适用于存储、处理或传输持卡人数据和/或敏感的身份验证数据的所有实体,其中包括服务提供商。您可以使用 AWS Artifact 索要 PCI DSS 合规性证明和责任摘要。但是,关于 Kinesis Streams 合规性的好消息还不止这些。Kinesis Streams 现在还符合 AWS GovCloud 中的 FedRAMP 标准。FedRAMP 代表“联邦风险与授权管理项目”(Federal Risk and Authorization Management Program),是美国政府实施的一个项目,为云产品和云服务的安全评估、授权和持续监控提供了一种标准方法。您可以在这里了解有关 AWS 服务的 FedRAMP 合规性的更多信息。

现在您准备好了解关键点了吗?那就记住关键点,而不是纠结于细节。好吧,是有点陈词滥调,但这是我能想到的最好类比了。回到 Kinesis Streams 的 SSE 讨论中,让我来解释 Kinesis 的服务器端加密流程。使用 PutRecord 或 PutRecords API 放入 Kinesis Stream 中的每个数据记录和分区键均使用 AWS Key Management Service (KMS) 主密钥进行加密。通过 AWS Key Management Service (KMS) 主密钥,Kinesis Streams 使用 256 位高级加密标准 (AES-256 GCM 算法) 对传入数据进行加密。

为了对新的或现有流启用 Kinesis Streams 服务器端加密,您可以使用 Kinesis 管理控制台或利用某个可用的 AWS 软件开发工具包。此外,您还可以使用 AWS CloudTrail 服务审核流加密历史记录,验证 Kinesis Streams 控制台中特定流的加密状态,或者检查 PutRecord 或 GetRecord 事务是否已加密。

演练:Kinesis Streams 服务器端加密

我们来快速演练一下 Kinesis Streams 的服务器端加密。首先,我将访问 Amazon Kinesis 控制台并选择 Streams 控制台选项。

进入 Kinesis Streams 控制台后,我可以向我现有的某个 Kinesis 流添加服务器端加密,或者选择创建一个新的 Kinesis 流。对于此演练,我将选择快速创建一个新的 Kinesis 流,因此,我选择 Create Kinesis stream 按钮。

我将该流命名为 KinesisSSE-stream,然后为它分配一个分区。请记住,您的流的数据容量是根据为流指定的分区数量计算的。您可以使用控制台中的 Estimate the number of shards you’ll need 下拉菜单,或者通过在此处阅读更多有关计算方式的内容来估计流中的分区数。为了完成流的创建,现在我单击 Create Kinesis stream 按钮。

创建 KinesisSSE-stream 后,我将在控制面板中选择它,然后选择 Actions 下拉菜单并选择 Details 选项。


KinesisSSE-stream 的“Details”页面上,现在有一个 Server-side encryption 部分。在该部分中,我将选择 Edit 按钮。

现在,我可以通过选择 Enabled 单选按钮,使用 AWS KMS 主密钥为我的流启用服务器端加密。选择该选项后,我就可以选择将哪个 AWS KMS 主密钥用于 KinesisSSE-stream 中的数据加密。我可以选择 Kinesis 服务生成的 KMS 主密钥 (Default) aws/kinesis,也可以选择之前我自己生成的一个 KMS 主密钥。我将选择默认主密钥,然后只需单击 Save 按钮即可。


就是这样!从下面的屏幕截图中可以看出,只有大约 20 秒,服务器端加密即添加到我的 Kinesis 流中,现在传入到我的流中的任何数据都将被加密。需要注意的是,服务器端加密仅对在启用加密后传入的数据进行加密。启用服务器端加密之前 Kinesis 流中预先存在的数据将保持未加密状态。

总结

使用 AWS KMS 密钥的 Kinesis Streams 服务器端加密让您可以轻松地自动加密传入流中的流媒体数据。您可以使用 AWS 管理控制台或 AWS 软件开发工具包启动、停止或更新任何 Kinesis 流的服务器端加密。要了解有关 Kinesis 服务器端加密、AWS Key Management Service 或 Kinesis Streams 的更多信息,请查看 Amazon Kinesis 入门指南AWS Key Management Service 开发人员指南Amazon Kinesis 产品页面

祝流式处理顺利。

Tara