HighLoad-2010: Приемы разработки высоконагруженных приложений на Twisted/Python 2

Posted by Андрей on Октябрь 28, 2010

25-26 октября состоялся HighLoad-2010, конференция получилось хорошей хотя бы потому, что было мало докладов ни о чем. Неплохой уровень, особенно было приятно увидеть «профессоров» PostgreSQL.

Я выступал с докладом «Приемы разработки высоконагруженных приложений на Twisted/Python». В докладе получилась (вполне сознательно) сборная солянка из советов и приемов о том, как писать приложения на Twisted (и похожих frameworkах). Из-за большого количества разных тем не получилось углубиться ни в одну, каюсь…

Тезисы:

  1. Запуск и шедулинг многих однопоточных процессов на одном сервере.
  2. Key-value storage и приемы работы с ним.
  3. Обслуживание сотен тысяч соединений на одном сервере.
  4. HTTP-сервисы и балансировка нагрузки, локализация нагрузки.
  5. Сбор статистики, интеграция с системой мониторинга.
  6. Шина обмена сообщениями на примере AMQP.
  7. Поиск и устранение memory leak.
  8. Оптимизация по времени отклика и пропускной способности.
  9. Мифы и правда о Python как языке разработки нагруженных приложений.

Презентация:



Утащить:

  • В формате PDF
  • Модуль py-numа, который упоминался в докладе

Профайлинг Twisted-приложений 2

Posted by Андрей on Февраль 15, 2010

Часто сам забываю, как профилировать легко и быстро Twisted-приложения (с некоторым изменениями подойдет для любых Python-приложений). Кроме Twisted нам понадобится еще KCachegrind

Запускаем наше приложение с включенным профайлингом:

twistd -n --savestats --profile=myprog.hotshot myprog

Подаем нагрузку, профайл собирается. Теперь с помощью утилиты hotshot2cg из поставки KCachegrind превращаем hotshot-профайл в calltree-профайл, который уже умеет KCachegrind «кушать».

hotshot2cg myprog.hotshot > myprog.calltree

Запускаем KCachegrind, открываем в нем полученный профайл:

kcachegrind myprog.calltree

HL++ (2009): Twisted Framework 17

Posted by Андрей on Октябрь 13, 2009

Сегодня выступал на HighLoad++ с докладом Twisted Framework — фреймворк для написания сетевых приложений в Python.

Введение

Последнее время в области web происходит смещение внимания с тяжелых application-серверов, которые тратят на обработку запроса сотни миллисекунд, а то и секунды, к более легковесным сервисам, передающим меньшие объемы данных с минимальной задержкой. Переход от генерации десятков и сотен килобайт HTML-кода в ответ на запрос к передаче изменений в данных, запакованных в JSON и измеряемых сотнями байт. В качестве примеров таких сервисов можно привести Gmail, FriendFeed, Twitter Live Search и т.п.

Для обеспечения минимальной задержки для пользователя необходимо либо поддерживать постоянное соединение (например, Adobe Flash, RTMP) или использовать технику HTTP long polling в сочетании с keep alive. Так или иначе на стороне сервера это приводит к появлению большого количества одновременных соединений (тысячи, десятки тысяч), по каждому из которых передается не такой большой объем данных. Эту ситуацию называют обычно проблемой C10k.

Continue reading…

Qik Push Engine API: приглашаем разработчиков

Posted by Андрей on Июль 12, 2009

qik_logo Qik — это сервис стриминга (вещания) и загрузки видео с мобильных телефонов. Загруженное видео можно посмотреть на сайте или на его специальной версии с мобильного телефона. Доступна интеграция с другими сервисами, такими как Twitter, Facebook и другие. Клиенты для практически всех современных моделей телефонов: iPhone, Windows Mobile, Symbian, Android, Blackberry и другие.

Qik Push Engine — это механизм, который позволяет получать мгновенные оповещения о новых/изменившихся Qik-видео. Например, можно посмотреть постоянно обновляющийся список live-видео, все видео из района Новопеределкино или все видео со словом «кошка». На основе Qik Push Engine API можно построить интересные приложения, интегрированные с Qik, или добавить функциональность в уже существующие. Можно написать собственную систему нотификации, desktop-widget или что-то еще.

Сегодня мы открываем API для работы c Qik Push Engine. Это первая ласточка в большом списке API, открывающих доступ к платформе стриминга Qik. Если вам интересно посмотреть Qik Push Engine в действии, заходите на одну из страниц примеров.

Continue reading…

AMQP по-русски 7

Posted by Андрей on Июнь 08, 2009

