我正在尝试设置一个uwsgi托管的应用程序,以便我使用uwsgi --reload进行优雅的重新加载,但我显然失败了。这是我的测试uwsgi设置:
[admin2-prod]
http = 127.0.0.1:9090
pyargv = $* --db=prod --base-path=/admin/
max-requests = 3
listen=1000
http-keepalive = 1
pidfile2 =admin.pid
add-header=Connection: keep-alive
workers = 1
master = true
chdir = .
plugins = python,http,router_static,router_uwsgi,router_http
buffer-size = 8192
pythonpath = admin2
file = admin2/app.py
static-map=/admin/static/=admin2/static/
static-map=/admin/v3/build/=admin2/client/build/
disable-logging = false
http-timeout = 100
(请注意,我之前运行过sysctl net.core.somaxconn = 1000)
这是我的测试python脚本:
import httplib
connection = httplib.HTTPConnection('127.0.0.1', 9090)
connection.connect()
for i in range(0, 1000):
print 'sending... ', i
try:
connection.request('GET', '/x', '', {'Connection' : ' keep-alive'})
response = connection.getresponse()
d = response.read()
print ' ', response.status
except:
connection = httplib.HTTPConnection('127.0.0.1', 9090)
connection.connect()
上述客户端在--reload:
期间失败sending... 920
Traceback (most recent call last):
File "./test.py", line 15, in <module>
connection.connect()
File "/usr/lib64/python2.7/httplib.py", line 836, in connect
self.timeout, self.source_address)
File "/usr/lib64/python2.7/socket.py", line 575, in create_connection
raise err
socket.error: [Errno 111] Connection refused
从tcpdump,看起来uwsgi确实接受了第二个传入的TCP请求,该请求发生在--reload,客户端正在发送GET,服务器正在TCP确认它,但连接最终由服务器进行RSTed发回HTTP响应。那么,我还缺少什么才能使服务器对这个传入连接进行排队,直到它准备好处理它并获得真正优雅的重新加载?
答案 0 :(得分:0)
当uwsgi进程显然不能接受连接时,您的异常就会发生...所以,您的进程必须等到服务器重新启动 - 您可以使用带有超时的循环除了阻止正确处理这种情况。试试这个:
import httplib
import socket
import time
connection = httplib.HTTPConnection('127.0.0.1', 8000)
# connection moved below... connection.connect()
for i in range(0, 1000):
print 'sending... ', i
try:
connection.request('GET', '/x', '', {'Connection' : ' keep-alive'})
response = connection.getresponse()
d = response.read()
print ' ', response.status
except KeyboardInterrupt:
break
except socket.error:
while True:
try:
connection = httplib.HTTPConnection('127.0.0.1', 8000)
connection.connect()
except socket.error:
print 'cant connect, will try again in a second...'
time.sleep(1)
else:
break
重启前:
sending... 220
404
sending... 221
404
sending... 222
404
重启服务器:
cant connect, will try again in a second...
cant connect, will try again in a second...
cant connect, will try again in a second...
cant connect, will try again in a second...
再次启动服务器:
sending... 223
404
sending... 224
404
sending... 225
404
更新您的评论:
显然,在现实世界中,你无法重写所有的代码 连接到您的服务器的http客户端。我的问题是:我能做些什么 为任意客户端做一个优雅的重新加载(没有失败)。
我认为可以处理客户端此类问题的通用解决方案之一 - 客户端和服务器之间的简单代理。使用代理,您可以独立于客户端重新启动服务器(意味着代理始终打开)。 事实上,这是常用的 - 来自Web应用程序前端代理的502(错误网关)错误 - 完全相同的情况 - 客户端在应用程序服务器关闭时从代理接收错误!尝试 nginx,清漆或类似的东西。
顺便说一下,uwsgi内置了“proxy / load-balancer / router”插件:
uWSGI FastRouter
对于高级设置,uWSGI包含“fastrouter”插件,代理uwsgi的代理/负载均衡器/路由器 协议。它默认内置。你可以把它放在你的 webserver和真正的uWSGI实例可以更好地控制 将HTTP请求路由到您的应用程序服务器。
这里的文档:http://uwsgi-docs.readthedocs.io/en/latest/Fastrouter.html
答案 1 :(得分:0)
您正在同一个uWSGI实例中管理应用程序和代理,因此当您重新加载堆栈时,您也会终止前端Web服务器(您使用&#39; http&#39;选项启动的服务器)。
您必须在另一个uWSGI实例中拆分http路由器,或使用nginx / haproxy或类似的。一旦有了两个不同的堆栈,就可以在不关闭套接字的情况下重新加载应用程序