2015-06-19 16 views
5

Ho seguito questo tutorial per provare a ottenere Flask SocketIO in esecuzione utilizzando nginx e gunicorn.Configurazione corretta per Saskione fiascoIO

nginx

server { 
    location/{ 
     proxy_pass http://127.0.0.1:8000; 
     proxy_redirect off; 

     proxy_set_header Host $host; 
     proxy_set_header X-Real-IP $remote_addr; 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 

    location /socket.io { 
     proxy_pass http://localhost:8000/socket.io; 
     proxy_redirect off; 
     proxy_buffering off; 

     proxy_set_header Host $host; 
     proxy_set_header X-Real-IP $remote_addr; 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

     proxy_http_version 1.1; 
     proxy_set_header Upgrade $http_upgrade; 
     proxy_set_header Connection "Upgrade"; 

    } 

} 

gunicorn_config.py

bind = '127.0.0.1:8000' 
workers = 2 
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker' 

In Supervisor io chiamo la mia app con:

[program:gunicorn-couponmonk] 
directory = ~/couponmonk_project 
command =~/venv/py2.7/bin/python ~/venv/py2.7/bin/gunicorn -c ~/venv/py2.7/lib/python2.7/site-packages/gunicorn/gunicorn_config.py __init__.py 
stdout_logfile = /var/log/gunicorn/couponmonk-std.log 
stderr_logfile = /var/log/gunicorn/couponmonk-err.log 
user = mint 

Con questa configurazione, la mia app (senza l'utilizzo di Flask SocketIO) funziona correttamente.

Sono solo confuso su come utilizzare socketIO. Se vado all'indirizzo http://localhost:8000/socket.io, ottengo la risposta Internal Server Error.

L'esempio HTML/Javascript (https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/example/templates/index.html) contiene questa linea:

var socket = io.connect('http://' + document.domain + ':' + location.port + namespace); 

Ho due domande:

1) Quale indirizzo si suppone questa variabile per puntare a?

2) La mia configurazione (nginx, gunicorn) è corretta?

Scusa se questa domanda è sciocca. Sono solo confuso su come tutto ciò dovrebbe funzionare.

Grazie per il vostro aiuto.

** UPDATE **

Questa è l'uscita del file nginxerror.log quando provo e accesso http://localhost/socket.io.

2015/06/20 14:05:08 [debug] 1917#0: *1 http cleanup add: 00000000009F2170 
2015/06/20 14:05:08 [debug] 1917#0: *1 get rr peer, try: 1 
2015/06/20 14:05:08 [debug] 1917#0: *1 socket 12 
2015/06/20 14:05:08 [debug] 1917#0: *1 epoll add connection: fd:12 ev:80000005 
2015/06/20 14:05:08 [debug] 1917#0: *1 connect to 127.0.0.1:8000, fd:12 #2 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream connect: -2 
2015/06/20 14:05:08 [debug] 1917#0: *1 posix_memalign: 0000000000A14170:128 @16 
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437 
2015/06/20 14:05:08 [debug] 1917#0: *1 http finalize request: -4, "/socket.io?" a:1, c:2 
2015/06/20 14:05:08 [debug] 1917#0: *1 http request count:2 blk:0 
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A295E0 
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648 
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request handler 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream send request 
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer buf fl:1 s:439 
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer in: 00000000009F21A8 
2015/06/20 14:05:08 [debug] 1917#0: *1 writev: 439 
2015/06/20 14:05:08 [debug] 1917#0: *1 chain writer out: 0000000000000000 
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer del: 12: 1434773168437 
2015/06/20 14:05:08 [debug] 1917#0: *1 event timer add: 12: 60000:1434773168437 
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A295E0 
2015/06/20 14:05:08 [debug] 1917#0: *1 http run request: "/socket.io?" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream check client, write event:1, "/socket.io" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream recv(): -1 (11: Resource temporarily unavailable) 
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A15E38 
2015/06/20 14:05:08 [debug] 1917#0: *1 post event 0000000000A29648 
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A29648 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream dummy handler 
2015/06/20 14:05:08 [debug] 1917#0: *1 delete posted event 0000000000A15E38 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream request: "/socket.io?" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http upstream process header 
2015/06/20 14:05:08 [debug] 1917#0: *1 malloc: 00000000009E88A0:4096 
2015/06/20 14:05:08 [debug] 1917#0: *1 recv: fd:12 244 of 4096 
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy status 500 "500 Internal Server Error" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Connection: close" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Type: text/html" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header: "Content-Length: 141" 
2015/06/20 14:05:08 [debug] 1917#0: *1 http proxy header done 
2015/06/20 14:05:08 [debug] 1917#0: *1 xslt filter header 
2015/06/20 14:05:08 [debug] 1917#0: *1 HTTP/1.1 500 Internal Server Error 
Server: nginx/1.4.6 (Ubuntu) 
Date: Sat, 20 Jun 2015 04:05:08 GMT 
Content-Type: text/html 
Content-Length: 141 
Connection: keep-alive 

