Должен ли я придерживаться или отказаться от Python для решения проблемы параллелизма?

У меня есть проект 10K LOC , написанный на Django с довольно сложной сделкой Celery (RabbitMQ ) для асинхронности и фоновых заданий там, где это необходимо, и пришли к выводу, что части системы выиграют от перезаписи в , кроме Django, для улучшения параллелизма. Причины включают:

  • Сигналы обрабатывающие и изменяемые объекты. Особенно, когда один сигнал запускает другой, обработка их в Django с помощью ORM может быть удивительной, когда экземпляры меняются или исчезают. Я хочу использовать какой-то метод обмена сообщениями, в котором данные, переданные вместе, не изменяются в обработчике ( копия Clojure's-copy-on-write подход кажется приятным, если я правильно понял).
  • Части системы не основаны на веб-интерфейсах и требуют лучшей поддержки для одновременного выполнения задач. Например, система читает теги NFC , а когда читается, светодиод продолжается несколько секунд (задача Сельдерея) , воспроизводится звук (другая задача Celery), и запрашивается база данных (другая задача). Это реализовано как команда управления Django, но Django и его ORM, являющиеся синхронными по своей природе и разделяющие память, ограничены (мы думаем добавить больше читателей NFC, и я не думаю, что подход Django + Celery будет работать дольше, Я хотел бы видеть лучшие возможности передачи сообщений).

Каковы плюсы и минусы использования чего-то вроде Twisted или Торнадо по сравнению с переходом на такой язык, как Erlang или Clojure ? Меня интересуют практические выгоды и недостатки.

  

Как вы пришли к выводу, что некоторые части системы будут лучше жить на другом языке? Вы испытываете проблемы с производительностью? Насколько серьезны эти проблемы? Если это может быть быстрее, важно ли это быстрее?

Пример 1: Django работает вне HTTP-запроса:

  1. Прочитан тег NFC.
  2. Запрашивается база данных (и, возможно, LDAP), и мы хотим что-то сделать, когда данные становятся доступными (красный или зеленый свет, воспроизведение звука). Это блокирует использование Django ORM, но пока есть рабочие-сельдерей, это не имеет значения. Может быть, проблема с большим количеством станций.

Пример 2: «передача сообщений» с использованием сигналов Django:

  1. Выполняется событие post_delete, другие объекты могут быть изменены или удалены из-за этого.
  2. В конце, уведомления должны быть отправлены пользователям. Здесь было бы неплохо, если бы аргументы, переданные обработчику уведомлений, были копиями удаленных или подлежащих удалению объектов и гарантированно не изменялись в обработчике. (Это можно сделать вручную просто, не передавая объекты, управляемые ORM, конечно.)
31 голос | спросил Simon Pantzare 20 PM00000060000004131 2011, 18:27:41

4 ответа


35

Открытие мысли

Как вы пришли к выводу, что некоторые части системы будут лучше жить на другом языке? Вы испытываете проблемы с производительностью? Насколько серьезны эти проблемы? Если это может быть быстрее, важно ли это быстрее?

Анимация с одной нитью

Есть несколько вопросов и других веб-ресурсов, которые уже касаются различий, плюсов и минусов однопоточной асинхронности и многопоточного параллелизма. Интересно прочитать о том, как одноразовые версии Node.js , асинхронная модель потоков выполняется, когда I /O является основным узким местом, и есть много запросов, обслуживаемых сразу.

Twisted, Tornado и другие асинхронные модели отлично используют однопоточность. Поскольку в большом количестве веб-программирования имеется множество операций ввода-вывода (сеть, база данных и т. Д.), Время ожидания ожидаемых удаленных вызовов значительно увеличивается. Это время, которое можно потратить на другие вещи, например, на запуск других вызовов базы данных, создание страниц и создание данных. Использование этого однопотока чрезвычайно велико.

Одно из самых больших преимуществ однопоточной асинхронизации заключается в том, что она использует much меньше памяти. При многопоточном выполнении каждому потоку требуется определенное количество зарезервированной памяти. По мере увеличения количества потоков увеличивается объем памяти, необходимый только для того, чтобы потоки существовали. Поскольку память конечна, это означает, что существуют ограничения на количество потоков, которые могут быть созданы в любой момент времени.


Пример

В случае веб-сервера притворяйтесь, что каждому запросу присваивается свой собственный поток. Скажем, 1 МБ памяти требуется для каждого потока, а веб-сервер имеет 2 ГБ ОЗУ. Этот веб-сервер будет способен обрабатывать (приблизительно) 2000 запросов в любой момент времени, прежде чем просто недостаточно памяти для обработки.

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


Многопоточный параллелизм

Многопоточный параллелизм вместо этого использует одновременное выполнение нескольких задач. Это означает, что если поток заблокирован в ожидании вызова базы данных для возврата, другие запросы могут обрабатываться одновременно. Использование потоков меньше, но количество выполняемых потоков намного больше.

Многопоточный код также гораздо сложнее рассуждать. Существуют проблемы с синхронизацией, синхронизацией и другими проблемами параллельного параллелизма. Однопоточная асинхронность не страдает от тех же проблем.

Многопоточный код намного более эффективен для задач с интенсивным процессором . Если нет возможности для потока «уступить» - такой как сетевой вызов, который обычно блокируется - однопоточная модель просто не будет иметь никакого параллелизма вообще.

Оба могут сосуществовать

Между ними, конечно, есть перекрытие; они не являются взаимоисключающими. Например, многопоточный код может быть написан неблокирующим способом, чтобы лучше использовать каждый поток.


Нижняя линия

Есть много других вопросов, которые нужно учитывать, но мне нравится думать обо всех таких:

  • Если ваша программа связана с привязкой ввода /вывода , то асинхронная однопоточная работа, вероятно, будет работать очень хорошо.
  • Если ваша программа связана с ЦП , то, вероятно, будет лучше использовать многопоточную систему.

В вашем конкретном случае вам нужно определить, какая асинхронная работа завершается и как часто возникают эти задачи.

  • Выполняются ли они по каждому запросу? Если это так, память, вероятно, станет проблемой по мере увеличения количества запросов.
  • Выполняются ли эти задачи? Если это так, вам нужно будет рассмотретьсинхронизация при использовании нескольких потоков.
  • Являются ли эти задачи интенсивными? Если это так, это однопоточный поток, способный не отставать от нагрузки?

Нет простого ответа. Вы должны подумать о том, какие ваши варианты использования, и соответственно разработать. Иногда асинхронная однопоточная модель лучше. В других случаях требуется использование нескольких потоков для достижения массивной параллельной обработки.

Другие соображения

Существуют и другие проблемы, которые вам необходимо учитывать, а не только выбранную модель параллелизма. Вы знаете Эрланг или Клоджур? Считаете ли вы, что сможете написать безопасный многопоточный код на одном из этих языков, чтобы повысить производительность вашего приложения? Будет ли у вас много времени, чтобы ускориться на одном из этих языков, и будет ли язык, который вы узнаете, в будущем?

Как насчет трудностей, связанных с коммуникацией между этими двумя системами? Будет ли чрезмерно сложно поддерживать две отдельные системы параллельно? Как система Erlang получит задания от Django? Как Эрланг передаст эти результаты обратно в Django? Является ли производительность достаточно значительной проблемой, которая требует дополнительной сложности?


Заключительные мысли

Я всегда находил Django достаточно быстрым, и он использовался некоторыми сайтами с большой нагрузкой. Существует несколько оптимизаций производительности, которые можно увеличить, чтобы увеличить количество одновременных запросов и время отклика. По общему признанию, до сих пор я ничего не делал с Celery, поэтому обычные оптимизации производительности, вероятно, не помогут решить любые проблемы, которые могут возникнуть с этими асинхронными задачами.

Конечно, всегда есть предложение бросить больше аппаратного обеспечения в проблему. Является ли стоимость предоставления нового сервера дешевле стоимости разработки и обслуживания совершенно новой подсистемы?

На данный момент я задал слишком много вопросов, но это было моим намерением. Ответ не будет легким без анализа и дальнейших подробностей. Уметь анализировать проблемы сводится к пониманию вопросов, которые нужно задать, хотя ... надеюсь, я помог на этом фронте.

Чувство кишки говорит, что переписать на другом языке не нужно. Сложность и стоимость, вероятно, будут слишком велики.


Edit

Ответ на последующие действия

В вашем обзоре представлены очень интересные примеры использования.


1. Django работает вне HTTP-запросов

Ваш первый пример включал чтение тегов NFC, а затем запрос к базе данных. Я не думаю, что для написания этой части на другом языке вам будет полезно, просто потому, что запрос базы данных или LDAP-сервера будет связан сетевым вводом-выводом (и, возможно, с производительностью базы данных). С другой стороны, количество одновременных запросов будет связано с самим сервером, так как каждая команда управления будет выполняться как собственный процесс. Будет время установки и разрыва, которое влияет на производительность, поскольку вы не отправляете сообщения на уже запущенный процесс. Тем не менее, вы сможете отправлять несколько запросов одновременно, поскольку каждый из них будет изолированным процессом.

В этом случае я вижу два пути, которые вы можете исследовать:

  1. Убедитесь, что ваша база данных способна обрабатывать сразу несколько запросов с пулом соединений. (Oracle, например, требует, чтобы вы настроили Django соответственно 'OPTIONS': {'threaded':True}.) Могут быть аналогичные параметры конфигурации на уровне базы данных или уровне Django, что вы можете настроить свою собственную базу данных. Независимо от того, на каком языке вы пишете свои запросы к базе данных, вам придется подождать, пока эти данные вернутся, прежде чем вы сможете подсвечивать светодиоды. Производительность кода запроса может изменить ситуацию, и Django ORM не молниеносно (, но , как правило, достаточно быстро).
  2. Сведите к минимуму время установки /срыва. Постоянно выполняйте процесс и отправляйте ему сообщения.(Исправьте меня, если я ошибаюсь, но на самом деле это ваш основной вопрос.) Описан ли этот процесс в Python /Django или другом языке /структуре выше. Мне не нравится идея часто использовать команды управления. Можно ли постоянно работать с небольшим фрагментом кода, который толкает сообщения от считывателей NFC в очередь сообщений, которые Celery затем читает и пересылает в Django? Настройка и отключение небольшой программы, даже если она написана на Python (но не Django!), Должна быть лучше, чем запуск и остановка программы Django (со всеми ее подсистемами).

Я не уверен, какой веб-сервер вы используете для Django. mod_wsgi для Apache позволяет вам настроить количество процессов и потоков в процессах, которые запрашивают службы. Не забудьте настроить соответствующую конфигурацию вашего веб-сервера, чтобы оптимизировать количество обслуживаемых запросов.


2. «Передача сообщений» с помощью сигналов Django

Ваш второй вариант использования также довольно интересен; Я не уверен, есть ли у меня ответы на это. Если вы удаляете экземпляры модели и хотите работать с ними позже, возможно, их можно будет сериализовать JSON.dumps, а затем десериализовать ---- +: = 3 = + ----. Невозможно полностью воссоздать граф объектов позже (запрос к связанным моделям), поскольку связанные поля загружаются из базы данных, и эта ссылка больше не будет существовать.

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

ответил Josh Smeaton 20 PM00000070000005031 2011, 19:05:50
8

Я сделал очень сложную высокомасштабируемую разработку для крупного US провайдера . Мы сделали несколько серьезных чисел tranasaction, используя Twisted server, и это был кошмар сложность получения Python /Twisted для масштабирования на все, что было привязано к процессору . привязка ввода /вывода не проблема, но ограничение ЦП было невозможно. Мы могли бы собрать системы быстро, но их масштабирование для миллионов одновременных пользователей было кошмаром конфигурации и сложности, если они были связаны процессором.

Я написал сообщение в блоге об этом, Python /Twisted VS Erlang /OTP .

TLDR; Erlang выиграл.

ответил Jarrod Roberson 22 AM00000050000001831 2011, 05:48:18
4

Практические проблемы с скрученными (которые я люблю и использовал около пяти лет):

  1. Документация оставляет желать лучшего, и в любом случае модель довольно сложна. Мне трудно заставить других программистов Python работать с Twisted code.
  2. Я закончил использование блокировки ввода-вывода файлов и доступа к базе данных из-за отсутствия хороших API-интерфейсов блокировки. Это может сильно повредить работе.
  3. Кажется, что нет огромного сообщества и здорового сообщества, использующего Twisted; например Node.js имеет гораздо более активную разработку, особенно для веб-программирования.
  4. Это еще Python, и по крайней мере CPython - это не самая быстрая вещь.

Я немного поработал с помощью Node.js с CoffeeScript , и если одновременная производительность ваша забота тогда может стоить скачка.

Рассматривали ли вы запуск нескольких экземпляров Django с некоторыми соглашениями о распространении клиентов между экземплярами?

ответил Dickon Reed 20 PM00000070000005631 2011, 19:28:56
1

Я предлагаю следующее, прежде чем вы перейдете на другой язык.

  1. Используйте LTTng для записи системных событий, таких как ошибки страницы, переключатели контекста и ожидания системного вызова.
  2. Преобразуйте любое время, затрачивая слишком много времени на использование библиотеки C, и используйте любой шаблон дизайна, который вам нравится (многопоточность, событие на основе сигнала, обратный вызов async или традиционный Unix select ), что хорошо для I /O там.

Я бы не использовал потоки в Python, как только приложение имеет приоритет в производительности. Я бы взял вышеприведенный вариант, который может решить многие проблемы, такие как повторное использование программного обеспечения, возможность подключения к Django , производительность, простота разработки и т. д.

ответил holmes 21 AM00000030000005431 2011, 03:07:54

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132