19

I have a web app which runs behind Amazon AWS Elastic Load Balancer with 3 instances attached. The app has a /refresh endpoint to reload reference data. It need to be run whenever new data is available, which happens several times a week.

What I have been doing is assigning public address to all instances, and do refresh independently (using ec2-url/refresh). I agree with Michael's answer on a different topic, EC2 instances behind ELB shouldn't allow direct public access. Now my problem is how can I make elb-url/refresh call reaching all instances behind the load balancer?

And it would be nice if I can collect HTTP responses from multiple instances. But I don't mind doing the refresh blindly for now.

4

7 回答 7

11

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

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

该解决方案的主要优势是

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

希望这是有用的。

于 2017-10-05T04:00:30.407 回答
7

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

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

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

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

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

于 2016-09-14T20:31:34.680 回答
6

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

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

于 2016-09-14T19:48:08.610 回答
4

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

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

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

上面我通过了一个UTC时间戳2019-08-27T23:50:23Z

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

实施说明

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

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

在此处输入图像描述

于 2019-08-28T00:11:09.890 回答
2

当您使用 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 并且您不必手动执行此操作每一次。

于 2016-09-14T20:19:30.810 回答
1

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

于 2018-08-11T17:20:03.600 回答
0

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

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

于 2022-01-18T18:52:40.707 回答