Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Пора ли отправлять С на свалку истории?  Пишем демонов на PHP с использованием расширения libevent
Кто мы такие? <ul><li>Вадим Крючков [Long], руководитель группы разработки </li></ul><ul><li>Андрей Голубев [440hz], ведущ...
Обычная архитектура (mem)cached
Наша архитектура — включаем демоны
Демонизация. Что есть такое  libevent? <ul><li>Предоставляет простой механизм для запуска callback функций, при наступлени...
Пишем демона
Пишем демона, работающего с сокетом <ul><li>// Создаем сокет - event вешается на дескриптор </li></ul><ul><li>$rSocket  = ...
Пишем демона — подключаем libevent <ul><li>// создаем событийную базу </li></ul><ul><li>$rBaseEvent  = event_base_new ( );...
Метод обработки <ul><li>function  onAcceptEvent (  $rSocket ,  $rEvent ,  $args  ) { </li></ul><ul><li>global  $rBaseEvent...
Метод чтения <ul><li>$iBufferReadLenght  =  1024 ;  // размер буфера чтения </li></ul><ul><li>function  onReadEvent( $rStr...
Превращаем демона в ... или не документированные возможности
Таймеры (thnx 440hz) <ul><li>Стандартный таймер libevent'а не работает :( </li></ul><ul><li>Выход есть! </li></ul><ul><ul>...
Таймеры - решение <ul><li>tmpfile() - открываем новый временный файл </li></ul><ul><li>«вешаем» на этот дескриптор отложен...
Демонстрация http://cyberdot.ru/src/socket.phps
Подводные камни <ul><li>Очень мало информации и примеров </li></ul><ul><li>Следить за ресурсами, не забываем их освобождат...
Даем нагрузку
Тестирование ботами <ul><li>Имитируем … пользователей в on-line: </li></ul><ul><li>Воспользовались API </li></ul><ul><li>Н...
Результаты <ul><li>Сервер Xeon 8х2.66GHz, RAM 8Gb: </li></ul><ul><li>Около 2.5 тысяч запросов в секунду (не Hello, World) ...
Результаты <ul><li>Сервер Xeon 8х2.66GHz, RAM 8Gb: </li></ul><ul><li>Около 2.5 тысяч запросов в секунду (не Hello, World) ...
Советы <ul><li>Научитесь «мыслить параллельно» </li></ul><ul><ul><li>Процесс не завершается </li></ul></ul><ul><ul><li>Чуж...
Выводы <ul><li>Выводы пока делать рано </li></ul><ul><li>:) </li></ul>
Выводы (серьезно) <ul><li>Можно рекомендовать к использованию на продакшене </li></ul><ul><li>Позволяет держать хорошие на...
Вопросы?
Upcoming SlideShare
Loading in …5
×

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

3,443 views

