Пора ли отправлять С на свалку истории? Пишем демонов...

23
Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Upload: vadim-kruchkov

Post on 08-May-2015

3.146 views

Category:

Documents


0 download

DESCRIPTION

Вадим Крючков [Long], руководитель группы разработки, компания Agunga Считается (в общем случае — вполне справедливо), что писать демонов на PHP — моветон. Использовать для прототипирования интерфейсов взаимодействия — можно, а вот в продакшене ни-ни. Именно с таким представлением мы начинали разработку новой версии игры — проработаем интерфейсы взаимодействия с демоном, который к запуску будет переписан на высокопроизводительном С. Однако, первые тесты демона, написанного на PHP с использованием libevent, заставили нас серьезно задуматься — а нужен ли нам переход на С? Какую производительность нам удалось достичь? Течет ли память? Обо всем этом будет рассказано в докладе. А так же - особенности использования и недокументированные возможности расширения, облегчающие рутинные операции

TRANSCRIPT

Page 1: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Пора ли отправлять С на свалку истории?

Пишем демонов на PHP с использованием расширения

libevent

Page 2: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Кто мы такие?

• Вадим Крючков [Long], руководитель группы разработки

• Андрей Голубев [440hz], ведущий разработчик• Евгений Прудников, ведущий разработчик

Page 3: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Обычная архитектура

(mem)cached

Page 4: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Наша архитектура — включаем демоны

Page 5: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Демонизация. Что есть такое libevent?

• Предоставляет простой механизм для запуска callback функций, при наступлении определенного события на дескрипторе:

– READ

– WRITE

– TIMEOUT

– SIGNAL• http://www.monkey.org/~provos/libevent/• http://ru.php.net/manual/en/intro.libevent.php

Page 6: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Пишем демона

Page 7: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Пишем демона, работающего с сокетом

// Создаем сокет - event вешается на дескриптор

$rSocket = stream_socket_server (

'tcp://127.0.0.1:666',

$errno, $errstr,

STREAM_SERVER_BIND | STREAM_SERVER_LISTEN );

// далем его не блокирующим, что бы позволить принимать другие коннекты

stream_set_blocking ( $rSocket, 0 );

Page 8: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Пишем демона — подключаем libevent

// создаем событийную базу

$rBaseEvent = event_base_new ( );

// создаем новое событие для сокета

$rSocketEvent = event_new ( );

/**

* ловим события "чтение" и после операции чтения возвращаем событие в базу

* EV_READ - чтение

* EV_PERSIST - вернуть событие в базу после выполнения

*/

event_set ( $rSocketEvent, $rSocket, EV_READ | EV_PERSIST, 'onAcceptEvent' );

// устанавливаем событие в базу событий

event_base_set ( $rSocketEvent, $rBaseEvent );

// запускаем отслеживание

event_add ( $rSocketEvent );

// запускаем цикл

event_base_loop ( $rBaseEvent );

Page 9: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Метод обработкиfunction onAcceptEvent ( $rSocket, $rEvent, $args ) {

global $rBaseEvent; // удобнее сделать через объект ;)

static $iConnect = 0; // идентификатор конекта

$iConnect++;

// Примем коннект

$rConnection = stream_socket_accept ( $rSocket );

// далем коннект не блокирующим, что бы позволить принимать еще коннекты

stream_set_blocking ( $rConnection, 0 );

// создадим буфер обмена данными

$buf = event_buffer_new ( $iConnect, 'onReadEvent', 'onWriteEvent', 'onFailureEvent', $iConnect);

// подключаем буфер к базе событий

event_buffer_base_set ( $buf, $rBaseEvent );

// включаем буфер на события и возвращаем события назад после выполнения

event_buffer_enable ( $buf, EV_READ | EV_WRITE | EV_PERSIST );

}

Page 10: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Метод чтения$iBufferReadLenght = 1024; // размер буфера чтения

function onReadEvent($rStream, $args) {

global $iBufferReadLenght;

$tmp = '';

do {

$tmp .= event_buffer_read ( $hBuffer, $this->iBufferReadLenght );

if( $iBufferReadLenght > strlen($tmp) ) {

break;

}

} while ( true );

return $tmp;

}

Page 11: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Превращаем демона в ...

или не документированные возможности

Page 12: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Таймеры (thnx 440hz)

• Стандартный таймер libevent'а не работает :(

• Выход есть!

– событие можно повесить на «любой» дескриптор

– event_add ( resource $event, int $timeout )

Page 13: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Таймеры - решение

• tmpfile() - открываем новый временный файл

• «вешаем» на этот дескриптор отложенное событие

event_set(

$rTimers,

$rTtmpFile,

0,

'onTimer',

);

Page 14: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Демонстрация

http://cyberdot.ru/src/socket.phps

Page 15: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Подводные камни

• Очень мало информации и примеров

• Следить за ресурсами, не забываем их освобождать

• Хитрости при чтении данных, превышающих размер буфера

• Входных данных — много и они бывают «чужие» :)

• Проблемы с отслеживанием сигналов (EV_SIGNAL)

Page 16: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Даем нагрузку

Page 17: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Тестирование ботами

Имитируем … пользователей в on-line:

• Воспользовались API• Написали приложение,

генерирующее ботов

Page 18: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Результаты

Сервер Xeon 8х2.66GHz, RAM 8Gb:

• Около 2.5 тысяч запросов в секунду (не Hello, World)• На 1 пользователя в online расходуется около 1Мб

памяти • Приложение (пока) не подвергалось жесткой

оптимизации

Page 19: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Результаты

Сервер Xeon 8х2.66GHz, RAM 8Gb:

• Около 2.5 тысяч запросов в секунду (не Hello, World)• На 1 пользователя в online расходуется около 1Мб

памяти • Приложение (пока) не подвергалось жесткой

оптимизации• Память не «течет» (1 месяц публичного бета-теста не

выявили)

Page 20: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Советы

• Научитесь «мыслить параллельно»

– Процесс не завершается

– Чужие данные• Читайте исходники — в них много

полезного• Если демон будет не один — напишите

простенький фреймворк• Документируйте код + протокол

взаимодействия• Напишите хороший логгер - без него

отлаживать приложение будет сложно

– Сделайте несколько уровней логгирования

Page 21: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Выводы

Выводы пока делать рано

:)

Page 22: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Выводы (серьезно)

• Можно рекомендовать к использованию на продакшене

• Позволяет держать хорошие нагрузки (при этом оставляя LA в разумных пределах )

• Реальные тесты — придется подождать :(

Page 23: Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent

Вопросы?