【问题标题】:Asynchronous Pool of Connections in Tornado with multiple processesTornado 中具有多个进程的异步连接池
【发布时间】:2016-06-20 18:16:27
【问题描述】:

我同时使用 Tornado 4.2.1tornadoes 2.4.1 库来查询我的 Elasticsearch 数据库,我正在寻找一种方法来初始化 连接池在多进程服务中的多个 RequestHandler 实例之间共享。

有可能做到吗? Tornado 是否有特定的库可以做到这一点?

提前致谢

【问题讨论】:

    标签: asynchronous elasticsearch tornado connection-pooling pool


    【解决方案1】:

    由于tornado-es 只是一个HTTP 客户端,它在ESConnection 中使用AsyncHTTPClient每个请求都会建立新的 TCP 连接,除非指定了 Connection: keep-alive 标头。

    conn = ESConnection()
    conn.httprequest_kwargs['headers'] = {'Connection': 'keep-alive'}
    

    我没有测试过,但它应该可以工作。我在 ruby​​ 中使用了类似的设置(使用patron http 客户端),效果很好

    接下来的事情

    AsyncHTTPClient 对每个 ioloop 的最大并发请求数 (fetch) 有限制。每个达到限制的请求都只是在内部排队。

    您可能想要增加全局限制:

    AsyncHTTPClient.configure(None, max_clients=50)
    

    或者用自己的限制分隔客户端(force_instance):

    from tornadoes import ESConnection
    from tornado.httpclient import AsyncHTTPClient
    
    class CustomESConnection(ESConnection):
    
        def __init__(self, , host='localhost', port='9200', io_loop=None, protocol='http', max_clients=20):
            super(CustomESConnection, self).__init__(host, port, io_loop, protocol)
            self.client = AsyncHTTPClient(force_instance=True, max_clients=max_clients)
    

    最后

    要重用相同的 ESConnection,您可以在应用程序中创建它,因为应用程序可用于每个请求 (RequestHandler)

    from tornado.web import Application, RequestHandler
    from tornadoes import ESConnection
    
    class MainHandler(RequestHandler):
        def get(self):
            yield self.application.es.search('something')
    
    
    class MyApp(Application):
    
        def __init__(self, *args, **kwargs):
            super(MyApp, self).__init__(*args, **kwargs)
    
            self.es = ESconnection()
    
    if __name__ == "__main__":
        application = MyApp([
            (r"/", MainHandler),
        ])
        application.listen(8888)
        tornado.ioloop.IOLoop.current().start()
    

    多进程

    其实没有简单的方法。常见的方法是池化,主要用于需要持久连接的情况,如数据库(pgbouncer 用于 postgres)或作为高负载服务的优化。

    你还得写一个pooler,一个es的网关应用

    subprocess1 
               \  (http, zmq, ...)
                \            
                  > pooler (some queue and tornadoes api) - http -> elastisearch
                /
               /
    subprocess2
    

    子进程可以通过 HTTP、ØMQ(甚至是 pooler 有很多示例)或 IPC(sockects,...)的某些实现与 pooler 通信。

    【讨论】:

    • 您好@kwarunek,非常感谢您的回答。我完全理解你所说的,而且效果很好。我唯一不明白的是是否可以将它与多个子流程一起使用。在我的主要内部,我实现了一种机制,我可以从命令行获取启动多少子进程,以这种方式:http_server = tornado.httpserver.HTTPServer(MyApp)http_server.bind(8888)http_server.start(tornado.options.options.processes)tornado.ioloop.IOLoop.current().start() 是否可以在多个子进程中使用您的示例?
    • 我尝试使用 2 个子进程启动我的 Tornado,但出现此错误:RuntimeError: Cannot run in multiple processes: IOLoop instance has already been initialized. You cannot call IOLoop.instance() before calling start_processes()
    • 我添加了关于多进程的注释。
    • 并且运行时错误可能是因为在stackoverflow.com/questions/22641015/…stackoverflow.com/questions/22641015/…之前创建了AsyncHTTPClient
    • 非常感谢@kwarunek,太好了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2021-11-19
    • 2012-11-25
    相关资源
    最近更新 更多