Действительно ли Торнадо не блокирует?
Tornado рекламирует себя как "относительно простую, неблокирующую структуру веб-сервера" и был разработан для решения проблемы C10k. Однако, глядя на свою оболочку базы данных, которая обертывает MySQLdb, я наткнулся на следующий фрагмент кода:
def _execute(self, cursor, query, parameters):
try:
return cursor.execute(query, parameters)
except OperationalError:
logging.error("Error connecting to MySQL on %s", self.host)
self.close()
raise
Насколько я знаю, вызовы MySQLdb, которые построены поверх libmysqlclient
, блокируются .
Правильно ли я думаю, что долговременный запрос сделает весь сервер Tornado безответственным до тех пор, пока он не завершится или не будет волшебным кодом?
Ответы
Ответ 1
Да, при отсутствии других мер сервер будет ожидать завершения выполнения запроса. Это не означает, что Tornado не является неблокирующим веб-сервером.
"Неблокирующий веб-сервер" не блокирует сетевые операции ввода-вывода (и может иметь некоторое положение для дискового ввода-вывода, если он выполняет статический файл). Это не означает, что вы получаете мгновенное, нарушающее казуальность выполнение инструкции в своем приложении.
Выполнение вызова базы данных требует времени, так же как чтение файлов, форматирование строк, шаблонов обработки и т.д. требует времени. Выполнение любой из этих вещей в том же потоке, что и основной цикл событий сервера, предотвратит движение цикла до тех пор, пока вы не закончите.
Ответ 2
Торнадо не блокируется, если вы пишете неблокирующий код сверху, если он, например. используя asyncmongo и @tornado.web.asynchronous decorator, Tornado в качестве основы предоставляет инструменты для этого.
Брет Тейлор, один из авторов, пишет:
Мы экспериментировали с различными подходами асинхронного БД, но синхронно в FriendFeed, потому что, как правило, если наши запросы в БД были отставание наших запросов, наши бэкенды не могли масштабироваться до нагрузки так или иначе. Вещи, которые были достаточно медленными, были абстрагированы, чтобы отделить бэкэнд-услуги, которые мы получаем асинхронно через асинхронный HTTP-запрос модуль.
Верно, что Tornado не включает неблокирующий уровень базы данных; на самом деле слой базы данных не является неотъемлемой частью структуры Tornado вообще, в отличие от, например, Django ORM. Да, Tornado поставляется с блокирующей оболочкой MySQL, потому что то, что FriendFeed произошло, но это скорее внешняя библиотека, чем основная функциональность. Я уверен, что большинство людей используют что-то еще для доступа к базе данных.
Ответ 3
Да; это не полностью неблокирующий веб-сервер вообще.
Неблокирующий веб-сервер не блокирует, используя неблокирующие API для ввода-вывода файлов, доступа к базе данных и т.д., чтобы гарантировать, что один запрос, который должен ждать чего-то, чтобы завершить, не мешает другим запросам от обработки. Это относится ко всему, что может блокировать сервер, включая доступ к базе данных.
Нет ничего глупого, как "нарушение причинности" при наличии неблокирующего доступа к базе данных; имеет смысл запускать неблокирующий запрос, связанный с одним запросом, и обрабатывать другие запросы, пока они все еще работают. На практике это обычно означает создание нескольких соединений с базой данных базы данных.
Обратите внимание, что если вы пытаетесь запустить десять тысяч одновременных запросов, будьте осторожны: большинство бэкэндов базы данных не справляются с этим. Если у вас более нескольких десятков запросов на базу данных, которые вы запускаете параллельно, вы, вероятно, хотите получить что-то вроде пула соединений, чтобы веб-сервер мог делать много соединений с базой данных, не опуская бэкэнд. Это вызовет блокировку запросов, ожидающих в очереди, чтобы получить доступ к базе данных, но это означает, что это не блокирует весь сервер - просто запросы, которым нужна база данных.