【问题标题】:Architecture design: how web-tier knows when worker-tier is done processing?架构设计:Web 层如何知道工作层何时完成处理?
【发布时间】:2016-04-26 19:42:29
【问题描述】:

我正在使用 Amazon AWS 构建一个用于教育目的的小型应用程序。 Web 应用程序有两个部分:

  1. 上传图片的表单。
  2. 显示已上传图片的所有缩略图的网格。

申请流程:

  1. 用户打开网页。
  2. 用户选择要上传的图片。
  3. 向 Web 层发送 AJAX 请求以生成预签名的 S3 URL。
  4. 收到 URL 后,会发起 AJAX PUT 请求,并将图像直接上传到 S3。
  5. 上传完成后,S3 会发送带有图像密钥的 SQS 队列消息。
  6. 其中一名工作人员收到该消息并创建缩略图。
  7. 图像处理完成后,工作人员将缩略图上传到 S3。

此图说明了上述情况:


现在,网络层使用db.json 文件来保存所有现有缩略图的链接。使用该文件,客户端网页会呈现网格中的所有缩略图。

问题是,网络层如何知道何时更新包含新缩略图链接的db.json

理想情况下,网络层将完成以下任务:

  1. 仅在需要时刷新json(如果网络层刷新了json,那么它一定已经被修改了)。
  2. 在更新后提供更新 db.json(如果按时添加缩略图x 并且另一个用户按时请求网页x+1,则用户知道新缩略图)。

几种方法:

  1. 对于每个 index.html 请求,列出 S3 存储桶并提供最新的缩略图(违反上一节中的第 1 项)。

  2. 按间隔列出 S3 存储桶(违反这两项)。

  3. 在请求预签名 URL 后设置计时器,并假设工作人员在计时器响起时已完成新图像的处理(这甚至不是解决方案,主要有两个原因;Web 层有多个实例,即计时器可能会在处理完成之前响铃)。

  4. 使用 S3 事件并设置一个 lambda 表达式,将 HTTP GET 请求发送到我的 Web 层上的特殊端点(也不是解决方案,因为此请求将从负载均衡器定向到单个实例,什么关于其他实例?)。


我不知道如何解决这个问题。 你建议我做什么?

编辑

由于这是一项教育活动,因此数据库服务超出了范围。

【问题讨论】:

    标签: amazon-web-services amazon-s3 architecture


    【解决方案1】:

    这个问题有点荒谬,将所有内容存储在一个我们不断更新的 JSON 文件中的概念,但解决方案似乎很明显......另一个 S3 事件通知。

    只要您有一个系统,可以将事件的神奇礼物交给您,让您不必轮询任何事情,您就会忽视所带来的价值。

    如果每个 Web 服务器都保留自己的 json 文件副本并需要更新它,那也很容易解决。

    在创建缩略图时触发 S3 事件(S3 通知可以匹配前缀而不是针对整个存储桶) > S3 事件发布到 SNS 主题 > SNS 主题扇出到多个 SQS 队列,每个 Web 服务器一个。 Web 服务器上的一个进程使用单个线程订阅该服务器的队列,每次有消息进来时,本地工作人员都会在该服务器上修改 json 文件。每个服务器都会获得每个通知的副本。

    我有一个旧的遗留系统,其中网站模板更改(不是代码,只是模板)通过将模板更改提交到 subversion 来实现,然后在服务器上提交svn up。因为这个 subversion repo 是为此目的而存在的,所以 Web 服务器直接从他的签出目录中读取模板。听起来很奇怪,但多年来一直很好用。我最近通过设置一个让人想起上述内容的安排来增强它,但没有 S3。当提交任何内容时,“提交后挂钩”会在 subversion 服务器上触发一个 shell 脚本。反过来,这会将有关已更改文件的消息发布到 SNS 主题,该主题散布到多个 SQS 队列——每个 Web 服务器一个,每个服务器上的一个简单脚本侦听该服务器的 SQS 队列。每个服务器一个侦听器,一个线程,因此不存在并发问题。监听器,它在新提交的文件上运行“svn up”,删除队列消息,然后监听下一个。实时事件扇出,为什么不呢?

    【讨论】:

    • 我看不出您的解决方案如何可扩展? SQS(每个进程一个)的数量是否可以根据 Web 服务器的数量进行横向扩展? SNS 是否也可以自动配置为将消息发送到所有新的 SQS 队列?此外,在我看来,这似乎是一种矫枉过正。每个 Web 服务器上的进程如何对队列进行采样?它没有 sqs 守护进程,因为它不是工作环境。
    • 它是完全可扩展的。当一个新的 Web 服务器上线时,它会为自己创建一个队列并将该队列订阅到 SNS 主题。如果您希望每个 Web 服务器都有一个本地副本,则必须在每个 Web 服务器上运行一些东西。您可以直接使用 SNS 并使用 https 向每个服务器发送主题通知,但这会失败,因为必须按顺序处理请求。但是,正如我所建议的,这里提出的假设“问题”是一个带有人为限制的荒谬问题。没有人会试图通过维护静态索引文件来解决这里的问题。
    【解决方案2】:

    db.json 文件是否存储在其中一台 Web 服务器上?如何跨多个 Web 服务器协调对 db.json 文件的更新?如何防止多个worker服务器同时更新db.json文件,互相踩踏?

    我建议将缩略图的存在存储在平面文件以外的其他位置。 DynamoDB 将是存储它的好地方。 PostgreSQL 或 RDS 上的一种 MySQL 风格也可以工作。

    为了将 JSON 数据提供给包含缩略图列表的 UI,我将创建一个动态页面来查询数据库并呈现 JSON 数据。这还允许您实现数据分页之类的功能,一旦您的图像集变得非常大,这将是一项要求。

    为了防止 Web 层因请求 JSON 数据而过载,我将在 Web 层前面放置一个 CDN,例如 CloudFront 或 CloudFlare。为了防止数据库因缩略图列表查询而过载,我将在 Web 层和数据库之间实现一个缓存层 (Redis)。

    【讨论】:

    • 在本练习中,数据库服务超出了范围。当然,json 不能存储在每个 Web 服务器中——这是我的结论之一。我也想过将json 文件也存储在 S3 中,并设置一个 lambda 函数以在将新缩略图放入存储桶时对其进行更新。这样,Web 服务器根本不会处理 json,它们只会在客户端代码中引用它。
    • @johni 在该设计中,仍然无法防止 Lambda 函数的多个实例同时运行并相互删除对 db.json 文件的更新。数据库服务可能在本练习中“超出范围”,但它们是正确构建它且不会出现大量并发更新问题的唯一方法。
    • 另外,如果你做的家庭作业有一些限制,比如“不能使用数据库”,那么你应该在问题中说明这一点。
    • 不能禁用 lambda 函数的并发执行吗?
    • @johni 不,这根本不可能。
    猜你喜欢
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 2014-01-25
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多