Upgrade to Pro — share decks privately, control downloads, hide ads and more …

«Боремся с shared-nothing моделью: PHP 7.4 prel...

Badoo Tech
September 21, 2019

«Боремся с shared-nothing моделью: PHP 7.4 preload, RoadRunner и другие» — Павел Мурзаков (Badoo)

Badoo PHP Meetup #3

Традиционное PHP-приложение (т.е. mod_php, php-fpm и т. п.) каждый раз исполняет весь код с нуля. Это значит, что весь bootstrap приложения происходит заново на каждый запрос: инициализация окружения, подключение необходимых файлов, сборка DI-контейнеров, загрузка конфигов и прочее. Всё это одинаково для каждого запроса, и могло быть сделано один раз, но PHP приходится постоянно повторять эти действия. Поэтому, даже если бизнес-логика достаточно оптимизирована, мы всё равно будем тратить ресурсы впустую на инициализацию.

В докладе поговорим, как можно решить или минимизировать эту проблему:

Разберёмся, на что именно тратятся ресурсы, посмотрим в perf и исходники PHP.
Поищем какие-то простые решения проблемы: как мы можем делать меньше инициализаций или сохранить данные между запросами.
Опробуем новые достижения PHP-сообщества — PHP 7.4 preload и RoadRunner — и сравним их.
Разберёмся, зачем нужен PHP 7.4 preload, если уже есть opcache, и как выжать из RoadRunner ещё больше.

Badoo Tech

September 21, 2019
Tweet

More Decks by Badoo Tech

Other Decks in Technology