AMQP logo Сегодня довольно мало информации о протоколе AMQP (Advanced Message Queueing Protocol) и его применении, особенно русском языке. А вообще это — замечательный, уже достаточно широко поддерживаемый открытый протокол для передачи сообщений между компонентами системы с низкой задержкой и на высокой скорости. При этом семантика обмена сообщениями настраивается под нужды конкретного проекта. Такие решения существовали и ранее, но это первый стандарт, для которого существует большое количество свободных реализаций.

Основная идея состоит в том, что отдельные подсистемы (или независимые приложения) могут обмениваться произвольным образом сообщениями через AMQP-брокер, который осуществляет маршрутизацию, возможно гарантирует доставку, распределение потоков данных, подписку на нужные типы сообщений. В качестве классических примеров обычно приводятся финансовые приложения, связанные, например, с доставкой потребителям информации о курсах ценных бумаг в режиме реального времени, также возможно RPC-взаимодействие двух подсистем, которые не имеют связи друг с другом (взаимодействие через общий протокол AMQP) и так далее и тому подобное.

Сегодня тема доставки информации в реальном времени является крайне актуальной (достаточно вспомнить хотя бы Twitter, Google Wave). И здесь системы передачи сообщений могут служить внутренним механизмом обмена данными, который обеспечивает доставку данных (изменений данных) клиентам.

Я не ставлю своей целью сегодня рассказать о том, как писать приложения для AMQP. Хочу лишь немного рассказать о том, что это совсем не страшно, не очень сложно, и действительно работает, хотя стандарт находится еще в развитии, выходят новые версии протокола, брокеров и т.п. Но это уже вполне production-quality. Расскажу лишь базовые советы, чтобы помочь «въехать» в протокол.

Continue reading…

Deferred: все подробности 2

Posted by Андрей on Февраль 24, 2009

В предыдущей статье были описаны основные принципы работы Deferred и его применение в асинхронном программировании. Сегодня мы постараемся рассмотреть в деталях функционирование Deferred и примеры его использования.

Итак, Deferred — это отложенный результат, результат выполнения, который станет известен через некоторое время. Результатом, хранящимся в Deferred, может быть произвольное значение (успешное выполнение) или ошибка (исключение), которое произошло в процессе выполнения асинхронной операции. Раз нас интересует результат операции и мы получили от некоторой асинхронной функции Deferred, мы хотим выполнить действия в тот момент, когда результат выполнения будет известен. Поэтому Deferred кроме результата хранит еще цепочку обработчиков: обработчиков результатов (callback) и обработчиков ошибок (errback).

Рассмотрим поподробнее цепочку обработчиков:

Deferred

Continue reading…

Асинхронное программирование: концепция Deferred 8

Posted by Андрей on Февраль 10, 2009

Асинхронная концепция программирования заключается в том, что результат выполнения функции доступен не сразу же, а через некоторое время в виде некоторого асинхронного (нарушающего обычный порядок выполнения) вызова. Зачем такое может быть полезно? Рассмотрим несколько примеров.

Первый пример — сетевой сервер, веб-приложение. Чаще всего как таковых вычислений на процессоре такие приложения не выполняют. Большая часть времени (реального, не процессорного) тратится на ввод-вывод: чтение запроса от клиента, обращение к диску за данными, сетевые обращение к другим подсистемам (БД, кэширующие сервера, RPC и т.п.), запись ответа клиенту. Во время этих операций ввода-вывода процессор простаивает, его можно загрузить обработкой запросов других клиентов. Возможны различные способы решить эту задачу: отдельный процесс на каждое соединение (Apache mpm_prefork, PostgreSQL, PHP FastCGI), отдельный поток (нить) на каждое соединение или комбинированный вариант процесс/нить (Apache mpm_worker, MySQL). Подход с использованием процессов или нитей перекладывает мультиплексирование процессора между обрабатываемыми соединениями на ОС, при этом расходуется относительно много ресурсов (память, переключения контекста и т.п.), такой вариант не подходит для обработки большого количества одновременных соединений, но идеален для ситуации, когда объем вычислений достаточно высок (например, в СУБД). К плюсам модели нитей и процессов можно добавить потенциальное использование всех доступных процессоров в многопроцессорной архитектуре.

