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

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

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. Павел Мурзаков · 21 сентября 2019 БОРЕМСЯ С SHARED-NOTHING МОДЕЛЬЮ

    PHP PHP 7.4 preload, RoadRunner и другие
  2. 7M строк кода на PHP 600 cерверов с PHP-FPM 120K

    запросов в секунду в пиках 2
  3. 3 (среднее RPS на одном из датацентров)

  4. План 4

  5. 1. Shared Nothing architecture PHP 5

  6. 1. Shared Nothing architecture PHP 2. Preload (PHP 7.4) 6

  7. 1. Shared Nothing architecture PHP 2. Preload (PHP 7.4) 3.

    RoadRunner 7
  8. Shared Nothing architecture PHP 8

  9. • Не шарит состояние между PHP worker’ами • Не сохраняет

    состояние между запросами Классический PHP 9 Shared Nothing architecture PHP
  10. Shared Nothing architecture PHP 10 Типичный PHP-скрипт

  11. 11 Init Payload Shared Nothing architecture PHP Типичный PHP-скрипт

  12. 12 Daemonized script Shared Nothing architecture PHP

  13. 13 Daemonized script Init Request Loop Shared Nothing architecture PHP

  14. 14 Daemonized script Init Request Loop Shared Nothing architecture PHP

  15. 15 Daemonized script Init Request Loop Shared Nothing architecture PHP

  16. • Проще писать код, сложнее допускать ошибки Pros/Cons of shared

    nothing 16 Shared Nothing architecture PHP
  17. • Проще писать код, сложнее допускать ошибки • Ниже производительность

    17 Shared Nothing architecture PHP Pros/Cons of shared nothing
  18. • Подключить файлы Повторяющиеся действия 18 Shared Nothing architecture PHP

  19. • Подключить файлы • Инициализировать фреймворк, библиотеки, etc Повторяющиеся действия

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

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

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

  23. • Подключить файлы (opcache?) • Инициализировать фреймворк, библиотеки, etc •

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

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

  26. 26 Производительность include Preload (PHP 7.4) Проблема

  27. ext/opcache/zend_accelerator_util_funcs.c — zend_accel_load_script() 27 Производительность include Preload (PHP 7.4) Проблема

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

    eliminating the overhead of PHP code recompilation” https://wiki.php.net/rfc/preload
  29. “This proposal is about the “ALMOST”, mentioned above” https://wiki.php.net/rfc/preload

  30. 30 Производительность include Preload (PHP 7.4) Проблема

  31. • Symfony 4 подключает ~310 файлов Производительность include 31 Preload

    (PHP 7.4) Проблема
  32. • Symfony 4 подключает ~310 файлов • Зависимости Composer’а (особенно

    объявляющие функции) Производительность include 32 Preload (PHP 7.4) Проблема
  33. 33 Решение при помощи preload

  34. php.ini: opcache.preload = /path/to/script.php (выполняется один раз при старте PHP-FPM)

    34 Preload (PHP 7.4) Решение
  35. • opcache_compile_file() • include/require Что прелоадится 35 Preload (PHP 7.4)

    Решение
  36. Бенчмарки 36 • Что: один endpoint продакшена Badoo (CPU-bound) Preload

    (PHP 7.4) Решение
  37. Бенчмарки 37 • Что: один endpoint продакшена Badoo (CPU-bound) •

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

    Как: preload’им все нужные файлы • Чем: wrk2 Preload (PHP 7.4) Решение
  39. • PHP 7.2: 845 rps 39 Бенчмарки — результаты Preload

    (PHP 7.4) Решение
  40. • PHP 7.2: 845 rps • PHP 7.4: 931 rps

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

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

    (+10%) • PHP 7.4 + preload: 1030 rps (+10% more) 42 Бенчмарки — результаты Preload (PHP 7.4) Решение
  43. 43 Нюансы

  44. • Изменение кода = перезапуск(reload) php-fpm/apache 44 Нюансы Preload (PHP

    7.4)
  45. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    45 Preload (PHP 7.4) Нюансы
  46. 46 Резолв зависимостей Preload (PHP 7.4) Нюансы

  47. 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
  48. 48 Резолв зависимостей Preload (PHP 7.4) Нюансы opcache_get_status()

  49. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require 49 Preload (PHP 7.4) Нюансы
  50. 50 opcache_compile_file VS include Preload (PHP 7.4) Нюансы • include/require

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

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

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

    • фактически исполняет код (в т.ч. вызывает автолоадер) • удаляет константы/переменные по окончанию фазы preload • в памяти остаются только функции/классы • opcache_compile_file() — просто компилирует
  54. 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
  55. 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
  56. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require • Поля/константы класса: preload VS runtime 56 Preload (PHP 7.4) Нюансы
  57. 57 Поля/константы класса Preload (PHP 7.4) Нюансы Preload Script

  58. • Изменение кода = перезапуск(reload) php-fpm/apache • Зависимости обязательно разрезолвлены

    • opcache_compile_file() VS include/require • Константы класса preload VS runtime • Cannot redeclare … function 58 Preload (PHP 7.4) Нюансы
  59. 59 Cannot redeclare function Preload (PHP 7.4) Нюансы

  60. • Изменение кода = перезапуск(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) Нюансы
  61. Preload (PHP 7.4) Нюансы

  62. RoadRunner 62

  63. 63 RoadRunner Master Daemon (Go) PHP Worker PHP Worker PHP

    Worker
  64. 64 RoadRunner Hello world example

  65. • Подключить файлы • Инициализировать фреймворк, библиотеки, etc • Запросить

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

    библиотеки, etc • Запросить данные из внешних хранилищ
  67. 67 RoadRunner Hello world example

  68. 68 RoadRunner Hello world example — errors

  69. 69 RoadRunner Hello world example — stdout

  70. 70 RoadRunner Hello world example — context

  71. 71 RoadRunner Hello world example — flush

  72. 72 Бенчмарки

  73. • PHP 7.4 (FPM): 931 rps • PHP 7.4 (FPM)

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

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

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

    (FPM): 931 rps • PHP 7.4 (FPM) + preload: 1030 rps (+10%) • PHP 7.4 RoadRunner: 987 rps (+6%)
  77. 77 Perf RoadRunner

  78. 78 Opcache RoadRunner

  79. 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%)
  80. 80 phpspy - flamegraph RoadRunner

  81. 81 RoadRunner phpspy - flamegraph

  82. 82 RoadRunner \Spiral\RoadRunner\PSR7Client::acceptRequest() phpspy - flamegraph

  83. 83 RoadRunner \Spiral\RoadRunner\PSR7Client::acceptRequest() phpspy - flamegraph

  84. 84 acceptRequest() RoadRunner

  85. 85 acceptRequest() RoadRunner

  86. 86 Патчим RoadRunner

  87. 87 Патчим RoadRunner

  88. 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%)
  89. 89 Нюансы

  90. • Код становится сложнее, сложнее поддерживать, проще допускать ошибки 90

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

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

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

  94. А почему не Swoole? А почему не amPHP?

  95. А почему не Swoole? А почему не amPHP? А почему

    не ReactPHP?
  96. А почему не Swoole? А почему не amPHP? А почему

    не ReactPHP? А почему не $OtherAsyncPHP$?
  97. Выводы 97

  98. 1. Shared Nothing — благо 98

  99. 1. Shared Nothing — благо 2. Shared Nothing можно оптимизировать

    99
  100. 1. Shared Nothing — благо 2. Shared Nothing можно оптимизировать

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

    3. PHP 7.4 с preload добавят производительность (с минимумом сложностей) 4. RoadRunner сложнее, но ещё производительнее 101
  102. bit.ly/phpinit tech.badoo.com СПАСИБО!