Non so quanto sia utile, ma non so dove altro cercare informazioni extra.

Sono anche curioso di sapere perché posso accedere a questo: http://localhost/socket.io123abc

e ancora ottenere un Internal Server Error al contrario di un errore di Not Found?

ho anche aggiornato il mio supervisord.conf file in base Miguel's risposta qui sotto:

supervisord.conf

[program:gunicorn-couponmonk] 
directory = /home/giri/couponmonk_project 
command = /home/giri/venv/py2.7/bin/python /home/giri/venv/py2.7/bin/gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker __init__:app 
stdout_logfile = /var/log/gunicorn/couponmonk-std.log 
stderr_logfile = /var/log/gunicorn/couponmonk-err.log 
user = mint 

/var/log/gunicorn/couponmonk-err.log

2015-06-20 14:30:11 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000) 
2015-06-20 14:30:11 [3821] [ERROR] Retrying in 1 second. 
2015-06-20 14:30:12 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000) 
2015-06-20 14:30:12 [3821] [ERROR] Retrying in 1 second. 
2015-06-20 14:30:13 [3821] [ERROR] Connection in use: ('127.0.0.1', 8000) 
2015-06-20 14:30:13 [3821] [ERROR] Retrying in 1 second. 

La lista continua per un po '..

+0

Probabilmente avete alcuni traceback in python nei file '/ var/log/gunicorn/couponmonk- *'. Riesci a trovarli e a pubblicarli? –

+0

@ DavidK.Hess Ho pubblicato l'output. Grazie per l'aiuto. –

+1

Sembra che tu abbia accidentalmente avviato lo stesso processo due volte. Controlla attentamente l'elenco dei processi per assicurarti che sia in esecuzione una sola istanza del processo master gunicorn. –

risposta

0

In primo luogo, citerò che non mi consiglia di utilizzare SocketIO a tutti. Aggiunge un po 'di funzionalità utile su WebSockets ma rende impossibile il bilanciamento del carico con più worker (ridimensionamento orizzontale), a meno che non si rendano i clienti appiccicosi ai singoli lavoratori o si usi qualcosa come Redis per condividere informazioni sullo stato tra loro. Vi consiglio di dare un'occhiata a:

https://github.com/youen/gevent-websocket

WebSockets nativo è più semplice e più facile e scale su più lavoratori frontend per vero il bilanciamento del carico. Il codice necessario per implementare la logica della chat room è molto minimale.

Detto questo, ecco la risposta alle tue domande:

1) Cosa indirizzo è questa variabile dovrebbe puntare a?

Lo spazio dei nomi sarà "". (Secondo Miguel, autore di Flask-SocketIO, il client Javascript inserisce automaticamente la parte "socket.io".)

Quindi, l'url io.connect deve essere "http://[hostname]/".

2) La mia configurazione (nginx, gunicorn) è corretta?

La configurazione di Ngnix sembra corretta (vedere la sezione successiva). Se decidi di utilizzare WebSockets, potresti prendere in considerazione l'aggiunta di proxy_read_timeout 3600;. In caso contrario, se non si dispone di un protocollo chatty, il WebSocket verrà rilasciato da Nginx una volta al minuto (il valore predefinito). (Inoltre, secondo Miguel, SocketIO ha heartbeat che si occupano di questo.)

Gunicorn config non è corretto. Con SocketIO avete un paio di scelte:

  1. Set workers = 1 in gunicorn in modo che ogni cliente SocketIO sta parlando con lo stesso processo di lavoro.
  2. Modificare la configurazione di nginx per utilizzare il comando ip-hash che causerà l'assegnazione dei client ai lavoratori in base all'indirizzo IP del client.
  3. Utilizzare Redis o un altro database per consentire a ciascun lavoratore di condividere informazioni sullo stato (sebbene non sia chiaro nessuno ha ancora funzionato per Gevent SocketIO).

