Предполагается, что нагрузка на мой веб-сервер составляет около 100 запросов в секунду.и у меня есть 70% запросов, которые связаны с вводом-выводом и выполняют легкую задачу (например, запросы к базе данных), в то время как 30% запросов связаны с процессором, что делает тяжелую задачу (такую как хеширование, вычисления с ресурсами в файловой системе),Последние запросы также являются блокировкой ввода / вывода, поэтому я использую ThreadPoolExecutor
, чтобы они не блокировали более быстрые запросы:
@tornado.concurrent.run_on_executor
def post(self, *args):
# I'm a io blocking request
data = heavy_load_task()
self.write(data)
, тогда как 70% запросов выполняются с asynchronous
decorator, таким образом запрашивая конкретный вызов self.finish()
для явного закрытия сокета:
@tornado.web.asynchronous
def post(self, *args):
# I'm a light request
data = light_load_task()
self.write(data)
self.finish()
См. здесь о том, как делать неблокирующие запросы в Tornado.В частности, вместо этого используется исполнитель пула потоков по умолчанию, например:
executor = concurrent.futures.ThreadPoolExecutor(5)
Я использую (надеюсь) лучшую реализацию, которая заботится об ограничении числа одновременных потоков, чтобы избежать нагрузки на память:
executor = BoundedThreadPoolExecutor(max_workers=5)
Пожалуйста, смотрите этот пакет для реализации BoundedThreadPoolExecutor
.
Кажется, это работает нормально.Из соображений производительности я попытался переместить прежние запросы легких задач из шаблона @tornado.web.asynchronous
в шаблон @tornado.concurrent.run_on_executor
, и здесь у меня возникла проблема.В какой-то момент сервер перестал обслуживать запросы, без сбоев, без ошибок времени выполнения.Он просто перестал получать запросы и обслуживать ответы с любой ошибкой или проблемой OOM на машине.Я пробовал разные размеры рабочей очереди max_workers
от 5 до 100 одновременно работающих без видимого эффекта.