php apcu что это
Php apcu что это
Хотя настроек APCu по умолчанию вполне достаточно для большинства задач, но для серьёзных проектов необходимо внимательно изучить следующие настройки.
Имя | По умолчанию | Место изменения | Список изменений |
---|---|---|---|
apc.enabled | «1» | PHP_INI_SYSTEM | |
apc.shm_segments | «1» | PHP_INI_SYSTEM | |
apc.shm_size | «32M» | PHP_INI_SYSTEM | |
apc.entries_hint | «4096» | PHP_INI_SYSTEM | |
apc.ttl | «0» | PHP_INI_SYSTEM | |
apc.gc_ttl | «3600» | PHP_INI_SYSTEM | |
apc.mmap_file_mask | NULL | PHP_INI_SYSTEM | |
apc.slam_defense | «1» | PHP_INI_SYSTEM | |
apc.enable_cli | «0» | PHP_INI_SYSTEM | |
apc.use_request_time | «0» | PHP_INI_ALL | До APCu 5.1.19 значение по умолчанию было «1». |
apc.serializer | «php» | PHP_INI_SYSTEM | До APCu 5.1.19 значение по умолчанию было «default». |
apc.coredump_unmap | «0» | PHP_INI_SYSTEM | |
apc.preload_path | NULL | PHP_INI_SYSTEM |
Для подробного описания констант PHP_INI_*, обратитесь к разделу Где могут быть установлены параметры конфигурации.
Краткое разъяснение конфигурационных директив.
Количество сегментов разделяемой памяти выделенной под кеш. Если APC использовал всю доступную разделяемую память, а apc.shm_size таким большим, как позволяет система, увеличение этого параметра может помочь.
Размер сегмента разделяемой памяти, заданный в короткой нотации (смотрите этот FAQ). По умолчанию, некоторые системы (включая большинство вариантов BSD) ограничивают это значение крайне малым значением.
Это подсказка о количестве уникальных пользовательских переменных, которые надо кешировать. Установите равным нулю или вообще не указывайте, если не уверены.
Количество секунд, которые запись может лежать в кеше без обращения к ней, прежде чем будет разрешено её заменить на другую. Установка этого параметра равного нулю может привести к тому, что все место будет забито и новые записи не смогут попасть в кеш. В этом случае, если параметр равен 0, кеш будет полностью очищен. Если же ttl будет больше нуля, то APCu постарается очистить устаревшие записи.
Количество секунд, которые запись может находиться в списке сборщика мусора. Это значение обеспечивает безотказность в случае падения сервера в момент исполнения закешированного файла. Если исполняемый файл был изменён, память, выделенная под кеширование его старой версии, не будет возвращена до истечения этого времени. Установка в ноль отключает этот функционал.
Больше для тестирования и отладки. Эта настройка включает APCu для CLI версии PHP. При обычной работе, запускать APCu, который будет создавать, наполнять и уничтожать кеш при каждом запуске сценария в консоли, будет далеко не лучшей идеей. Но в целях тестирования и отладки, можно легко включить APCu для CLI.
Указывает APC использовать сторонний сериализатор.
Разрешает APC перехватывать сигналы, такие как SIGSEGV, который записывает coredump, когда подан. Когда эти сигналы будут получены, APC попытается освободить всю разделяемую память, чтобы не включать её в coredump. Эта настройка может увеличить стабильность системы, когда критический сигнал был получен, а APC сконфигурирован на использование большого объёма памяти.
Эта возможность потенциально опасна. Освобождение сегментов разделяемой памяти при получении критического сигнала может привести к непредсказуемому поведению.
Хотя некоторые ядра предоставляют возможность игнорировать некоторые сегменты разделяемой памяти при записи core-файла, эти реализации могут также игнорировать важные сегменты памяти, такие как Apache scoreboard.
Опционально. Задаёт путь, который используется APC для загрузки кешированных данных во время запуска.
Ускоряем PHP-проект с помощью кэширования
В статье будут рассмотрены рекомендации стандарта PSR и реализация кэш-сервисов в соответствии с этими стандартами, а также различные программные решения, кластеризация кэша и рекомендации по использованию.
Скачок роста проекта и нагрузки на него могут стать настоящим испытанием для разработчика. Веб-сайт начинает отвечать с большой задержкой, и всё важнее становится вопрос масштабирования. Существует множество эффективных решений для повышения устойчивости проекта к нагрузке и скорости его работы, и один из самых базовых — кэширование.
Кэширование — это сохранение данных в высоко доступных местах на временной основе для того, чтобы их можно было получать быстрее, чем из оригинального источника. Самый распространенный пример применения кэша — получение данных из базы. При первом получении, допустим, продукта из базы данных, он сохраняется в кэш на определённое время, поэтому каждый следующий запрос к этому продукту уже не будет тревожить БД: данные будут получены из другого хранилища.
Какие бывают подходы?
Существует множество подходов к кэшированию. Список совместимых с PHP инструментов можно посмотреть на странице PHP-cache. Самые распространенные из них:
Давайте разберемся, какие особенности есть у каждого из них и чем они отличаются друг от друга.
Один из самых распространённых и простых в настройке инструментов кэширования, сохраняет нужные нам данные в оперативную память. (Ещё умеет кэшировать промежуточный код, но это уже совсем другая история) Чтобы начать работу с APCu, необходимо убедиться, что он установлен. Для этого в командной строке запустите следующую команду:
Другой способ проверки: создайте файл index.php и поместите в него вызов функции phpinfo(). Убедитесь, что у вас настроен веб-сервер для используемой директории и откройте скрипт в браузере через адрес сервера. Нас интересует секция APCu: если внутри неё есть пункт APCu Support: Enabled, значит всё хорошо, мы можем идти дальше.
Если APCu у вас не установлен, сделать это можно следующим способом:
3. Откройте в любом текстовом редакторе файл конфигурации php.ini и убедитесь в наличии следующих строк:
Для использования этого подхода кэширования нам понадобятся основные функции. Вот пример их применения:
Важно! Этот подход работает только при работе в режиме веб-сайта, то есть при запуске из командной строки вы не будете получать данные из кэша, а всё, что вы в него сохранили, будет очищено по завершению работы скрипта. Однако это не вызовет никаких ошибок.
Array-кэш
Более простой, но не всегда применимый метод кэширования. Если APCu сохраняет данные и делает их доступными для последующих выполнений всеми процессами, то Array-кэш хранит их только в рамках обрабатываемого запроса.
Что это значит? Представим, что у вас есть страница с комментариями пользователей. Один пользователь может оставить несколько сообщений, и когда мы будем собирать массив этих данных, нам не захочется несколько раз ходить в базу данных за одним и тем же пользователем. Что мы можем сделать, так это сохранить полученные данные в массив, чтобы при его наличии не делать повторный запрос. Этот принцип очень прост и так же просто реализуется. Давайте напишем класс, который будет выполнять подобное сохранение:
Из-за своей ограниченности этот подход применяется редко, однако знать о нём полезно.
Memcached и Redis
Наиболее продвинутые подходы кэширования. Подразумевают наличие запущенного отдельно сервера Memcached или Redis. Из PHP мы подключаемся к этому серверу по адресу и порту. Конфигурация этих решений сложнее, чем настройка APCu, но метод хранения данных очень похож: оперативная память. Самыми главными их преимуществами являются
В этой статье мы не будем вдаваться в подробности настройки Memcached и Redis. На этом этапе нам важно помнить, что, если нагрузка очень высокая, нам следует смотреть в сторону именно этих решений, так как они имеют хороший потенциал к масштабированию.
Стандарт PSR-16
В PSR есть два стандарта, посвящённых кэшированию: PSR-6 (обычный интерфейс кэширования) и PSR-16 (простой интерфейс кэширования) — мы сосредоточимся на PSR-16.
Этот стандарт предлагает специальный интерфейс (CacheInterface), которому могут удовлетворять классы, выполняющие функцию кэширования. Согласно ему, такие классы должны реализовывать следующие методы:
Как вы можете заметить, интерфейс очень прост, и даже тех функций, что мы рассмотрели в примере с APCu, достаточно для того, чтобы написать свой сервис кэша в соответствии с PSR-16. Но зачем это нужно?
Главные преимущества соблюдения стандартов PSR заключаются в том, что
Давайте подробнее рассмотрим последний пункт и его преимущества.
Подключение PSR-16 библиотек
Библиотеки, создающие «обертку» над существующими инструментами кэширования для соответствия интерфейсу называются адаптерами. Для примера, рассмотрим адаптеры тех методов, что мы уже обсудили:
Все они удовлетворяют PSR-16 и поэтому применяются одинаково, однако логика «под капотом» у каждого своя.
Для примера давайте загрузим APCu- и Array-адаптеры в наш проект с помощью Composer.
Давайте представим, что у нас есть специальный класс для получения продуктов из базы данных. Назовем его ProductRepository, у него есть метод find($id), который возвращает продукт по его идентификатору, а если такого продукта нет — null.
Если мы хотим подключить кэширование, мы не должны делать это внутри репозитория, потому что его ответственность — возвращать данные из базы данных. Куда же мы тогда добавим кэш? Есть несколько популярных решений, самое простое — дополнительный класс-провайдер. Всё, что он будет делать — пробовать получить данные из кэша, а если это не получится — обратится в репозиторий. Для этого в конструкторе такого класса определим две зависимости — наш репозиторий и CacheInterface. Почему именно интерфейс? Потому что так мы сможем использовать абсолютно любой из упомянутых адаптеров или других классов, удовлетворяющих PSR-16.
Наш класс готов. Теперь давайте рассмотрим его применение в сочетании с APCu-адаптером.
Если же мы захотим, заменить APCu-кэширование на Array-адаптер или любой другой, мы просто передадим новый подход в провайдер вместо старого, потому что все они реализуют CacheInterface.
Состояние гонки и обновление данных
Кэш работает до тех пор, пока мы содержим его в актуальном состоянии. Это значит, что, если пользователь хочет обновить продукт, то продукт должен обновиться и в базе данных, и в нашем кэше. Однако здесь есть один важный нюанс.
Представим, что нашим проектом пользуется очень большое количество пользователей, и двое из них одновременно обновляют одну и ту же сущность. В этом случае, может возникнуть такая ситуация:
Такая ситуация называется состоянием гонки, когда несколько процессов обращаются одновременно к одному и тому же ресурсу, и может возникнуть конфликт версий. Чтобы избежать такой проблемы, следует придерживаться одного простого правила:
Когда вы получаете любую сущность в коде с целью её обновления, всегда используйте данные из БД.
В любой ситуации, когда нам нужно получить продукт и мы не собираемся его обновлять — используем кэш. Если же мы хотим его обновить — обращаемся к данным из БД.
Вы можете либо обращаться в нужных местах к ProductRepository вместо ProductDataProvider, либо добавить аргумент к методу DataProvider. Например, такой ($fromCache):
Заключение
Кэширование требует от разработчика дополнительных усилий при разработке проекта, и его применение не всегда может быть целесообразно. Решение применять его или нет должно быть основано на предполагаемой (или фактической) нагрузке и ваших ожиданиях от скорости отклика пользователю.
Однако вне зависимости от того, будете ли вы применять эти подходы в ваших текущих проектах или нет, стоит изучить их и применить на практике, потому что этот навык обязательно пригодится вам в работе в крупных командах.
Подводя итог, повторим ключевые идеи статьи:
В статье будут рассмотрены рекомендации стандарта PSR и реализация кэш-сервисов в соответствии с этими стандартами, а также различные программные решения, кластеризация кэша и рекомендации по использованию.
Скачок роста проекта и нагрузки на него могут стать настоящим испытанием для разработчика. Веб-сайт начинает отвечать с большой задержкой, и всё важнее становится вопрос масштабирования. Существует множество эффективных решений для повышения устойчивости проекта к нагрузке и скорости его работы, и один из самых базовых — кэширование.
Кэширование — это сохранение данных в высоко доступных местах на временной основе для того, чтобы их можно было получать быстрее, чем из оригинального источника. Самый распространенный пример применения кэша — получение данных из базы. При первом получении, допустим, продукта из базы данных, он сохраняется в кэш на определённое время, поэтому каждый следующий запрос к этому продукту уже не будет тревожить БД: данные будут получены из другого хранилища.
Какие бывают подходы?
Существует множество подходов к кэшированию. Список совместимых с PHP инструментов можно посмотреть на странице PHP-cache. Самые распространенные из них:
Давайте разберемся, какие особенности есть у каждого из них и чем они отличаются друг от друга.
Один из самых распространённых и простых в настройке инструментов кэширования, сохраняет нужные нам данные в оперативную память. (Ещё умеет кэшировать промежуточный код, но это уже совсем другая история) Чтобы начать работу с APCu, необходимо убедиться, что он установлен. Для этого в командной строке запустите следующую команду:
Другой способ проверки: создайте файл index.php и поместите в него вызов функции phpinfo(). Убедитесь, что у вас настроен веб-сервер для используемой директории и откройте скрипт в браузере через адрес сервера. Нас интересует секция APCu: если внутри неё есть пункт APCu Support: Enabled, значит всё хорошо, мы можем идти дальше.
Если APCu у вас не установлен, сделать это можно следующим способом:
3. Откройте в любом текстовом редакторе файл конфигурации php.ini и убедитесь в наличии следующих строк:
Для использования этого подхода кэширования нам понадобятся основные функции. Вот пример их применения:
Важно! Этот подход работает только при работе в режиме веб-сайта, то есть при запуске из командной строки вы не будете получать данные из кэша, а всё, что вы в него сохранили, будет очищено по завершению работы скрипта. Однако это не вызовет никаких ошибок.
Array-кэш
Более простой, но не всегда применимый метод кэширования. Если APCu сохраняет данные и делает их доступными для последующих выполнений всеми процессами, то Array-кэш хранит их только в рамках обрабатываемого запроса.
Что это значит? Представим, что у вас есть страница с комментариями пользователей. Один пользователь может оставить несколько сообщений, и когда мы будем собирать массив этих данных, нам не захочется несколько раз ходить в базу данных за одним и тем же пользователем. Что мы можем сделать, так это сохранить полученные данные в массив, чтобы при его наличии не делать повторный запрос. Этот принцип очень прост и так же просто реализуется. Давайте напишем класс, который будет выполнять подобное сохранение:
Из-за своей ограниченности этот подход применяется редко, однако знать о нём полезно.
Memcached и Redis
Наиболее продвинутые подходы кэширования. Подразумевают наличие запущенного отдельно сервера Memcached или Redis. Из PHP мы подключаемся к этому серверу по адресу и порту. Конфигурация этих решений сложнее, чем настройка APCu, но метод хранения данных очень похож: оперативная память. Самыми главными их преимуществами являются
В этой статье мы не будем вдаваться в подробности настройки Memcached и Redis. На этом этапе нам важно помнить, что, если нагрузка очень высокая, нам следует смотреть в сторону именно этих решений, так как они имеют хороший потенциал к масштабированию.
Стандарт PSR-16
В PSR есть два стандарта, посвящённых кэшированию: PSR-6 (обычный интерфейс кэширования) и PSR-16 (простой интерфейс кэширования) — мы сосредоточимся на PSR-16.
Этот стандарт предлагает специальный интерфейс (CacheInterface), которому могут удовлетворять классы, выполняющие функцию кэширования. Согласно ему, такие классы должны реализовывать следующие методы:
Как вы можете заметить, интерфейс очень прост, и даже тех функций, что мы рассмотрели в примере с APCu, достаточно для того, чтобы написать свой сервис кэша в соответствии с PSR-16. Но зачем это нужно?
Главные преимущества соблюдения стандартов PSR заключаются в том, что
Давайте подробнее рассмотрим последний пункт и его преимущества.
Подключение PSR-16 библиотек
Библиотеки, создающие «обертку» над существующими инструментами кэширования для соответствия интерфейсу называются адаптерами. Для примера, рассмотрим адаптеры тех методов, что мы уже обсудили:
Все они удовлетворяют PSR-16 и поэтому применяются одинаково, однако логика «под капотом» у каждого своя.
Для примера давайте загрузим APCu- и Array-адаптеры в наш проект с помощью Composer.
Давайте представим, что у нас есть специальный класс для получения продуктов из базы данных. Назовем его ProductRepository, у него есть метод find($id), который возвращает продукт по его идентификатору, а если такого продукта нет — null.
Если мы хотим подключить кэширование, мы не должны делать это внутри репозитория, потому что его ответственность — возвращать данные из базы данных. Куда же мы тогда добавим кэш? Есть несколько популярных решений, самое простое — дополнительный класс-провайдер. Всё, что он будет делать — пробовать получить данные из кэша, а если это не получится — обратится в репозиторий. Для этого в конструкторе такого класса определим две зависимости — наш репозиторий и CacheInterface. Почему именно интерфейс? Потому что так мы сможем использовать абсолютно любой из упомянутых адаптеров или других классов, удовлетворяющих PSR-16.
Наш класс готов. Теперь давайте рассмотрим его применение в сочетании с APCu-адаптером.
Если же мы захотим, заменить APCu-кэширование на Array-адаптер или любой другой, мы просто передадим новый подход в провайдер вместо старого, потому что все они реализуют CacheInterface.
Состояние гонки и обновление данных
Кэш работает до тех пор, пока мы содержим его в актуальном состоянии. Это значит, что, если пользователь хочет обновить продукт, то продукт должен обновиться и в базе данных, и в нашем кэше. Однако здесь есть один важный нюанс.
Представим, что нашим проектом пользуется очень большое количество пользователей, и двое из них одновременно обновляют одну и ту же сущность. В этом случае, может возникнуть такая ситуация:
Такая ситуация называется состоянием гонки, когда несколько процессов обращаются одновременно к одному и тому же ресурсу, и может возникнуть конфликт версий. Чтобы избежать такой проблемы, следует придерживаться одного простого правила:
Когда вы получаете любую сущность в коде с целью её обновления, всегда используйте данные из БД.
В любой ситуации, когда нам нужно получить продукт и мы не собираемся его обновлять — используем кэш. Если же мы хотим его обновить — обращаемся к данным из БД.
Вы можете либо обращаться в нужных местах к ProductRepository вместо ProductDataProvider, либо добавить аргумент к методу DataProvider. Например, такой ($fromCache):
Заключение
Кэширование требует от разработчика дополнительных усилий при разработке проекта, и его применение не всегда может быть целесообразно. Решение применять его или нет должно быть основано на предполагаемой (или фактической) нагрузке и ваших ожиданиях от скорости отклика пользователю.
Однако вне зависимости от того, будете ли вы применять эти подходы в ваших текущих проектах или нет, стоит изучить их и применить на практике, потому что этот навык обязательно пригодится вам в работе в крупных командах.
Подводя итог, повторим ключевые идеи статьи:
PHP жив. PHP 7 на практике
Недавно PHP-проекты Avito перешли на версию PHP 7.1. По этому случаю мы решили вспомнить, как происходил переход на PHP 7.0 у нас и наших коллег из OLX. Дела давно минувших дней, но остались красивые графики, которые хочется показать миру.
Первая часть рассказа основана на статье PHP’s not dead! PHP7 in practice, которую написал наш коллега из OLX Łukasz Szymański (Лукаш Шиманьски): переход OLX на PHP 7. Во второй части — опыт перехода Avito на PHP 7.0 и PHP 7.1: процесс, трудности, результаты с графиками.
Часть 1. PHP 7 в OLX
Компания OLX Europe управляет десятью сайтами, самый большой из которых — OLX.pl. Все наши сайты должны работать максимально эффективно, поэтому миграция на PHP 7 стала для нас основным приоритетом.
В этом посте расскажем, с какими проблемами пришлось столкнуться и чего удалось получить с переходом на PHP 7. Про переход было рассказано на конференции PHPers Summit 2016.
Переход
Вопреки нашим опасениям, миграция прошла гладко. За исключением стандартного списка необходимых изменений из официальной документации, пришлось внести лишь некоторые правки, связанные с нашей архитектурой.
Стоит упомянуть, что десять наших сайтов работают в разных странах. И изменения мы выкатываем последовательно: на один сайт за другим. Такой подход особенно важно применять при серьёзных изменениях.
Мы начали обновление версии с самого маленького сайта и переходили ко всё более крупным, поглядывая, чтобы тесты проходили успешно. Это позволило следить за возникновением неожиданных проблем и снизило потенциальный ущерб.
Memcache
Отказ от поддержки Memcache в PHP 7 подтолкнул нас к переходу на Memcached. Пришлось поддержать две версии сайта: PHP 5 + Memcache и PHP 7 + Memcached.
Для решения задачи использовали простенькую обёртку. Она выбирает подходящий PHP-модуль для соединения с кэшом, исходя из информации о сервере, на котором выполняется код.
Однако, приключения с Memcached на этом не закончились. Выяснилось, что объекты, сериализованные с помощью Memcache, не могут быть десериализованы с помощью Memcached.
Но кэш — он на то и кэш, что его можно легко удалить. Поэтому мы просто удалили старые проблемные объекты из кэша, и они были пересозданы с помощью нового модуля.
APC, APCu и OPCache
Немного о терминах.
APC (Alternative PHP Cache) — это кэш байт-кода и пользовательских данных.
APCu (APC User Cache) — только кэш пользовательских данных.
OPCache — только кэш байт-кода.
В PHP 7 нет APC, нам пришлось взять и APCu, и OPCache. Ранее мы использовали API APC во многих критичных частях нашего фреймворка, управляющего кэшем, поэтому мы прикрутили к APCu модуль apcu-bc, совместимый с API APC.
Результаты
Ниже представлены результаты самого большого из наших сайтов, OLX.pl.
CPU на Apache
Наши веб-серверы (Apache) крутятся на 20 физических машинах с 32 ядрами процессора каждая. Пиковое потребление процессора в результате миграции снизилось с 50% до 20%.
LA на Apache
Подобным образом снизился и Load Average на веб-серверах.
Числа говорят сами за себя: снижение нагрузки, экономия ресурсов, повышение эффективности. Если ваши проект-менеджеры или клиенты не дают достаточно времени на миграцию — эти графики наверняка смогут их убедить.
Причины эффективности PHP 7
Таких поразительных результатов удалось добиться благодаря оптимизации в трёх основных областях.
Меньше операций выделения памяти
PHP 5 расходовал 20% потребляемого им процессорного времени только на операции выделения памяти. Разработчики языка обратили на это внимание, уменьшили количество операций выделения памяти, чем значительно снизили потребление процессора.
Меньше потребление памяти
Этот набросок показывает путь, который процессору нужно пройти для доступа к оперативной памяти (RAM), с указанием времени на каждый шаг. Как видно, отрезок до оперативной памяти — самый длинный. Разработчики PHP снизили потребление памяти, ускорив отклик приложений.
Меньше промежуточных указателей
Последняя причина улучшения эффективности PHP 7 — уменьшение числа промежуточных указателей. Для этого разработчики PHP избавились от множества указателей, ссылающихся на другие указатели; вместо этого они заставили указатели ссылаться непосредственно на запрашиваемые сущности.
Помимо улучшения эффективности, PHP 7 припас небольшую революцию структуры кода.
Скаляры в объявлении функции
До PHP 7 типами аргументов функции могли выступать только объект, интерфейс, массив или функция обратного вызова (callable). Возьмём для примера следующий код.
Очевидно, что использование таких методов сулит множество проблем, если вы не уверены в корректности входящих аргументов.
Помимо добавления проверок типов в каждый метод, можно использовать конструкт ValueObject из предметно-ориентированного программирования (DDD).
PHP 7 позволяет просто указать скаляры, такие как string, int, float, bool. Кроме того, можно указать тип возвращаемого значения.
Strict-режим
Но простое добавление вышеуказанных конструкций в код может не дать ожидаемых результатов. Всё потому, что PHP 7 по умолчанию работает в coercive-режиме, в котором происходят обычные преобразования типов. Если вы принудительно не включили strict-режим, можно переписать вышеуказанный метод следующим образом.
К сожалению, даже добавление конструкции declare(strict_types=1) в файл PHPisNotDead.php не включает strict-режим. Объяснение в примере ниже. В комментариях указаны возвращаемые значения.
Почему так происходит? Строгая типизация в методах класса PHPisNotDead включилась только для возвращаемых значений.
Если вам нужно включить строгую типизацию также и для аргументов, придётся добавить декларацию strict_types и во все файлы, в которых вызываются методы класса.
Больше информации об указании типов и его влиянии на выполнение программы можно прочитать в документации. Чтение этой документации убережёт от сюрпризов при выполнении вашего кода.
Будущее
Если даже сейчас вы всё ещё не решились перейти на PHP 7, загляните в список поддерживаемых версий PHP. Версия 5.6 уже не получает активной поддержки, а в конце 2018 года перестанут выходить даже исправления критических уязвимостей. Активная поддержка продолжается для версий 7.0 и выше.
Следите за новостями мира PHP и планами относительно новых верий. Наиболее интересные посты: дружественные классы, generic-типы и функции. Найти другие предложения о развитии языка можно в PHP RFC.
Итоги
PHP 7 впечатляет: помимо повышения эффективности, он помогает разработчикам писать более качественный код. Я набросал небольшое пособие, которое поможет вам принять решение о переходе.
— Когда стоит перейти на PHP 7?
— Прямо сейчас.
Часть 2. PHP 7 в Avito
Процесс перехода на PHP 7.0
Мы так же, как и OLX, осуществляли перевод наших сервисов на PHP 7 постепенно. Сначала перевели небольшие отдельностоящие сервисы, протестировали их, исправили возникшие ошибки. Далее перешли к последовательному обновлению серверов админки сайта, после чего раскатывали на PHP 7 оставшиеся сервисы и сайт.
Трудности перехода
Мы прочитали список обратно несовместимых изменений. Однако это не уберегло ото всех бед.
В старом коде нашёлся класс с названием String. PHP 7 выдал ошибку “Cannot use ‘String’ as class name as it is reserved”. Класс переименовали. Обратите внимание на список зарезервированных слов.
В PHP 7 изменился формат кеш-файла для WSDL-схемы в SoapClient. Можно настроить сохранение кэша в разные директории в зависимости от версии PHP или полностью очищать кэш перед сменой версии интерпретатора.
Расширение mongo, которое мы активно использовали, перестало поддерживаться в новом PHP. Вместо него мы стали использовать официальную библиотеку MongoDB PHP Library. Прошлись по всему коду и заменили MongoCollection::insert() на MongoDB\Collection::insertOne(), MongoCollection::remove() на MongoDB\Collection::deleteMany() и далее по списку. Стали использовать классы для работы с BSON из нового драйвера MongoDB, например, MongoDate вместо MongoDB\BSON\UTCDateTime.
Результат
Бэкенд сайта тоже доволен.
Обновление до PHP 7.1
В PHP 7.1 появилось несколько очень приятных нововведений: тип void для возвращаемых значений, iterable, возможность вернуть null для типизированных возвращаемых значений, область видимости констант и прочее. К тому же, период активной поддержки PHP 7.0 заканчивается уже в конце этого года. Решили обновиться до PHP 7.1.
Неожиданности
При обновлении на ровном месте образовалась проблема. Пакет php-memcached для 7.1 потянул за собой пакет php-igbinary. Когда поставили PHP 7.1 на один из боевых серверов, с остальных серверов начали сыпаться ошибки, в которых фигурировало слово “igbinary”.
Старый друг Memcache, снова различия сериализации, но немного под другим соусом. Выяснилось, что модуль php-memcached по умолчанию использует первый доступный сериализатор из списка: igbinary (в отдельном модуле), msgpack (в отдельном модуле), php (не требует отдельного модуля, доступен всегда). И тот сервер, на котором мы поставили 7.1 с igbinary, начал записывать данные в мемкеш, сериализованные igbinary. А на остальных серверах не было поддержки этого сериализатора, и они не могли прочитать данные, записанные сервером с обновлённым PHP. Локализовали проблему, установили igbinary на всех остальных серверах, ошибки прекратились.
Послесловие
Разработчики PHP взяли хороший курс. Они добавляют полезные инструменты, избавляются от недостатков, связанных с наследием языка, всерьёз задумываются о производительности.
Ранее мы уже рассказывали о переходе Avito на сервисную архитектуру (раз, два). Такая архитектура позволяет писать на любых языках, и новые сервисы мы чаще всего пишем на Go или Python’е. Однако об отказе от PHP речи не идёт: основная логика сайта (монолит) всё ещё на PHP, а команда отлично знает, как с ним работать. Новые версии интерпретатора позволяют сделать код лучше, а его выполнение быстрее.
Делитесь вашим опытом перехода на PHP 7 и выше, будем рады обсудить открытия и грабли, которые встретились вам на этом пути.