由 GUnicorn 提供服务的烧瓶插座的并发连接出现问题



Flask-sockets使用geevent -websocket和gunicorn来服务websocket。

但是当我运行客户端脚本连接到超过300个连接的服务器时,更多的连接被gunicorn拒绝。

我已经尝试过配置gunicorn和/或从gevent-web-socket-worker继承,但两种方式都没有意义。

Linux的fd和连接限制可能是问题所在,但它们的价值远远大于我可怜的300个连接。

环境:

CentOS 6.5 with kernel-33.12.8-0.2.x86_64 
Python 2.6.6
Flask 0.10.1
gunicorn 18.0
ws4py 0.3.4
gevent-websocket 0.9.5
gevent 1.0.2

我使用我自己的项目(从flask-sockets派生)来服务web-sockets。Websocket服务器运行

gunicorn -b :9000 -k flask_sockets.worker flask_ws:app --debug  --log-level info --worker-connections 2000 --workers 8

"——worker"one_answers"——worker-connections"选项对并发连接没有影响。

from threading import Thread
import threading
from time import sleep
from ws4py.client.threadedclient import WebSocketClient
HOST = "ws://127.0.0.1:9000/echo2"

class EchoClient(WebSocketClient):
    def __init__(self, url, client_id, *args):
        super(EchoClient, self).__init__(url, *args)
        self.id = client_id
    def opened(self):
        print("connetcion %s opend!" % self.id)
    def closed(self, code, reason):
        print(("Closed down", code, reason))
    def received_message(self, m):
        print("#%s" % m)
        if len(m) == 175:
            self.close(reason='bye bye')
def run(cid):
    client = EchoClient(HOST, cid)
    client.connect()
    client.send("hello1")
    client.send("hello2")
    while True:
        sleep(10)
def multi_run():
    threads = [Thread(target=run, args=(x, )) for x in range(300)]
    for thread in threads:
        thread.setDaemon(True)
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
if __name__ == "__main__":
    multi_run()

这是我的客户端脚本,当我运行这个脚本时,第一个280客户端可以连接到服务器并且工作良好,最后20客户端得到错误,如

connetcion 244 opend!
connetcion 242 opend!
connetcion 245 opend!
connetcion 247 opend!
Exception in thread Thread-249:
Traceback (most recent call last):
  File "/usr/lib64/python2.6/threading.py", line 532, in __bootstrap_inner
    self.run()
  File "/usr/lib64/python2.6/threading.py", line 484, in run
    self.__target(*self.__args, **self.__kwargs)
  File "client.py", line 32, in run
    client.connect()
  File "/usr/lib/python2.6/site-packages/ws4py/client/__init__.py", line 237, in connect
    self.handshake_ok()
  File "/usr/lib/python2.6/site-packages/ws4py/client/threadedclient.py", line 68, in handshake_ok
    self._th.start()
  File "/usr/lib64/python2.6/threading.py", line 474, in start
    _start_new_thread(self.__bootstrap, ())
error: can't start new thread
在服务器端,我得到了
Traceback (most recent call last):
  File "/usr/lib64/python2.6/site-packages/gevent/pywsgi.py", line 508, in handle_one_response
    self.run_application()
  File "/usr/lib/python2.6/site-packages/geventwebsocket/handler.py", line 76, in run_application
    self.run_websocket()
  File "/usr/lib/python2.6/site-packages/geventwebsocket/handler.py", line 52, in run_websocket
    self.application(self.environ, lambda s, h, e=None: [])
  File "/usr/lib/python2.6/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/winkidney/workspace/flask_ws/flask-sockets/flask_sockets/__init__.py", line 40, in __call__
    handler(environment_ws)
  File "/home/winkidney/workspace/flask_ws/flask-sockets/flask_sockets/__init__.py", line 79, in get_instance
    return cls()(ws)
  File "/home/winkidney/workspace/flask_ws/flask-sockets/flask_sockets/contrib/__init__.py", line 30, in __call__
    self.protocol.on_message(message)
  File "/usr/lib/python2.6/site-packages/geventwebsocket/protocols/base.py", line 11, in on_message
    self.app.on_message(message)
  File "/home/winkidney/workspace/flask_ws/flask-sockets/example/flask_ws.py", line 23, in on_message
    self.write_message("this is the client message from %s: %s" % (request.remote_addr, message))
  File "/home/winkidney/workspace/flask_ws/flask-sockets/flask_sockets/contrib/__init__.py", line 42, in write_message
    self.ws.send(message, binary)
  File "/usr/lib/python2.6/site-packages/geventwebsocket/websocket.py", line 348, in send
    raise WebSocketError(MSG_SOCKET_DEAD)
WebSocketError: Socket is dead
{'GATEWAY_INTERFACE': 'CGI/1.1',
 'HTTP_CONNECTION': 'Upgrade',
 'HTTP_HOST': '127.0.0.1',
 'HTTP_ORIGIN': 'ws://127.0.0.1:9000/echo2',
 'HTTP_SEC_WEBSOCKET_KEY': 'fLip7N4OGt4hqbpK24EuBw==',
 'HTTP_SEC_WEBSOCKET_VERSION': '13',
 'HTTP_UPGRADE': 'websocket',
 'PATH_INFO': '/echo2',
 'QUERY_STRING': '',
 'REMOTE_ADDR': '127.0.0.1',
 'REMOTE_PORT': '28256',
 'REQUEST_METHOD': 'GET',
 'SCRIPT_NAME': '',
 'SERVER_NAME': 'localhost.localdomain',
 'SERVER_PORT': '9000',
 'SERVER_PROTOCOL': 'HTTP/1.1',
 'SERVER_SOFTWARE': 'gevent/1.0.2 gunicorn/18.0',
 'werkzeug.request': None,
 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x7fef077d81e0>,
 'wsgi.input': <gevent.pywsgi.Input object at 0x1ee9e10>,
 'wsgi.multiprocess': False,
 'wsgi.multithread': False,
 'wsgi.run_once': False,
 'wsgi.url_scheme': 'http',
 'wsgi.version': (1, 0),
 'wsgi.websocket': None,
 'wsgi.websocket_version': '13'} failed with WebSocketError

然后我注意到Gunicorn的文档说

worker_connections

—worker-connections INT 1000

客户端最大并发数。

这个设置只影响Eventlet和Gevent工作者类型。

我试图在flask_socket/init.py中继承GeventWebSocketWorker以取代原始的Worker,但仍然没有工作。

我的代码如下:

from geventwebsocket.gunicorn.workers import GeventWebSocketWorker
class Worker(GeventWebSocketWorker):
    def __init__(self, *args, **kwargs):
        super(Worker).__init__(*args, **kwargs)
        self.worker_connections = 10000

如果你能帮我解决这个问题或者告诉我解决的方法,我会很感激的。

最后,问题就在这里:

将fd更改为root用户,但以普通用户运行客户端。

我必须更改ulimit为普通用户以下链接:

https://askubuntu.com/questions/162229/how-do-i-increase-the-open-files-limit-for-a-non-root-user

可能有帮助:)

相关内容

  • 没有找到相关文章

最新更新