4

я использую оба Tornado 4.2.1 и смерчи 2.4.1 библиотеки запросить мою базу данных Elasticsearch и я ищу способ инициализировать пул из соединения для совместного использования нескольких экземпляров RequestHandler в службе нескольких процессов.Асинхронный пул соединений в Торнадо с несколькими процессами

Можно ли это сделать? Существуют ли специальные библиотеки для Tornado?

Заранее спасибо

ответ

5

Поскольку tornado-es является только клиент HTTP, он использует AsyncHTTPClient в ESConnection. Новое TCP-соединение производится по каждому запросу, если не указано заголовок Connection: keep-alive.

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

Я не тестировал, но он должен работать. Я использовал подобную установку в рубине (с patron клиента HTTP), и он работает хорошо

Следующая вещь

AsyncHTTPClient имеет ограничение на максимальное число одновременных запросов (fetch) в ioloop. Каждый запрос, который попадает в предел, просто находится внутри очереди.

Вы можете увеличить глобальное ограничение:

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 вы можете создать в приложении, так как приложение доступно с каждым запросом (Reque stHandler)

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, приложение шлюза эс

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

подпроцессы могут взаимодействовать с Pooler через HTTP, ØMQ (есть много примеров, даже Пулера) или некоторые реализации IPC (sockects , ...).

+1

Привет @kwarunek и большое спасибо за ваш ответ. Я полностью понимаю, что вы сказали, и работает отлично. Единственное, что я не понимаю, - это если можно использовать его с несколькими подпроцессами. Внутри моего основного я реализовал механизм, из которого я получаю из командной строки, сколько подпроцессов запускается, таким образом: 'http_server = tornado.httpserver.HTTPServer (MyApp) '' http_server.bind (8888) '' http_server.start (tornado.options.options.processes) '' tornado.ioloop.IOLoop.current(). Начать() ' Возможно ли использовать ваш пример в нескольких подпроцессах? – alauri

+1

Я попытался запустить свой Tornado с двумя подпроцессами, и я получил эту ошибку: 'RuntimeError: не может работать в нескольких процессах: экземпляр IOLoop уже инициализирован. Вы не можете вызвать IOLoop.instance() перед вызовом start_processes() '. – alauri

+0

Я добавил примечание о многопроцессорности. – kwarunek