如何使 HTTP 调用到达亚马逊 AWS 负载均衡器后面的所有实例?

Posted

技术标签:

【中文标题】如何使 HTTP 调用到达亚马逊 AWS 负载均衡器后面的所有实例?【英文标题】:How to make a HTTP call reaching all instances behind amazon AWS load balancer? 【发布时间】:2017-01-22 17:32:45 【问题描述】:

我有一个在 Amazon AWS Elastic Load Balancer 后面运行的 Web 应用程序,附加了 3 个实例。该应用程序有一个/refresh 端点来重新加载参考数据。只要有新数据可用,就需要运行它,每周发生几次。

我一直在做的是为所有实例分配公共地址,并独立刷新(使用ec2-url/refresh)。我同意Michael's answer on a different topic,ELB 后面的 EC2 实例不应允许直接公共访问。现在我的问题是如何让elb-url/refresh 调用到达负载均衡器后面的所有实例?

如果我可以从多个实例收集 HTTP 响应,那就太好了。但我现在不介意盲目地进行刷新。

【问题讨论】:

如果您向 ec2 添加公共 IP 地址,您将如何执行该刷新调用? @error2007s 我的每个实例都有公共 DNS 名称,例如 ec2-123-123-123-123.compute-1.amazonaws.com,我必须对它们单独调用 /refresh 每次有新数据可用时,您都要手动执行此操作? @error2007s 是的,每次有新数据进来时我都必须这样做。当我在 ELB 上调用 /refresh 时,只有一个服务器得到更新。因此,我正在寻找一种解决方案来为我完成所有的腿部工作:) 对于同样的事情,这里是another question。 【参考方案1】:

我解决这个问题的方法之一是通过

    将数据写入 AWS s3 存储桶 triggering a AWS Lambda function automatically from the s3 write 使用 AWS 开发工具包从 Lambda 函数中识别附加到 ELB 的实例,例如使用 boto3 from python 或 AWS Java SDK 从 Lambda 对单个实例调用 /refresh 确保在创建新实例时(由于自动缩放或部署),它会在启动期间从 s3 存储桶中获取数据 确保实例所在的私有子网允许来自附加到 Lambda 的子网的流量 确保附加到实例的安全组允许来自附加到 Lambda 的安全组的流量

这个解决方案的关键胜利是

从将数据写入 s3 的那一刻起,该过程就完全自动化了, 避免由于自动缩放/部署导致的数据不一致, 易于维护(您不必在任何地方硬编码实例 IP 地址), 您不必在 VPC 之外公开实例 高度可用(AWS 确保在 s3 写入时调用 Lambda,您不必担心在实例中运行脚本并确保实例启动并运行)

希望这是有用的。

【讨论】:

这是一个很好的答案。我只想指出,在这种情况下,lambda 需要位于 VPC 内部,否则它将无法通过其私有 IP 访问实例。执行此操作时,不要忘记允许 lambda 安全组上的出站流量。【参考方案2】:

虽然考虑到您的应用程序和环境的限制,这可能是不可能的,但值得注意的是,在 AWS ELB 后面运行的实例(特别是如果它们是 AutoScalingGroup 的一部分)的最佳实践应用程序架构可确保实例不是有状态的

这样做的目的是让您可以通过添加新实例进行横向扩展,或通过删除实例进行横向扩展,而不会影响数据完整性或性能。

一种选择是更改应用程序以将引用数据重新加载的结果存储到非实例数据存储中,例如缓存或数据库(例如 Elasticache 或 RDS),而不是内存中。

如果应用程序能够做到这一点,那么您只需要点击单个服务器上的refresh 端点 - 它会重新加载参考数据,执行任何所需的分析和操作以有效地将其存储在合适的位置- 应用程序的专用方式,将其存储到数据存储中,然后所有实例都可以通过共享数据存储访问刷新的数据。

虽然向数据存储添加往返会增加延迟,但对于应用程序的一致性而言,这样做通常是值得的 - 在您当前的模型下,如果一台服务器在刷新参考数据方面落后于其他服务器,如果 ELB 没有使用粘性会话,则通过 ELB 的请求将根据分配到的服务器返回不一致的数据。

【讨论】:

【参考方案3】:

您无法通过负载均衡器发出这些请求,因此您必须打开实例的安全组以允许来自 ELB 以外的源的传入流量。但这并不意味着您需要将其开放给所有直接流量。您可以简单地将安全组中的 IP 地址列入白名单,以允许来自您的特定计算机的请求。

如果您不想将公共 IP 地址添加到这些服务器,那么您需要在 VPC 内的 EC2 实例上运行类似 curl 的命令。在这种情况下,您只需打开安全组以允许来自 VPC 中存在的某些服务器(或服务器组)的流量。

【讨论】:

啊...也许我会创建一个新的端点,无论哪台机器收到请求都会运行一堆 curl 的原始/refresh。它们已经在同一个 VPC 中。感谢@Mark B 的快速回答。 请注意,您仍然需要打开一些安全组。如果您有一个 EB 服务器将请求发送到所有其他 EB 服务器,您将在实例所属的安全组中添加入站规则,指定它们允许来自同一安全组中其他实例的入站流量。 是的,我知道你在说什么。在安全组中添加新规则没什么大不了的。 我正在考虑让所有需要这种“刷新”活动的应用程序订阅企业消息总线上的“刷新”主题。【参考方案4】:

