GEvent / GUnicorn и выпуск C10k

Проблема C10K говорит нам о традиционных веб-серверах, которые в лучшем случае имеют ограничение в ~10 тыс. Ограничений.

Серверы, такие как nginx, используют однопотоковую модель и асинхронную связь вместо потоков для обработки входящих запросов. AFAIK Gevent использует гринлеты (переключаемые контексты исполнения внутри одного потока) вместо потоков.

Это подводит меня к двум вопросам (опять же: предположим, что мы находимся в асинхронной модели - подумайте в gevent и gunicorn):

  1. При таких обстоятельствах: существует ли риск нехватки ресурсов? Для серверов на базе greenlet я ограничу вопрос еще: предположим, что перегрузка ресурсов на самом деле является блокировкой мьютекса (блокировка мьютекса блокирует текущий поток, хотя не текущий процесс; но теперь мы больше не в многопоточной архитектуре если мы используем гринлеты... я не прав?).
  2. Если мы не в архитектуре на основе гринлетов (и не в многопоточной): как реализованы веб-сокеты на сервере?

И дополнительный вопрос касается Джанго:

  1. Как определить текущий запрос, когда я не нахожусь внутри представления и не могу напрямую получить доступ к параметрам представления? У меня была плохая практика идентификации текущего потока, используя threading.local (который был заполнен в пользовательском Middleware), но в то время я не рассматривал непоточные архитектуры (мой код был в порядке, пока я мог сказать "один запрос (подразумевает) один поток").

Это поможет мне в сценарии: определение текущего request когда форма называется (мое / пользовательское) поле clean() метод (т.е. проверка значения по данным в зависимости от текущего запроса). Однако этот метод потерпит неудачу, если у меня будут одновременные запросы, превышающие предел 10 КБ и использующий асинхронный (не поточный) подход.

1 ответ

(EDIT - gevent.monkey.patch_all () - запускается в файле сценария wsgy.py - автоматически исправляет локальные потоки, чтобы они стали локальными для greenlet, поэтому для GEvent (или для GUventorn с работниками Gevent) эта альтернатива, использующая Werkzeug, не нужна - если как-то, вы используете гринлеты без GEvent, вам может понадобиться это решение)

Я нашел ответ, когда вспомнил об Flask Framework:

Flask - это платформа, которая поддерживает "глобально" многие объекты, такие как session а также request который "выглядит" как threading.local объекты. Основное различие заключается в том, что они являются контекстными локальными, а не локальными потоками, а контекст - это любой текущий стек выполнения.

Поток имеет свой собственный контекст (отсюда и концепция переключения контекста при чтении теории потоков). Процесс имеет свой контекст, который содержит потоки (и основной поток).

До сих пор в известной нам теории процесс содержит поток, а поток содержит собственный контекст выполнения. Данные всегда совместно используются, если поток не может создать свой собственный контекст данных. Именно здесь появляется концепция локальных потоков (переменных / данных).

Но для решения этой концепции параллельного выполнения и с учетом проблемы C10K было предпочтительным асинхронное выполнение в одном потоке вместо нескольких блокирующих потоков с соответствующим переключателем контекста (особенно в отношении python, где у нас есть GIL в стандартном python distr0). Greenlet был создан как контекст переключения того же потока, и теперь иерархия изменилась:

Process 1--* thread 1--* greenlet (and now the requests are here)

Таким образом, концепция Greenlets была создана и реализована в Python на серверах, таких как Gevent, и вы больше не можете использовать локальные данные потоков, потому что запросы больше не связаны с потоками (т. Е. Они могут совместно использовать один и тот же локальный контекст потока, участвуя в гонке за данными).

Теперь сам контекст - это гринлет, и нам нужно понятие локального контекста вместо локальных потоков.

Итак: Как Flask использует локальный контекст, который изолирует данные для каждого запроса? (например, сеанс, запрос). Ответ на контекстно-независимую изоляцию находится здесь:

Контекст Werkzeug Местные жители

Werkzeug и Flask имеют одного и того же создателя. Werkzeug - это не Framework, а просто набор утилит, которые вы можете использовать в любой среде WSGI (например, Django). Сам фреймворк - Flask, который на самом деле зависит от утилит Werkzeug.

Локальные контексты Werkzeug помогают создавать (правильно сказано) контекстные локальные объекты (контекст означает поток, запрос или процесс - в зависимости от того, как сервер отправляет запросы), что может помочь нам сохранить специфичные для гринлета данные и избежать использования threadlocals:

#a python module for my django project where I define
#a custom field class which statically needs to know the
#current request.

#I was using, instead, a threadlocal. The usage is THE SAME.
#the main difference is that threads are GCed, while contexts
#not necessarily, so you must ALWAYS release them explicitly
#using release_local, for the current context.

#this code below used to have `threading.local` instances
#instead of `werkzeug.local.Local` instances.

#as I said before, assigning data works like before, but
#the main difference is when releasing the data.

from werkzeug.local import Local, release_local

class AutocompleteField(object):

    DATA = Local()

    @staticmethod
    def set_request(request):
        AutocompleteField.DATA.request = request

    @staticmethod
    def unset_request(request):
        release_local(AutocompleteField.DATA)

    @staticmethod
    def get_request():
        try:
            return AutocompleteField.DATA.request
        except AttributeError as e:
            return None
Другие вопросы по тегам