Download - PHP libevent Daemons. A high performance and reliable solution. Practical experience

Transcript
Page 1: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Демоны на PHP и libevent

как высокопроизводительное и надежное решение

Опыт практического применения

Международная конференция веб‑разработчиков

Page 2: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Кто мы такие?

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

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

Разработка браузерной MMORPG

http://chaosroad.ru/

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

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

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

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

Page 3: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

(mem)cached

Page 4: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

Page 5: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Демонизация. Что есть такое 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 Daemons. A high performance and reliable solution. Practical experience

Плюшками балуемся?

Page 7: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

// Создаем сокет - 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 Daemons. A high performance and reliable solution. Practical experience

Пишем демона — подключаем 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 Daemons. A high performance and reliable solution. Practical experience

Метод обработки

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 Daemons. A high performance and reliable solution. Practical experience

Метод чтения

$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 Daemons. A high performance and reliable solution. Practical experience

Легким движением руки, превращаем демона в ...

Page 12: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Таймеры

Стандартный таймер libevent'а УЖЕ работает :) (thx Tony2001)

• Но выход есть, даже в «плохом» раскладе!

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

– event_add ( resource $event, int $timeout )

Page 13: PHP libevent Daemons. A high performance and reliable solution. Practical experience

ДЕМОНстрация

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

Page 14: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

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

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

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

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

• Проблемы с отслеживанием сигналов (EV_SIGNAL) — УЖЕ решены (thx Tony2001)

• Дедлоки в случае общения между демонами

Page 15: PHP libevent Daemons. A high performance and reliable solution. Practical experience

DeadLock

Page 16: PHP libevent Daemons. A high performance and reliable solution. Practical experience

DeadLockПричины возникновения

Самое неприятное — столкнуться только под нагрузкой

Users Combats

Update User A

Create User A

Page 17: PHP libevent Daemons. A high performance and reliable solution. Practical experience

DeadLockМетоды борьбы

• Реорганизация приложения• Форк процессов

• Устранение асинхронности — введение блокировок

Page 18: PHP libevent Daemons. A high performance and reliable solution. Practical experience

DeadLockУстраняем асинхронность

Users CombatsLOCK

Create User A

Update User A

Page 19: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

Page 20: PHP libevent Daemons. A high performance and reliable solution. Practical experience

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

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

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

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

Page 21: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Результаты

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

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

памяти

• Память не «течет» (если того не захочет разработчик)

Page 22: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Советы

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

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

– Чужие данные

– Асинхронные режимы• Читайте исходники — в них много полезного• Если демон будет не один — напишите

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

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

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

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

Page 23: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Выводы

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

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

• Требует ОЧЕНЬ аккуратной работы

Page 24: PHP libevent Daemons. A high performance and reliable solution. Practical experience

Вопросы?

[email protected]: v.kruchkov

http://l-o-n-g.livejournal.com/