socket server 创建监听 socket 的时候,在调用 listen 时候,可以指定一个 int 参数,表示连接请求的最大数量,也就是在连接队列中允许等待的客户端连接的数量
nginx、uvicorn、gunicorn 这些 HTTP sever 的 socket 的 listen 队列是多大?
我为什么会有和这个疑问?因为我自己写了一个简单的 TCP server 的时候,发现,客户端连接 sevrer 的时候,非常容易出现 ConnectionResetError: [Errno 54] Connection reset by peer
,只要把 listen 的 int 参数修改为很大,比如 100,报错 ConnectionResetError: [Errno 54] Connection reset by peer
的概率就大大降低了
但是 nginx、uvicorn、gunicorn 这些 HTTP server 不管有多少客户端并发请求,都不会出现 ConnectionResetError: [Errno 54] Connection reset by peer
为什么?是因为 nginx、uvicorn、gunicorn 这些 HTTP sever 的 socket 的 listen 的 int 参数设置的很大很大吗?
下面是我写的测试代码:
服务端的
import socket
import sys
import time
import threading
from loguru import logger
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures._base import Future
default_encoding: str = 'utf-8'
pool = ThreadPoolExecutor(
max_workers=20,
thread_name_prefix='simple-work-thread-pool'
)
def init_serversocket() -> socket.socket:
serversocket = socket.socket(
family=socket.AF_INET,
type=socket.SOCK_STREAM
)
# 获取本地主机名
host = socket.gethostname()
logger.debug(f'host {host}')
port = 6000
# 绑定端口号
serversocket.bind(('0.0.0.0', port))
# 设置最大连接数,超过后排队
serversocket.listen(5)
return serversocket
def send_response(clientsocket: socket.socket, addr: tuple, response_body: bytes) -> int:
send_len: int = clientsocket.send(response_body)
clientsocket.close()
return send_len
def start_request(clientsocket: socket.socket, addr: tuple) -> int:
try:
logger.debug(f'get message from {addr}')
request_body: bytes = clientsocket.recv(2048)
request_text: str = request_body.decode(encoding=default_encoding)
response_text: str = f'server get message: {request_text}'
response_body: bytes = response_text.encode(default_encoding)
time.sleep(1)
return send_response(clientsocket=clientsocket, addr=addr, response_body=response_body)
except Exception as error:
logger.exception(error)
def start_request_callback(future: Future) -> None:
send_len: int = future.result()
logger.debug(
f'{threading.current_thread().name}, send payload len is {send_len}')
serversocket = init_serversocket()
while True:
clientsocket, addr = serversocket.accept()
clientsocket: socket.socket
addr: tuple
future: Future = pool.submit(start_request, clientsocket, addr)
future.add_done_callback(start_request_callback)
客户端的
from base64 import encode
import socket # 客户端 发送一个数据,再接收一个数据
import json
from loguru import logger
from concurrent.futures import ThreadPoolExecutor
failture_requests = []
def send_request(index:int):
try:
# 声明socket类型,同时生成链接对象
clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(('127.0.0.1', 6000)) # 建立一个链接,连接到本地的6969端口
payload = b'ponponon'
clientsocket.send(payload)
data = clientsocket.recv(1024)
payload = data.decode()
logger.debug(index)
clientsocket.close()
logger.debug('请求完成')
except Exception as error:
failture_requests.append(index)
logger.exception(error)
pool = ThreadPoolExecutor(max_workers=100)
for index in range(10):
pool.submit(send_request,index)
pool.shutdown(wait=True)
logger.debug(failture_requests)
logger.debug(len(failture_requests))
uvicorn 的 backlog 默认是 2048
gunicorn 的 backlog 默认是 2048
是的,这玩意叫做 backlog,很诡异的名字。(backlog(中文名“积压”、“滞后”))
nginx 的 backlog 的默认值是多少?
我问了一下 chatGPT,得到的对话结果如下:
Q:nginx 的 backlog 的默认值是多少
A:在 Nginx 中,backlog
表示监听 socket 的队列大小,即 Nginx 可以同时处理的并发连接数。默认情况下,Nginx 的 backlog
值为 511
。
在 Linux 中,监听 socket 队列的最大值取决于系统的参数 net.core.somaxconn
,该参数的默认值通常为 128
。当 backlog
值大于 net.core.somaxconn
时,实际上系统会将其截断为 net.core.somaxconn
。
因此,在 Nginx 中,如果需要增加 backlog
的大小,也需要将 net.core.somaxconn
参数的值相应地增加。这可以通过修改系统参数、或者在 Nginx 的配置文件中使用 worker_rlimit_nofile
和 worker_connections
参数来实现。
Q:为什么监听 socket 的队列大小的英文名是 backlog
A:在计算机科学中,backlog(中文名“积压”、“滞后”)是一个常见的概念,指的是未能立即处理的任务或事件的数量。在网络编程中,backlog指的是未能立即处理的连接请求的数量。
在Linux中,backlog参数是指在服务端内核中维护的一个队列,用于存放连接请求,也就是连接请求的队列。当服务端使用listen系统调用打开一个socket来监听客户端连接时,backlog参数指定了在队列中允许等待的客户端连接的数量。
当服务端在处理连接请求时,如果队列已经满了,新的连接请求将会被拒绝。因此,如果backlog参数设置得太小,服务端可能无法处理所有的连接请求,导致连接被拒绝。如果设置得太大,会占用过多的内存,因此需要在服务端的负载能力和内存资源之间进行平衡。
至于为什么监听 socket 的队列大小的英文名是backlog,可能是因为在Linux内核中,这个队列是一个被称为backlog的数据结构。
Q:如何查看系统的 net.core.somaxconn
A:要查看系统的 net.core.somaxconn
参数的值,可以使用以下命令:
sysctl net.core.somaxconn
这将输出当前系统的 net.core.somaxconn
参数值。如果您想要修改该参数的值,可以使用以下命令:
sudo sysctl -w net.core.somaxconn=<new_value>
其中,<new_value>
是您想要设置的新值。请注意,这将修改系统全局参数,可能会影响其他应用程序的性能,因此请谨慎修改。如果您想要临时修改此参数,可以使用 sysctl
命令的 -w
选项,但该修改将在系统重新启动后失效。如果您想要永久修改该参数,可以将其添加到系统的配置文件中(如 /etc/sysctl.conf
或 /etc/sysctl.d/*
),以在系统启动时加载该值。
在 ubuntu22.04 下,net.core.somaxconn = 4096
╰─➤ sysctl net.core.somaxconn
net.core.somaxconn = 4096
Supported tags and respective Dockerfile links python3.9, latest (Dockerfile) python3.8, (Dockerfile) python3.7, (Dockerfile) python3.6 (Dockerfile) python3.9-slim (Dockerfile) python3.8-slim (Dockerf
uvicorn 是如何实现多进程同时监听一个 socket 的?如何设置了多个工作进程,http 请求是如何在多个 worker 进程中分配的?是由谁来分配的?是操作系统把 http 请求给 master 进程,再有 master 经常转发给 worker 进程,还是操作系统直接发给 worker 进程?如果是操作系统直接发给 worker 进程,具体又是怎么给的?是操作系统轮训 worker,均
问题内容: 我正在尝试在Python中的多处理库中使用队列。执行下面的代码后(打印语句起作用),但是在调用Queue上的join之后,这些进程没有退出,并且仍然存在。我如何终止其余过程? 谢谢! 问题答案: 尝试这个:
我跑 fastapi 的时候,都是用 uvicorn 直接部署 但是我发现,uvicorn 的官方文档在讲部署的时候,还有 gunicorn 混搭 https://www.uvicorn.org/deployment/#gunicorn 如果 uvicorn 和 gunicorn 一起部署,还能异步吗?因为按照我的理解,gunicorn 是一个 wsgi server,而 uvicorn 是一个
我写了一个fastapi应用程序。现在我正在考虑部署它,但是我似乎遇到了奇怪的意外性能问题,这似乎取决于我使用的是uvicorn还是gunicorn。特别是,如果我使用gunicorn,所有代码(甚至是标准库纯python代码)似乎都会变慢。为了进行性能调试,我编写了一个小应用程序来演示这一点: 运行Fastapi Appi与: get to的共振体始终类似于: 然而使用: 我经常得到这样的时机
亚马逊EC2上的许多Django应用程序部署使用HTTP服务器NGINX和GUnicorn。 我想知道它们实际上是做什么的,为什么两者并行使用。并行运行它们的目的是什么?