当其他多个请求返回缓慢时,ECS 会因 health_check 失败而重新启动

当其他多个请求返回缓慢时,ECS 会因 health_check 失败而重新启动

我们注意到,我们的 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 结果后端。

相关内容