Slide 1

Slide 1 text

Павел Мурзаков · 21 сентября 2019 БОРЕМСЯ С SHARED-NOTHING МОДЕЛЬЮ PHP PHP 7.4 preload, RoadRunner и другие

Slide 2

Slide 2 text

7M строк кода на PHP 600 cерверов с PHP-FPM 120K запросов в секунду в пиках 2

Slide 3

Slide 3 text

3 (среднее RPS на одном из датацентров)

Slide 4

Slide 4 text

План 4

Slide 5

Slide 5 text

1. Shared Nothing architecture PHP 5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Shared Nothing architecture PHP 8

Slide 9

Slide 9 text

• Не шарит состояние между PHP worker’ами • Не сохраняет состояние между запросами Классический PHP 9 Shared Nothing architecture PHP

Slide 10

Slide 10 text

Shared Nothing architecture PHP 10 Типичный PHP-скрипт

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

12 Daemonized script Shared Nothing architecture PHP

Slide 13

Slide 13 text

13 Daemonized script Init Request Loop Shared Nothing architecture PHP

Slide 14

Slide 14 text

14 Daemonized script Init Request Loop Shared Nothing architecture PHP

Slide 15

Slide 15 text

15 Daemonized script Init Request Loop Shared Nothing architecture PHP

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

• Подключить файлы Повторяющиеся действия 18 Shared Nothing architecture PHP

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Preload (PHP 7.4) 22

Slide 23

Slide 23 text

• Подключить файлы (opcache?) • Инициализировать фреймворк, библиотеки, etc • Запросить данные из внешних хранилищ Повторяющиеся действия 23 Preload (PHP 7.4) Проблема

Slide 24

Slide 24 text

# perf record --call-graph dwarf,65528 -F 99 -p \ $(pgrep php-cgi | paste -sd "," -) -- sleep 20 # perf report 24

Slide 25

Slide 25 text

25

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

“opcode caches … achieve significant performance boost by ALMOST completely eliminating the overhead of PHP code recompilation” https://wiki.php.net/rfc/preload

Slide 29

Slide 29 text

“This proposal is about the “ALMOST”, mentioned above” https://wiki.php.net/rfc/preload

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

• Symfony 4 подключает ~310 файлов • Зависимости Composer’а (особенно объявляющие функции) Производительность include 32 Preload (PHP 7.4) Проблема

Slide 33

Slide 33 text

33 Решение при помощи preload

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

• PHP 7.2: 845 rps 39 Бенчмарки — результаты Preload (PHP 7.4) Решение

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

43 Нюансы

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

57 Поля/константы класса Preload (PHP 7.4) Нюансы Preload Script

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

59 Cannot redeclare function Preload (PHP 7.4) Нюансы

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Preload (PHP 7.4) Нюансы

Slide 62

Slide 62 text

RoadRunner 62

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

64 RoadRunner Hello world example

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

67 RoadRunner Hello world example

Slide 68

Slide 68 text

68 RoadRunner Hello world example — errors

Slide 69

Slide 69 text

69 RoadRunner Hello world example — stdout

Slide 70

Slide 70 text

70 RoadRunner Hello world example — context

Slide 71

Slide 71 text

71 RoadRunner Hello world example — flush

Slide 72

Slide 72 text

72 Бенчмарки

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

77 Perf RoadRunner

Slide 78

Slide 78 text

78 Opcache RoadRunner

Slide 79

Slide 79 text

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%)

Slide 80

Slide 80 text

80 phpspy - flamegraph RoadRunner

Slide 81

Slide 81 text

81 RoadRunner phpspy - flamegraph

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

84 acceptRequest() RoadRunner

Slide 85

Slide 85 text

85 acceptRequest() RoadRunner

Slide 86

Slide 86 text

86 Патчим RoadRunner

Slide 87

Slide 87 text

87 Патчим RoadRunner

Slide 88

Slide 88 text

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%)

Slide 89

Slide 89 text

89 Нюансы

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

А почему не Swoole?

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

А почему не Swoole? А почему не amPHP? А почему не ReactPHP? А почему не $OtherAsyncPHP$?

Slide 97

Slide 97 text

Выводы 97

Slide 98

Slide 98 text

1. Shared Nothing — благо 98

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

bit.ly/phpinit tech.badoo.com СПАСИБО!