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.TCPConnector
或 aiohttp.ProxyConnector
(如果您使用代理)。只需在会话中创建它而不是使用默认值。
aiohttp.ClientSession(
connector=aiohttp.TCPConnector(limit=1)
)
aiohttp.ClientSession(
connector=aiohttp.ProxyConnector.from_url(proxy_url, limit=1)
)
我无法理解 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.TCPConnector
或 aiohttp.ProxyConnector
(如果您使用代理)。只需在会话中创建它而不是使用默认值。
aiohttp.ClientSession(
connector=aiohttp.TCPConnector(limit=1)
)
aiohttp.ClientSession(
connector=aiohttp.ProxyConnector.from_url(proxy_url, limit=1)
)