php libevent daemons. a high performance and reliable solution. practical experience

24
Демоны на PHP и libevent как высокопроизводительное и надежное решение Опыт практического применения Международная конференция веб‑разработчиков

Upload: arvids-godjuks

Post on 19-Jun-2015

3.337 views

Category:

Technology


2 download

DESCRIPTION

It is considered (rigthly in most cases) that it's a bad manner to implement a daemon using PHP. It's OK for prototyping but no-no for production. That were our thoughts when we've started to implement a new version of browser game. It was planned to describe an interface to communicate with daemon that will be then rewritten in pure C. However, fist libevent PHP daemon performance tests forced us to think if we really need to rewrite it in C. What was the performance? Are there memory leaks? All these will be covered in the speech. You will also learn about problems, features and how a real project results.

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/