Альтернативой является использование однопоточной модели с использованием примитивов асинхронного ввода-вывода, предоставляемых ОС (select, poll, и т.п.). При этом объем ресурсов на каждое новое обслуживаемое соединение не такой большой (новый сокет, какие-то структуры в памяти приложения). Однако программирование существенно усложняется, т.к. данные из сетевых сокетов поступают некоторыми «отрывками», причем за один цикл обработки данные поступают от разных соединений, находящихся в разных состояниях, часть соединений могут быть входящими от клиентов, часть — исходящими к внешним ресурсам (БД, другой сервер и т.п.). Для упрощения разработки используются различные концепции: callback, конечные автоматы и другие. Примеры сетевых серверов, использующих асинхронный ввод-вывод: nginx, lighttpd, HAProxy, pgBouncer, и т.д. Именно при такой однопоточной модели возникает необходимость в асинхронном программировании. Например, мы хотим выполнить запрос в БД. С точки зрения программы выполнение запроса — это сетевой ввод-вывод: соединение с сервером, отправка запроса, ожидание ответа, чтение ответа сервера БД. Поэтому если мы вызываем функцию «выполнить запрос БД», то она сразу вернуть результат не сможет (иначе она должна была бы заблокироваться), а вернет лишь нечто, что позволит впоследствие получить результат запроса или, возможно, ошибку (нет соединения с сервером, некорректный запрос и т.п.) Этим возвращаемым значением удобно сделать именно Deferred.

Второй пример связан с разработкой обычных десктопных приложений. Предположим, мы решили сделать аналог Miranda (QIP, MDC, …), то есть свой мессенджер. В интерфейсе программы есть контакт-лист, где можно удалить контакт. Когда пользователь выбирает это действие, он ожидает что контакт исчезнет на экране и что он действительно удалится из контакт-листа. На самом деле операция удаления из серверного контакт-листа опирается на сетевое взаимодействие с сервером, при этом пользовательский интерфейс не должен быть заблокирован на время выполнения этой операции, поэтому в любом случае после выполнения операции потребуется некоторое асинхронное взаимодействие с результатом операции. Можно использовать механизм сигналов-слотов, callback’ов или что-то еще, но лучше всего подойдет Deferred: операция удаления из контакт-листа возвращает Deferred, в котором обратно придет либо положительный результат (всё хорошо), либо исключение (точная ошибка, которую надо сообщить пользователю): в случае ошибки контакт надо восстановить контакт в контакт-листе.

Примеры можно приводить долго и много, теперь о том, что же такое Deferred. Deferred — это сердце framework’а асинхронного сетевого программирования Twisted в Python. Это простая и стройная концепция, которая позволяет перевести синхронное программирование в асинхронный код, не изобретая велосипед для каждой ситуации и обеспечивая высокое качества кода. Deferred — это просто возвращаемый результат функции, когда этот результат неизвестен (не был получен, будет получен в другой нити и т.п.) Что мы можем сделать с Deferred? Мы можем «подвеситься» в цепочку обработчиков, которые будут вызваны, когда результат будет получен. При этом Deferred может нести не только положительный результат выполнения, но и исключения, сгенерированные функцией или обработчиками, есть возможность исключения обработать, перевыкинуть и т.д. Фактически, для синхронного кода есть более-менее однозначная параллель в терминах Deferred. Для эффективной разработки с Deferred оказываются полезными такие возможности языка программирования, как замыкания, лямбда-функци.

Continue reading…

Open Source: Deferred для qooxdoo

Posted by Андрей on Ноябрь 01, 2008

Мы представляем начало нашего маленького проекта по выкладыванию в open-source исходного кода наших проектов (полностью или частично). Первой ласточкой становится маленькая библиотека, предназначенная для работы с Deferred из Twisted Framework в qooxdoo на JavaScript.

Практически полностью код был взят из MochiKit.Async и адаптирован под qooxdoo. Полезные нововедения: если если в течение 1 секунды не будет обработана ошибка в Deferred (выполнение дойдет до конца цепочки callback, и останется ошибка), о ней будет сообщено на консоль, как о возможно необработанном исключении.

Если Вы еще не знаете, что такое Deferred, я бы рекомендовал обратиться к Twisted Handbook. Со своей стороны обещаю как можно скорее написать о Deferred по-русски.

Итак, страничка qx.Deferred.

Continue reading…

twisted.python.log и trial — веселимся вместе

Posted by Андрей on Октябрь 24, 2008

Следующий забавный случай взаимодействия частей Twisted Framework заставил меня потерять час времени, спешу рассказать, в надежде, что это спасет чьё-то время. Итак, в Twisted есть модуль логгинга, twisted.python.log, в котором есть удобный метод log.err(), который позволяет записать в лог информацию о текущем исключении. А trial — это framework для написания юнит-тестов из того же Twisted. Их сочетание иногда приводит к проблеме :)

Continue reading…