Queste scelte sono forzate perché SocketIO utilizza un meccanismo di configurazione stateful che si interrompe quando si tenta di ridimensionare orizzontalmente. Vedere questo problema per maggiori informazioni: https://github.com/abourget/gevent-socketio/issues/112

Ed ecco un link alla documentazione del SocketIO parlarne anche: http://socket.io/docs/using-multiple-nodes/

Se hai trovato un Internal Server Error poi c'è probabilmente un'eccezione essere collegati in qualche luogo. Prova a scovarlo e aggiungilo alla tua domanda.

Si noti che non è possibile verificare ciò toccando quell'URL nella barra degli indirizzi del browser: il browser non pronuncia il protocollo WebSocket appropriato per impostazione predefinita e non farà nulla di utile per l'utente. Le connessioni WebSocket devono essere configurate utilizzando l'API di Javascript.

Inoltre, il tentativo di raggiungere quell'URL con il numero di porta ignora nginx, che probabilmente non è quello che si vuole fare. Normalmente Nginx ascolta 80/443 e inoltra le richieste a localhost: 8000 (che viene chiamata impostazione "reverse proxy").

+0

Ci sono molte imprecisioni nella risposta. * Aggiunge un po 'di funzionalità utile su WebSockets * Socket.IO funziona su HTTP normale e WebSocket, sceglie il miglior trasporto per ogni client. Inoltre, tiene traccia degli utenti connessi e consente al server di trasmettere a tutti gli usi o ai gruppi di utenti che accedono a una stanza. Con WebSocket nessuno di questi esiste. * Native WebSockets è più semplice e più semplice e si adatta a più operatori frontend senza dover distribuire qualcosa come Redis * Sure, ma non è a causa di WebSocket, è perché non ci sono broadcast/sale. – Miguel

+0

* A causa di come il tuo traffico SocketIO è stato separato con una posizione separata nella configurazione di nginx, lo spazio dei nomi per definizione è /socket.io* Questo non è corretto, il nome della risorsa '/ socket.io' viene aggiunto dal socket .IO client, non va nell'URL di connessione. * In caso contrario, se non si dispone di un protocollo chatty, il WebSocket sottostante verrà rilasciato da Nginx una volta al minuto (il valore predefinito). * I pacchetti heart beat in Socket.IO lo impediranno. – Miguel

+0

Immagino dipenda dalla tua prospettiva. Con WebSocket così pervasivo ora (http://caniuse.com/#feat=websockets) non c'è bisogno di trasporti alternativi.Inoltre, la quantità di logica lato server necessaria per implementare le chat room può contenere meno di 100 righe di codice. Lo so perché l'ho fatto. Per me, il rompicapo aveva bisogno di qualcosa di simile a Redis per abilitare più frontend worker. SocketIO non fornisce quasi abbastanza utilità per renderlo utile. Dovrò prendere la parola sulle parti del namespace e del battito cardiaco e aggiornerò la mia risposta. –

2

Ti consiglio di far funzionare Flask-SocketIO senza nginx e gunicorn. Una volta che puoi farlo funzionare tramite il server gevent nativo, puoi passare alla tua configurazione reale.

quanto riguarda le vostre domande:

1) Cosa indirizzo è questa variabile suppone per puntare a?

L'istruzione di connessione è corretta. Socket.IO prenderà l'host, la porta e lo spazio dei nomi e costruirà l'URL di connessione da solo, incluso il componente /socket.io. Non è necessario specificarlo nella tua connessione.

2) La mia configurazione (nginx, gunicorn) è corretta?

Penso che la configurazione di nginx sia corretta. Sembra che tu l'abbia copiato direttamente dalla mia documentazione, e ho verificato che funzioni.

Il gunicorn config non sono sicuro, non stai mostrando abbastanza del tuo progetto da raccontare. Il comando che uso, che si dovrebbe avere nella propria configurazione del supervisore, è questa:

gunicorn --worker-class socketio.sgunicorn.GeventSocketIOWorker module:app 

Dove module è il modulo principale dell'applicazione, e app è il nome dell'istanza dell'applicazione Flask. Dovresti assolutamente usare un singolo lavoratore, non usare due lavoratori quando usi SocketIO.

+0

Grazie per il tuo aiuto Miguel. Sembra che l'errore "server interno" sia correlato a me nell'esecuzione di più istanze di 'gunicorn'. –