GEvent / GUnicorn и проблема C10k

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

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

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

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

И еще один вопрос к Django:

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

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


person Luis Masuelli    schedule 10.07.2014    source источник
comment
Вы должны задать один вопрос в одном посте. Это не дискуссионный форум. Вы просите помощи с вашими решениями, но не объяснили свою проблему.   -  person Burhan Khalid    schedule 18.07.2014


Ответы (1)


(РЕДАКТИРОВАТЬ - gevent.monkey.patch_all () - запускать в файле сценария wsgy.py - автоматически исправляет локальные потоки, чтобы они становились локальными гринлетами, поэтому эта альтернатива с использованием Werkzeug не требуется для GEvent (или GUnicorn с рабочими процессами Gevent) - если каким-то образом вы используете гринлеты без 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 - это не фреймворк, а просто набор утилит, которые вы можете использовать в любой структуре 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
person Community    schedule 16.07.2014
comment
Не знаю, как вы ему помогли, потому что он говорит о джанго. - person Burhan Khalid; 18.07.2014
comment
Собственно пост мой. Хотя это django, вы можете свободно использовать утилиты Werkzeug (они предназначены не только для flask, но и для любого приложения wsgi). Однако истинный ответ нашел метод monkey.patch_all (). Вот почему выпуск поста. - person Luis Masuelli; 18.07.2014