2016-07-13 54 views
2

我想設置一個uwsgi託管的應用程序,使我得到優雅與uwsgi重裝--reload但我明顯失敗。這裏是我的測試uwsgi設置:uwsgi --reload拒絕傳入連接

[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確實接受這恰好在所述--reload,客戶端被髮送GET第二傳入TCP請求時,服務器是TCP確認序號,但在連接最後由服務器發送回HTTP響應之前RSTed。那麼,我錯過了什麼才能讓服務器對這個傳入連接進行排隊,直到它準備好處理它並獲得真正的優雅重新加載?

回答

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已內建 「代理/負載均衡/路由器」 插件:

的uWSGI FastRouter

對於高級設置uWSGI包括「fastrouter」插件,一個代理/負載均衡器/路由器說話uwsgi 協議。它默認是內置的。你可以將它放在你的 網絡服務器和真正的uWSGI實例之間,以更好地控制HTTP請求到你的應用服務器的路由。

文檔瀏覽:http://uwsgi-docs.readthedocs.io/en/latest/Fastrouter.html

+0

很明顯,在現實世界中,你不能重寫所有連接到你的服務器的http客戶端的代碼。我的問題是:我可以做些什麼來獲得任意客戶端的優雅重載(無失敗)。 – mathieu

+0

@mathieu - 通過異常退出,如果服務器不可用任意的客戶有邏輯錯誤的一些明顯:)但是,如果你是認真的 - ** **代理(檢查答案更新)或寫一些包裝過程中,將可能處理不當的情況或向客戶作者發送補丁... – ndpu

0

要管理兩個應用程序,並在同一個uWSGI實例的代理,所以當你重裝你殺前端Web服務器太堆棧(一個你先從'http'選項)。

您必須在HTTP路由器在另一個uWSGI實例拆分,或使用nginx的/ HAProxy的或相似的。一旦你有兩個不同的堆棧,你可以在不關閉套接字的情況下重新加載應用程序