Published on

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

  • Be the first to comment

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

  1. 1. Пора ли отправлять С на свалку истории? Пишем демонов на PHP с использованием расширения libevent
  2. 2. Кто мы такие? <ul><li>Вадим Крючков [Long], руководитель группы разработки </li></ul><ul><li>Андрей Голубев [440hz], ведущий разработчик </li></ul><ul><li>Евгений Прудников, ведущий разработчик </li></ul>
  3. 3. Обычная архитектура (mem)cached
  4. 4. Наша архитектура — включаем демоны
  5. 5. Демонизация. Что есть такое libevent? <ul><li>Предоставляет простой механизм для запуска callback функций, при наступлении определенного события на дескрипторе: </li></ul><ul><ul><li>READ </li></ul></ul><ul><ul><li>WRITE </li></ul></ul><ul><ul><li>TIMEOUT </li></ul></ul><ul><ul><li>SIGNAL </li></ul></ul><ul><li>http://www.monkey.org/~provos/libevent/ </li></ul><ul><li>http://ru.php.net/manual/en/intro.libevent.php </li></ul>
  6. 6. Пишем демона
  7. 7. Пишем демона, работающего с сокетом <ul><li>// Создаем сокет - event вешается на дескриптор </li></ul><ul><li>$rSocket = stream_socket_server ( </li></ul><ul><li>'tcp://127.0.0.1:666' , </li></ul><ul><li>$errno , $errstr , </li></ul><ul><li>STREAM_SERVER_BIND | STREAM_SERVER_LISTEN ); </li></ul><ul><li>// далем его не блокирующим, что бы позволить принимать другие коннекты </li></ul><ul><li>stream_set_blocking ( $rSocket , 0 ); </li></ul>
  8. 8. Пишем демона — подключаем libevent <ul><li>// создаем событийную базу </li></ul><ul><li>$rBaseEvent = event_base_new ( ); </li></ul><ul><li>// создаем новое событие для сокета </li></ul><ul><li>$rSocketEvent = event_new ( ); </li></ul><ul><li>/** </li></ul><ul><li>* ловим события &quot;чтение&quot; и после операции чтения возвращаем событие в базу </li></ul><ul><li>* EV_READ - чтение </li></ul><ul><li>* EV_PERSIST - вернуть событие в базу после выполнения </li></ul><ul><li>*/ </li></ul><ul><li>event_set ( $rSocketEvent , $rSocket , EV_READ | EV_PERSIST, 'onAcceptEvent' ); </li></ul><ul><li>// устанавливаем событие в базу событий </li></ul><ul><li>event_base_set ( $rSocketEvent , $rBaseEvent ); </li></ul><ul><li>// запускаем отслеживание </li></ul><ul><li>event_add ( $rSocketEvent ); </li></ul><ul><li>// запускаем цикл </li></ul><ul><li>event_base_loop ( $rBaseEvent ); </li></ul>
  9. 9. Метод обработки <ul><li>function onAcceptEvent ( $rSocket , $rEvent , $args ) { </li></ul><ul><li>global $rBaseEvent ; // удобнее сделать через объект ;) </li></ul><ul><li>static $iConnect = 0 ; // идентификатор конекта </li></ul><ul><li>$iConnect ++; </li></ul><ul><li>// Примем коннект </li></ul><ul><li>$rConnection = stream_socket_accept ( $rSocket ); </li></ul><ul><li>// далем коннект не блокирующим, что бы позволить принимать еще коннекты </li></ul><ul><li>stream_set_blocking ( $rConnection , 0 ); </li></ul><ul><li>// создадим буфер обмена данными </li></ul><ul><li>$buf = event_buffer_new ( $iConnect , 'onReadEvent' , 'onWriteEvent' , 'onFailureEvent' , $iConnect ); </li></ul><ul><li>// подключаем буфер к базе событий </li></ul><ul><li>event_buffer_base_set ( $buf , $rBaseEvent ); </li></ul><ul><li>// включаем буфер на события и возвращаем события назад после выполнения </li></ul><ul><li>event_buffer_enable ( $buf , EV_READ | EV_WRITE | EV_PERSIST ); </li></ul><ul><li>} </li></ul>
  10. 10. Метод чтения <ul><li>$iBufferReadLenght = 1024 ; // размер буфера чтения </li></ul><ul><li>function onReadEvent( $rStream , $args ) { </li></ul><ul><li>global $iBufferReadLenght ; </li></ul><ul><li>$tmp = '' ; </li></ul><ul><li>do { </li></ul><ul><li>$tmp .= event_buffer_read ( $hBuffer , $this ->iBufferReadLenght ); </li></ul><ul><li>if ( $iBufferReadLenght > strlen( $tmp ) ) { </li></ul><ul><li>break ; </li></ul><ul><li>} </li></ul><ul><li>} while ( true ); </li></ul><ul><li>return $tmp ; </li></ul><ul><li>} </li></ul>
  11. 11. Превращаем демона в ... или не документированные возможности
  12. 12. Таймеры (thnx 440hz) <ul><li>Стандартный таймер libevent'а не работает :( </li></ul><ul><li>Выход есть! </li></ul><ul><ul><li>событие можно повесить на «любой» дескриптор </li></ul></ul><ul><ul><li>event_add ( resource $event, int $timeout ) </li></ul></ul>
  13. 13. Таймеры - решение <ul><li>tmpfile() - открываем новый временный файл </li></ul><ul><li>«вешаем» на этот дескриптор отложенное событие </li></ul>event_set( $rTimers , $rTtmpFile , 0 , 'onTimer' , ) ;
  14. 14. Демонстрация http://cyberdot.ru/src/socket.phps
  15. 15. Подводные камни <ul><li>Очень мало информации и примеров </li></ul><ul><li>Следить за ресурсами, не забываем их освобождать </li></ul><ul><li>Хитрости при чтении данных, превышающих размер буфера </li></ul><ul><li>Входных данных — много и они бывают «чужие» :) </li></ul><ul><li>Проблемы с отслеживанием сигналов (EV_SIGNAL) </li></ul>
  16. 16. Даем нагрузку
  17. 17. Тестирование ботами <ul><li>Имитируем … пользователей в on-line: </li></ul><ul><li>Воспользовались API </li></ul><ul><li>Написали приложение, генерирующее ботов </li></ul>
  18. 18. Результаты <ul><li>Сервер Xeon 8х2.66GHz, RAM 8Gb: </li></ul><ul><li>Около 2.5 тысяч запросов в секунду (не Hello, World) </li></ul><ul><li>На 1 пользователя в online расходуется около 1Мб памяти </li></ul><ul><li>Приложение (пока) не подвергалось жесткой оптимизации </li></ul>
  19. 19. Результаты <ul><li>Сервер Xeon 8х2.66GHz, RAM 8Gb: </li></ul><ul><li>Около 2.5 тысяч запросов в секунду (не Hello, World) </li></ul><ul><li>На 1 пользователя в online расходуется около 1Мб памяти </li></ul><ul><li>Приложение (пока) не подвергалось жесткой оптимизации </li></ul><ul><li>Память не «течет» (1 месяц публичного бета-теста не выявили) </li></ul>
  20. 20. Советы <ul><li>Научитесь «мыслить параллельно» </li></ul><ul><ul><li>Процесс не завершается </li></ul></ul><ul><ul><li>Чужие данные </li></ul></ul><ul><li>Читайте исходники — в них много полезного </li></ul><ul><li>Если демон будет не один — напишите простенький фреймворк </li></ul><ul><li>Документируйте код + протокол взаимодействия </li></ul><ul><li>Напишите хороший логгер - без него отлаживать приложение будет сложно </li></ul><ul><ul><li>Сделайте несколько уровней логгирования </li></ul></ul>
  21. 21. Выводы <ul><li>Выводы пока делать рано </li></ul><ul><li>:) </li></ul>
  22. 22. Выводы (серьезно) <ul><li>Можно рекомендовать к использованию на продакшене </li></ul><ul><li>Позволяет держать хорошие нагрузки (при этом оставляя LA в разумных пределах ) </li></ul><ul><li>Реальные тесты — придется подождать :( </li></ul>
  23. 23. Вопросы?

×