Пора ли отправлять С на свалку истории?  Пишем демонов на 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,301 views
3,248 views

Published on

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

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,301
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
23
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Пора ли отправлять С на свалку истории? Пишем демонов на 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. Вопросы?

×