uwsgi --reload拒绝传入的连接

时间:2016-07-13 10:51:43

标签: python tcp uwsgi

我正在尝试设置一个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响应。那么,我还缺少什么才能使服务器对这个传入连接进行排队,直到它准备好处理它并获得真正优雅的重新加载?

2 个答案:

答案 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或类似的。一旦有了两个不同的堆栈,就可以在不关闭套接字的情况下重新加载应用程序