Aiohttp 服务器最大连接数

Aiohttp server max connections

我无法理解 aiohttp(和一般的 asyncio)服务器实现不提供限制最大并发连接限制(接受的套接字数,或 运行ning 请求处理程序的数量)的方法的原因。 (https://github.com/aio-libs/aiohttp/issues/675)。没有这个限制,很容易运行 out of memory and/or 文件描述符。

同时,aiohttp客户端默认限制并发请求数为100(https://docs.aiohttp.org/en/stable/client_advanced.html#limiting-connection-pool-size),aiojobs限制运行ning任务数和pending任务列表大小,nginx有worker_connections 限制,任何同步框架都受设计工作线程数的限制。

虽然 aiohttp 可以处理很多并发请求,但这个数量仍然有限。 aiojobs 上的文档说 "The Scheduler has implied limit for amount of concurrent jobs (100 by default). ... It prevents a program over-flooding by running a billion of jobs at the same time"。而且,我们仍然可以愉快地生成 "billion"(好吧,直到我们 运行 资源不足)aiohttp 处理程序。

那么问题来了,为什么要这样实现呢?我是否遗漏了一些重要的细节?我认为我们可以使用 Semafor 以某种方式暂停请求处理程序,但与 nginx 相比,aiohttp 仍接受套接字并生成协程。另外当部署在nginx后面时,worker_connections的数量和aiohttp期望的限制肯定会不同。(因为nginx也可以服务于静态文件)

根据开发人员对 linked issue 的评论,做出此选择的原因如下:

  • 如果应用程序检测到连接数大于它可以合理处理的数量,它可以 return 4xx 或 5xx 响应。 (这不同于 Semaphore 习惯用法,后者会有效地 queue 连接。)

  • 限制服务器连接的数量比仅仅指定一个数字更复杂,因为限制可能取决于你的协同程序在做什么,即它至少应该是 path-based。 Andrew Svetlov 链接到 NGINX documentation 关于支持这个的连接限制。

  • 反正建议把aiohttp放在专门的前端服务器比如NGINX后面。

比这更多的细节只能由阅读此标签的开发人员提供。

在这一点上,推荐的解决方案似乎是使用反向代理进行限制,或者像这个装饰器(未测试)这样的 application-based 限制:

REQUEST_LIMIT = 100

def throttle_handle(real_handle):
    _nrequests = 0
    async def handle(request):
        nonlocal _nrequests
        if _nrequests >= REQUEST_LIMIT:
            return aiohttp.web.Response(
                status=429, text="Too many connections")
        _nrequests += 1
        try:
            return await real_handle(request)
        finally:
            _nrequests -= 1
    return handle

@throttle_handle
async def handle(request):
    ... your handler here ...

要限制并发连接,您可以使用 aiohttp.TCPConnectoraiohttp.ProxyConnector(如果您使用代理)。只需在会话中创建它而不是使用默认值。

aiohttp.ClientSession(
    connector=aiohttp.TCPConnector(limit=1)
)
aiohttp.ClientSession(
    connector=aiohttp.ProxyConnector.from_url(proxy_url, limit=1)
)