Transcript

  1. 7M строк кода на PHP 600 cерверов с PHP-FPM 120K

    запросов в секунду в пиках 2
  2. • Не шарит состояние между PHP worker’ами • Не сохраняет

    состояние между запросами Классический PHP 9 Shared Nothing architecture PHP
  3. • Подключить файлы • Инициализировать фреймворк, библиотеки, etc • Запросить

    данные из внешних хранилищ Повторяющиеся действия 20 Shared Nothing architecture PHP
  4. Что делать? 21 • Shared memory, apcu, … • Хранение

    данных в IS_ARRAY_IMMUTABLE массивах • Батчинг/объединение запросов • Тюнить opcache • … Производительность PHP: планируем, профилируем, оптимизируем https://habr.com/ru/company/badoo/blog/430722/ Shared Nothing architecture PHP
  5. • Подключить файлы (opcache?) • Инициализировать фреймворк, библиотеки, etc •

    Запросить данные из внешних хранилищ Повторяющиеся действия 23 Preload (PHP 7.4) Проблема
  6. # perf record --call-graph dwarf,65528 -F 99 -p \ $(pgrep

    php-cgi | paste -sd "," -) -- sleep 20 # perf report 24
  7. 25

  8. “opcode caches … achieve significant performance boost by ALMOST completely

    eliminating the overhead of PHP code recompilation” https://wiki.php.net/rfc/preload
  9. • Symfony 4 подключает ~310 файлов • Зависимости Composer’а (особенно

    объявляющие функции) Производительность include 32 Preload (PHP 7.4) Проблема
  10. Бенчмарки 37 • Что: один endpoint продакшена Badoo (CPU-bound) •

    Как: preload’им все нужные файлы Preload (PHP 7.4) Решение
  11. Бенчмарки 38 • Что: один endpoint продакшена Badoo (CPU-bound) •

    Как: preload’им все нужные файлы • Чем: wrk2 Preload (PHP 7.4) Решение
  12. • PHP 7.2: 845 rps • PHP 7.4: 931 rps

    (+10%) 40 Бенчмарки — результаты Preload (PHP 7.4) Решение
  13. • PHP 7.2: 845 rps • PHP 7.4: 931 rps

    (+10%) • PHP 7.4 + preload: ??? rps 41 Бенчмарки — результаты Preload (PHP 7.4) Решение
  14. • PHP 7.2: 845 rps • PHP 7.4: 931 rps

    (+10%) • PHP 7.4 + preload: 1030 rps (+10% more) 42 Бенчмарки — результаты Preload (PHP 7.4) Решение
  15. 47 Резолв зависимостей Preload (PHP 7.4) Нюансы PHP Warning: Can't

    preload class MyTestClass with unresolved initializer for constant RAND in /local/mdk/code/preload- internal.php on line 5 PHP Warning: Can't preload unlinked class MyTestClass: Unknown parent AnotherClass in /local/mdk/code/preload-internal.php on line 5
  16. 50 opcache_compile_file VS include Preload (PHP 7.4) Нюансы • include/require

    • фактически исполняет код (в т.ч. вызывает автолоадер)
  17. 51 opcache_compile_file VS include Preload (PHP 7.4) Нюансы • include/require

    • фактически исполняет код (в т.ч. вызывает автолоадер) • удаляет константы/переменные по окончанию фазы preload Preload (PHP 7.4) Нюансы
  18. 52 opcache_compile_file VS include Preload (PHP 7.4) Нюансы • include/require

    • фактически исполняет код (в т.ч. вызывает автолоадер) • удаляет константы/переменные по окончанию фазы preload • в памяти остаются только функции/классы
  19. 53 opcache_compile_file VS include Preload (PHP 7.4) Нюансы • include/require

    • фактически исполняет код (в т.ч. вызывает автолоадер) • удаляет константы/переменные по окончанию фазы preload • в памяти остаются только функции/классы • opcache_compile_file() — просто компилирует
  20. 54 opcache_compile_file VS include Preload (PHP 7.4) Нюансы include: OK

    opcache_compile_file: PHP Warning: Can't preload class MyTestClass with unresolved initializer for constant RAND in /local/mdk/code/preload- internal.php on line 5
  21. 55 opcache_compile_file VS include Preload (PHP 7.4) Нюансы include: PHP

    Fatal error: Class 'NotPreloadedClass' not found in /local/ mdk/code/preload-internal.php on line 5 opcache_compile_file: PHP Warning: Can't preload unlinked class MyTestClass: Unknown parent AnotherClass in /local/mdk/code/preload- internal.php on line 5
  22. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require • Поля/константы класса: preload VS runtime 56 Preload (PHP 7.4) Нюансы
  23. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require • Константы класса preload VS runtime • Cannot redeclare … function 58 Preload (PHP 7.4) Нюансы
  24. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require • Константы класса preload VS runtime • Cannot redeclare … function • PHP 7.4 не production-ready (пока) 60 Preload (PHP 7.4) Нюансы
  25. • Подключить файлы • Инициализировать фреймворк, библиотеки, etc • Запросить

    данные из внешних хранилищ Повторяющиеся действия 65 RoadRunner
  26. Повторяющиеся действия 66 RoadRunner • Подключить файлы • Инициализировать фреймворк,

    библиотеки, etc • Запросить данные из внешних хранилищ
  27. • PHP 7.4 (FPM): 931 rps • PHP 7.4 (FPM)

    + preload: 1030 rps (+10%) 73 Бенчмарки — результаты RoadRunner
  28. • PHP 7.4 (FPM): 931 rps • PHP 7.4 (FPM)

    + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: ??? rps 74 Бенчмарки — результаты RoadRunner
  29. • PHP 7.4 (FPM): 931 rps • PHP 7.4 (FPM)

    + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: 987 rps (+6%) 75 Бенчмарки — результаты RoadRunner
  30. 76 Бенчмарки — результаты RoadRunner WAT ?! • PHP 7.4

    (FPM): 931 rps • PHP 7.4 (FPM) + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: 987 rps (+6%)
  31. 79 Бенчмарки — результаты RoadRunner • PHP 7.4 (FPM): 931

    rps • PHP 7.4 (FPM) + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: 987 rps (+6%) • PHP 7.4 RoadRunner + Opcache: 1049 rps (+12%)
  32. 88 Бенчмарки — результаты RoadRunner • PHP 7.4 (FPM): 931

    rps • PHP 7.4 (FPM) + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: 987 rps (+6%) • PHP 7.4 RoadRunner + Opcache: 1049 rps (+12%) • PHP 7.4 RoadRunner + Opcache + no PSR 7: 1089 rps (+17%)
  33. • Код становится сложнее, сложнее поддерживать, проще допускать ошибки •

    Чтобы выжать максимум, нужно писать код “под демон” изначально 91 RoadRunner Нюансы
  34. • Код становится сложнее, сложнее поддерживать, проще допускать ошибки •

    Чтобы выжать максимум нужно писать код “под демон” изначально • Тестировалось на наших кейсах, на одном запросе 92 RoadRunner Нюансы
  35. А почему не Swoole? А почему не amPHP? А почему

    не ReactPHP? А почему не $OtherAsyncPHP$?
  36. 1. Shared Nothing — благо 2. Shared Nothing можно оптимизировать

    3. PHP 7.4 с preload добавят производительность (с минимумом сложностей) 100
  37. 1. Shared Nothing — благо 2. Shared Nothing можно оптимизировать

    3. PHP 7.4 с preload добавят производительность (с минимумом сложностей) 4. RoadRunner сложнее, но ещё производительнее 101