На данной странице будут собраны тесты скорости продукта и различных функций. Зачёркнутыми являются функции от которых решено было отказаться. Красными - над которыми ведется работа по ускорению.
Железо:
CPU 2 ядра (2300 Mhz на ядро)
4Gb Ram
php 8.1
SSD
Использование системных ресурсов от 11.2022
Процессор от 2 Ядер (чем больше тем быстрее смогут работать параллельно работающие программные сервера и производиться расчеты системой ):
Нагрузка в покое CPU ~ 0,05% (load average 1, 5 и 15 минут): 0.07, 0.02, 0.01
RAM (оперативная память) от 4ГБ, нужна в целом для работы служб “железа” , сам программный сервер потребляет доп мощности по следующей формуле:
1 Мб на запуска 1 экземпляра программного сервера ( 1 карта = 1 сервер )
~ 1 Мб данных на загрузку информации о где на карте ходить можно, где препятствия
+ ~ 0.005 Мб на каждого монстра, объект, игрока (в зависимости насколько много данных из базы будет браться)
Анализ минимальной скорости интернета, нагрузка 100 блуждающих объектов (постоянный поток пакетов с координатами) от 11.2022
При скорости интернета 0.22 Мбит/Сек при одновременной действии 100 мобов (игроков) на карте игровой пакеты будут отправляться и приходить в клиент игры и игра будет с начальными признаками freez’ов (критический порог когда она начнет тормозить) тк Ping (разница между отправкой пакета и получением назад данных) составляет 0.2 секунды (игра НЕ тормозит в 90% времени за счет технологий интерполяции позволяющая игрокам с медленным интернетом побыстрее выполнять действия в игре уравновешивая ситуацию)
Системные тесты
Результаты замеров скорости различных технологий на сервере указаны как количество запросов в секунду (RPS)
Redis
get set 13 000 (используется асинхронный запрос на получение в работе сервера)
pub sub 40 000 (в рамках работы сервера ничего не пишется, только на других сервисах)
ZeroMQ
pub sub 300 000 (в асинхронном, неблокируемом режиме)
Shmop (раздельная память данных между процессами)
get 700 000
Libevent
остановка основного кода, вызов функций по таймеру, продолжение основного кода. работает на базе ticks в php добавляя некую асинхронность
300 000 вызовов
Swoole
...
Opcache (кэшируемые данные в opcode)
get 50 000 000
- 30% скорости загрузки библиотек фреймворка при запуске процесса (в CLI не сильно актуально)
Обычная переменная
get 70 000 000
Semaphores / System V (раздельная память с неблокируемым и блокируемым доступом)
pub sub 30 000 (ограничение по длине 16 000 байт)
get с блокировками 40 000
get без блокировки 2 000 000
Workerman Websocket server
обработка запросов в секунду чисто сервером 1 700 000+ (согласно публичным тестам, на сервере разработки еще не проверялось )
Workerman http server
обработка запросов в секунду чисто сервером ~2 000 000 (согласно публичным тестам, на сервере разработки еще не проверялось ) с пропускной способностью канала превышающее это значение (так что она не является ограничивающим фактором)
PHP FPM
400 000 (при условии что настройки fpm max_children установлено в достаточном количестве и ядер процессора достаточно для поднятия соединений в нормальном режиме скорости и ни один потомок не ждет освобождения пула)
минимальное потребление CPU на процесс поднятый 0.7%
Стандартные функции php
exec 30мс/вызов
pcntl_fork 1.2мс/вызов (только для поднятия сервера)
работы с mysql через php запись ~8мс (скачкообразно)
работа с mysql через php на запись асинхронно 1мс на непостоянных TCP (рассмотреть библиотеку Parallel , замерить скорости на отправку сообщений или использовать асинхронный TCP постоянного соединения)
Ниже среднее количество вызовов указанных функций в секунду (красным выделены текущие проблемные места):
microtime(true) 20 000 000
date("Y-m-d") 2 000 000
date("Y-m-d H:i:s") 1 000 000
localtime() 1 800 000
getdate() 1 100 000
(new \DateTime())->format("Y-m-d H:i:s:v") 700 000
memory_get_usage() 70 000 000
asort 200 записей 100 000
get_object_vars 20 свойств 5 000 000
file_get_contents (он же fopen+fread ) 40 000
file_exists() 250 000
class_exists() 10 000 000 , на несуществующий (полагаю проверяется наличие функций autoload ) 7 000 000
method_exists 20 000 000 на несуществующий (полагаю проверяется наличие в объекте метода __call) 11 000 000
$reflectionMethod = new ReflectionMethod(object $object, 'method_name') 8 000 000
$reflectionMethod->invoke() 10 000 000 (x4 быстрее если бы метод вызвался напрямую)
(new ReflectionMethod(...)) -> getParameters 40 000 000 (0 аргументов), далее: 10 000 000 (1 аргумент), 7 000 000 (2 аргумента) и тп (в среднем на 1 аргумент падение скорости на 30% , +-5%)
new \ArrayIterator(...) - 500 000
implements \Iterator + его методы 1.000.000
array_intersect_key 5 000 000 (4 значения)
array_merge 5 000 000 (4 значения)
array_column 10.000.000 (1 значение, на 35% падение скорости за каждое доп значение)
восстановление Объекта из строки new A( ... explode(',', $a)) 3 800 000
SeasLog::log 80 000 vs file_put_contents (..., date("Y-m-d H:i:s").'|'.getmypid().' ....') 5000 vs fopen('..', 'a') + fwrite 80 000(используется для логов. принято решение писать логи через множественные TCP соединения асинхронно но с потерей порядка записи)
Тесты песочниц (обработчик кода добавляемый в админ панели пользователями)
Lua Sandbox (движок для компилируемого языка LUA)
call (closure отдает фиксированную строку ) 70 000 (8 ядер + физ сервер дает x10 к скорости)
call (closure отдает вызов PHP функции сервера с параметрами созданной с помощью registerLibrary число параметров значимо не влияет на скорость) 60 000 (8 ядер + физ сервер дает x10 к скорости)
callFunction (аналог call но взывает не closure, a именованную глобальную функцию lua) - аналогично параметрам выше
Заметки:
данной технологии PHP и LUA не имеют общего хранилища и все данные передаются в виде сообщений двусторонних не передавая ссылки (поэтому напрямую объект не передать, свойства не получить).
Передавая объект из PHP в LUA приходится прибегать к registerLibrary (заранее создавать доступные в LUA функции из PHP) и мета таблицам (аналог объектов) при смене или получения значения которых вызвать указанные функции
В боевых условиях (кеш, синхронизация данных всех песочниц и тп) простое игровое событие (регенерация) занимает 0.17мс (6000 запросов в секунду где идет вызов LUA и 2 раза обращение в PHP)
V8js (движок для языка JavaScript)
Выполнение компиляции происходит на лету (для примера, использование не рационально):
executeString (отдает фиксированную строку ) 140 000 (8 ядер + физ сервер дает x4.5 к скорости)
executeString (отдает получение свойств объекта переданного из PHP) 80 000 (8 ядер + физ сервер дает x5 к скорости)
executeString (отдает выполнение метода объекта переданного из PHP) 40 000 (8 ядер + физ сервер дает x5 к скорости)
execiteString возвращающий анонимную функцию (closure) и вызываемый как метод PHP полученного объекта на 20% быстрее (за счет того что executeString вызван единожды)
Тоже что и выше но код JS запроса заранее компилируется и его можно использовать повторно:
executeScript (отдает фиксированную строку) 600 000 (8 ядер + физ сервер дает x3.5 к скорости)
executeScript (отдает получение свойств объекта переданного из PHP) 300 000 (8 ядер дают x4 прибавку к скорости)
executeScript (отдает выполнение метода объекта переданного из PHP) 60 000 (8 ядер + физ сервер дает x5 к скорости)
executeScript возвращающий анонимную функцию (closure) на 30% медленнее (в зависимости что возвращает, полагаю особенность компиляции closure)
передача параметров из PHP 700 000 / свойство (8 ядер дают лишь x2.5 прибавку к скорости)
Заметки:
Добавлять новые значения из PHP в V8js - медленно, для экономии времени добавление новых данных можно передать в пространство V8js объект один раз (тк он передастся по ссылке) , а в нем самом уже из PHP менять свойства (это создаст некое хранилище посредник) но свойства должны быть обязательно статичными в этом объекте
В данной технологии PHP и V8js делят некое общее хранилище памяти однако в отличие от LUA объект передается по ссылке и сразу доступен.
Вывод:
В настоящее время javaScript более популярен за счет игрового движка Phaser2D (33.000 лайков), в то время как для разработки игр где игровые механики (есть движки где LUA используется в незначительной степени для описания действий в игре) написаны на LUA используется Love (3.000 лайков). Lua имеет явный недостаток - это то что для получения свойств объекта PHP нужно вызвать некие функции (как если бы мы взвали методы объектов), но это можно решить кешируя в самом LUA значения , при изменении LUA - менять кеш, при изменении в PHP или JS - отправлять команду на изменение кеша (тк по большей части будет чтение это будет выигрышным выходом). На более мощном железе явный рывок в скорости
В Javascript на рынке много библиотек для работы с физикой, графикой, есть общая память и получение свойств объектов отрабатывает быстро без нужды что либо кешировать (хотя и это тоже можно сделать по примеру LUA). Однако вызов методов объектов PHP явно проигрывает по скорости LUA на хорошем железе, но такие методы вызываются реже (например 1 раз в 200мс) чем читаются (сотни раз в 1мс) и меняются свойства (например раз в кадр 60мс). Пример методов: добавления на карту новых объектов, добавление объекты новых событий, сохранение игрока в базу.
В LUA можно сделать некий кеш который кеширует все свойство не тратя время на обращение в PHP для их чтения, однако это сопряжено с тем что при смене свойств в JS или PHP мы должны обновлять их в LUA однако все эти изменения не обязательно обновлять как только они появились , а отправлять пакетом при следующем запуске LUA
В таких языках как С++ язык LUA встраиваемый (как в нашем сервисе) и старые игры в тч и онлайн до сих пор используют LUA для написания часто меняющейся игровой логики (игровые мероприятия, диалоги, квесты)
Сравнительные тесты CORE (ядра) фреймворка от 02.2021
Результат нагрузочного тестирования HTTP запросами, указан в в миллисекундах (1 секунда = 1000 миллисекунд).
На Данном примере видно что помимо нагрузки на сервер имеет место тот факт что Laravel и Symfony не успевают освобождать FPM Child (стандартные php fpm с max_children = 5) и создается очередь ожидания освобождения процесса FPM .
Тем самым даже при увеличении числа max_children до достаточного что бы обработать все запросы параллельно скорость выполнения каждого будет равна параметру "min" в табличке ниже на сервере где производилось тестирование. На более мощных серверах и при использовании кэш показатели Symfony и Laravel можно улучшить в Х10 , но не стоит забывать что и показатели фреймворка "Моя Фантазия" вырастут пропорционально. Скорость Symfony и Laravel обусловлена большим количеством библиотек и overhead на роутинг http запросов
Однако скорость обработки запросов в секунду ограничена скоростью HTTP соединений (который работает на базе TCP) и работой самого PHP FPM . Выбрав медленное из них из данных выше можно сделать вывод что 2 миллисекунды (0.002 секунды) на сервере тестирования занимала скорость поднятия такого соединения и она не будет меньше на нем (те чистый результат работы PHP составляя min - 2 )
Создание онлайн сервера для мобильных многопользовательских, realtime 2D игр (жанра RPG и стратегии) с API на PHP ч. 6
Правительство РФ анонсировало выделение до $50 млрд для выхода РФ в топ-20 стран—разработчиков Игр к 2030 году. Возможно в скором времени разрабатываемый мной сервис наконец увидит свет.
В этой статье я расскажу как сделать архитектуру приложения игрового сервера быстрой и что использует Unity. Эта статья результаты исследований предыдущих так что в ней будет много ссылок на них.
Создание онлайн сервера для мобильных многопользовательских, realtime 2D игр (жанра RPG и стратегии) с API на PHP ч. 5
Продолжая серию статей про разработку сервера для онлайн игр (адрес проекта http://my-fantasy.ru) на языке PHP в это части я хочу рассказать про безопасное добавления пользовательского кода для добавления функционала игровых механик. В статье я опишу существующие решения для PHP , сравню скорость работы приведу видео примеры.
Создание онлайн сервера для мобильных многопользовательских, realtime 2D игр (жанра RPG и стратегии) с API на PHP ч. 4
В предыдущей статья я рассказал о протоколах клиент-серверного взаимодействия и о нагрузке которую может выдержать TCP соединения. В этой статье мы рассмотрим технологию для хранения , записи и публикации данных клиентам - Redis , разберем сколько игроков и NPC мы можем держать с демонстрацией игры, затронем архитектурные решения других игр
Создание онлайн сервера для мобильных многопользовательских, realtime 2D игр (жанра RPG и стратегии) с API на PHP ч. 3
В 3й части статей я расскажу простым языком про протоколы передачи данных, как они работают и что такое Websocket сервер и какие есть решения для его создания на PHP
Создание онлайн сервера для мобильных многопользовательских, realtime 2D игр (жанра RPG и стратегии) с API на PHP ч. 1
Привет, Хабр! Мой первый пост и я хочу поделиться с вами своей идеей создание сервиса предоставляющего разработчикам игр и студиям платформу для создания онлайн игр! Поехали!