我以不同的方式解决了这个问题,没有在安全组中开辟新的流量,也没有求助于 S3 等外部资源。它的灵活性在于它会动态通知通过 ECS 或 ASG 添加的实例。

ELB 的目标组提供定期运行状况检查的功能,以确保其背后的实例处于活动状态。这是您的服务器响应的 URL。端点可以包括最新配置的时间戳参数。 TG 中的每台服务器都将在配置的Interval 阈值内接收健康检查 ping。如果 ping 的参数发生变化,则表示刷新。

网址可能如下所示: /is-alive?last-configuration=2019-08-27T23%3A50%3A23Z

上面我传递了2019-08-27T23:50:23Z的UTC时间戳

接收请求的服务将检查内存状态是否至少与时间戳参数一样新。如果没有,它将刷新其状态并更新时间戳。下一次运行状况检查将导致无操作,因为您的状态已刷新。

实施说明

如果刷新状态可能需要比间隔窗口或 TG 运行状况超时更多的时间,您需要将其卸载到另一个线程以防止并发更新或彻底的服务中断,因为运行状况检查需要及时返回。否则该节点将被视为离线。

如果您为此目的使用流量端口,请确保 URL 安全,使其无法猜测。任何公开暴露的东西都可能受到 DoS 攻击。

【讨论】:

【参考方案5】:

当您使用 S3 时,您可以使用 S3 的 ObjectCreated 通知自动执行任务。

https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html

https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-notification.html

您可以安装 AWS CLI 并编写一个简单的 Bash 脚本来监控该 ObjectCreated 通知。启动一个 Cron 作业,该作业将查找 S3 通知以创建新对象。

在该脚本文件中设置条件以 curl "http://127.0.0.1/refresh" 当脚本文件检测到在 S3 中创建的新对象时,它将卷曲 127.0.0.1/refresh 并且您不必这样做每次手动执行。

【讨论】:

每个数据包约为 500MB,定期重新加载相当昂贵。更复杂的是,/refresh 需要一个 arg 来指定要加载的包,而且它们都很大。 如何检测到有新数据可用? @error2007s 一个不同的团队负责创建这些文件并放入 S3。 @error2007s 谢谢你,我也会调查 S3 触发器。 我对 bash 脚本如何监控推送通知感到有些困惑?这是假设有一个 SQS 队列或接收推送通知的东西吗? bash 脚本轮询的究竟是什么?【参考方案6】:

我个人喜欢@redoc 的答案,但想为感兴趣的人提供另一种选择,这是他和接受的答案的组合。使用 SEE 对象创建事件,您可以触发 lambda,但不是发现实例并调用它们,这需要 lambda 在 vpc 中,您可以让 lambda 使用 SSM(又名 Systems Manager)通过 powershell 执行命令或 bash 文档关于通过标签定位的 EC2 实例。然后该文档将调用 127.0.0.1/reload ,就像接受的答案一样。这样做的好处是您的 lambda 不必在 vpc 中,并且您的 EC2 不需要入站规则来允许来自 lambda 的流量。缺点是它需要实例安装 SSM 代理,这听起来比实际工作要多。 AWS AMI 已经使用 SSM 代理进行了优化,但您自己在用户数据中安装它非常简单。根据您的用例,另一个潜在的缺点是它使用指数上升来同时执行,这意味着如果您的目标是 20 个实例,它会运行一个 1,然后一次运行 2,然后一次运行 4,然后是 8,直到它们全部完成,或者达到您为最大值设置的值。这是因为它内置了错误恢复功能。如果出现问题,它不想破坏你所有的东西,比如慢慢地将你的体重放在冰上。

【讨论】:

【参考方案7】:

您可以快速连续多次调用以调用负载均衡器后面的所有实例。这会起作用,因为 AWS 负载均衡器默认使用没有粘性会话的循环,这意味着负载均衡器处理的每个调用都被分派到可用实例列表中的下一个 EC2 实例。因此,如果您进行快速调用,您很可能会命中所有实例。

另一个选项是,如果您的 EC2 实例相当稳定,您可以为每个 EC2 实例创建一个目标组,然后在您的负载均衡器上创建一个侦听器规则,以根据某些标准(例如查询参数、URL 或标题。

【讨论】:

以上是关于如何使 HTTP 调用到达亚马逊 AWS 负载均衡器后面的所有实例?的主要内容,如果未能解决你的问题,请参考以下文章

route53 裸域未到达亚马逊弹性负载均衡器

如何使 DNS ARecord 指向 AWS 弹性 beanstalk 负载均衡器?

AWS 负载均衡器返回 403 响应?

如何在 ELB 应用程序负载均衡器上将 HTTPS 重定向到 HTTP

用于 lambda 的亚马逊负载均衡器

如何在 AWS 负载均衡器响应中禁用 Apache HTTP 标头信息?