我们注意到,我们的 ECS Fargate 后端服务由于健康检查响应超时而重新启动:
(service our-site-com-stack-BackendApiServiceStack...) (port 8000) is unhealthy in (target-group arn:aws:elasticloadbalancing:us-east-1:1234:targetgroup/dev-d-ABC-ABC123/ABC123) due to (reason Request timed out).
我们正在尝试弄清楚如何对我们的 ECS 应用程序进行 health_check,这样当数据库变得繁忙(或其他缓慢的请求待处理)时就不会不必要地重新启动我们的服务。
我们最初觉得情况可能与这里描述的情况类似:https://cloudsoft.io/blog/consequences-of-bad-health-checks-in-aws-application-load-balancer。基本上,如果我们的数据库很忙/很慢,那么请求可能会超时。
但是,我们修改了 health_check 以不影响我们的 RDS postgres 数据库,甚至尝试关闭我们的数据库。即使数据库关闭,我们也能访问端点,但当我们触发少至 7 个超时请求(例如数据库关闭时的登录请求)或类似数量的返回速度缓慢的请求(数据库启动时)时,我们就无法再访问它了。
在我们的 AWS 应用程序堆栈中,Route 53 用于将流量路由到我们的 CloudFront 分发。CloudFront 将此终端节点的流量路由到 Django 应用程序的应用程序负载均衡器。
我们的健康检查是 Django 应用程序的一部分,基本上只返回 200 响应:
def health_check(request):
response = JsonResponse({"message": "OK"})
return response
以下是我们在 CDK 中设置健康检查的方式:
self.https_listener = self.alb.add_listener(
"HTTPSListener",
port=443,
certificates=[scope.certificate],
open=True,
)
scope.https_listener.add_targets(
"BackendTarget",
port=80,
targets=[self.backend_service],
priority=2,
path_patterns=["*"],
health_check=elbv2.HealthCheck(
healthy_http_codes="200-299",
path="/api/core/health-check/",
),
)
启动生产服务器的命令是:
GEVENT_RESOLVER=ares gunicorn -t 1000 -k gevent -w 4 -b 0.0.0.0:8000 backend.wsgi
在一次不相关的测试中,我们使用 Daphne 重现了同样的问题:
daphne -b 0.0.0.0 -p 8000 backend.asgi:application
答案1
虽然请求没有到达数据库,但它被卡在了阻塞请求之后(或由于其他原因未返回)。我们误解了 gunicorn(或其他服务器)事件循环很容易被阻塞,因此将重新设计以更好地使用 gevents 和 celery 结果后端。