Компания
242,80
рейтинг
11 марта в 14:22

Разработка → Badoo перешли на PHP7 и сэкономили $1M

Badoo перешли на PHP7 и сэкономили $1M

Мы сделали это! Несколько сотен наших application-серверов переведены на PHP7 и прекрасно себя чувствуют. Насколько нам известно, это второй переход на PHP7 проекта такого масштаба (после Etsy). В процессе мы нашли несколько очень неприятных багов в системе кеширования байт-кода PHP7, но они исправлены. А теперь — ура! — благая весть для всего PHP-сообщества: PHP7 действительно готов к продакшену, стабилен, потребляет значительно меньше памяти и дает очень хороший прирост производительности. Ниже мы подробно расскажем, как мы перешли на PHP7, с какими трудностями столкнулись, как с ними боролись и какие результаты получили. Но начнем с небольшого введения.

Мнение о том, что узким местом в веб-проектах является база данных — одно из самых распространенных заблуждений. Хорошо спроектированная система сбалансирована — при увеличении входной нагрузки удар держат все части системы, а при превышении пороговых значений тормозить начинает все: и процессор, и сетевая часть, а не только диски на базах. В этой реальности процессорная мощность application-кластера является чуть ли не самой важной характеристикой. Во многих проектах этот кластер состоит из сотен или даже тысяч серверов, поэтому «тюнинг» процессорной нагрузки на кластере приложений оказывается более чем оправданным экономически (миллион долларов в нашем случае).

Процессор в веб-приложениях PHP «съедает» столько же, сколько и любой высокоуровневый динамический язык — много. Но у PHP-разработчиков годами была особенная печаль (и повод для сильнейшего «троллинга» со стороны прочих сообществ) — отсутствие в PHP «честного» JIT или хотя бы генератора в компилируемый текст на языках типа С и С++. Неспособность сообщества предоставить подобные решения в рамках основного проекта породило неприятную тенденцию: крупные игроки стали придумывать собственные решения. Так появились HHVM в Facebook, KPHP во «Вконтакте», наверняка были и другие «поделки».

К счастью, в 2015 году сделан первый шаг к тому, чтобы PHP стал «взрослее»: вышел PHP7. JIT в PHP7 так и не появился, однако результат изменений в «движке» трудно переоценить: теперь на многих задачах PHP7 даже без JIT не уступает HHVM (см., например, бенчмарки из блога LiteSpeed и бенчмарки из презентации разработчиков PHP7). Новая архитектура PHP7 также упрощает дальнейшее добавление JIT.

Платформенные разработчики в Badoo пристально следили за этими страстями последние несколько лет и даже сделали пилотный проект с HHVM, но решили дождаться PHP7, поскольку посчитали его более перспективным. И недавно мы запустили Badoo на PHP7! Это был эпичный проект как минимум из-за размера: у нас больше 3 миллионов строк кода на PHP и 60 000 тестов. О том, как мы со всем этим справились, попутно придумав новый фреймворк для тестирования PHP-приложений (уже выпустили в open source — похож на Go! AOP) и сэкономили целый миллион — читайте дальше.

Опыты с HHVM


Перед переходом на PHP7 мы некоторое время искали другие способы оптимизировать наш backend. Конечно, первым делом мы решили «поиграться» с HHVM.

Потратив пару недель на исследование, мы получили весьма достойные результаты: после прогрева JIT на нашем фреймворке выигрыш по скорости и использованию CPU составлял сотни процентов.

Однако HHVM обладал неприятными недостатками:

  • сложный и медленный деплой. При деплое необходимо обязательно прогревать JIT-кеш. В момент прогрева машина не должна быть нагружена продакшен-трафиком, потому как работает все достаточно медленно. Прогревать параллельными запросами тоже не рекомендуется. Короче, фаза прогрева большого кластера — операция небыстрая, плюс на большой кластер в несколько сотен машин надо научиться выкладывать порционно. В итоге получаем нетривиальную архитектуру и процедуру деплоя с непредсказуемым временем работы. А мы хотим иметь максимально простой и быстрый деплой: важной частью нашей девелоперской культуры является выкладка двух плановых релизов в день и возможность быстро «раскатать в бой» хотфиксы;
  • неудобство тестирования. Для юнит-тестирования мы активно использовали расширение runkit, которое отсутствует в HHVM. Мы подробнее расскажем об этом дальше, но если вы вдруг не в курсе, то это такое расширение, которое позволяет на лету менять поведение переменных, классов, методов, функций практически как угодно, и делается это через весьма «хардкорную» интеграцию с «внутренностями» PHP. Ядро HHVM лишь отдаленно похоже на ядро PHP, так что эти самые «внутренности» там абсолютно разные. Поэтому реализовать runkit поверх HHVM самостоятельно — адов труд: из-за особенностей расширения нам пришлось бы переписывать десятки тысяч тестов, чтобы убедиться, что HHVM правильно работает с нашим кодом. Нам это показалось нецелесообразным. Если быть честными, это было проблемой любого из вариантов, и при переходе на PHP7 нам все равно пришлось переделать очень многое, в том числе выкинуть runkit, но об этом позже;
  • совместимость. В первую очередь это неполная совместимость с PHP 5.5 (см. github.com/facebook/hhvm/blob/master/hphp/doc/inconsistencies, github.com/facebook/hhvm/issues?labels=php5+incompatibility&state=open) и несовместимость с уже написанными расширениями, а у нас их десятки. Обе несовместимости вытекают из очевидного структурного недостатка проекта: HHVM разрабатывается не сообществом, а отделом внутри Facebook. В таких случаях компаниям значительно проще поменять внутренние правила и стандарты, не оглядываясь на сообщество и тонны уже написанного кода. Им проще переделать все под себя, решить проблему своими ресурсами. Поэтому, чтобы успешно работать при таких же объемах задач, нужно иметь сравнимый по мощности ресурс и для первичного этапа внедрения, и для дальнейшей поддержки. Это рискованно и потенциально дорого — мы так рисковать не хотели;
  • перспективы. Несмотря на то, что Facebook — большая компания с классными программистами, у нас были большие сомнения в том, что отдел разработки HHVM может оказаться мощнее PHP-сообщества. Мы полагали, что как только внутри PHP появится что-то похожее, все доморощенные проекты начнут медленно, но верно умирать.

И мы стали ждать PHP7.

Переход на новую версию интерпретатора — важный и сложный процесс, поэтому мы готовились к нему, составив четкий план перехода. Он состоял из трех этапов подготовки:

  • изменение инфраструктуры для сборки и деплоя PHP и адаптация множества написанных нами расширений;
  • изменение инфраструктуры и окружения тестирования;
  • изменения PHP-кода приложений.

Расскажем обо всех этапах подробнее.

Исправления в ядре и расширениях


У нас есть собственная, активно поддерживаемая и дорабатываемая ветка PHP. Мы начали проект по переводу Badoo на PHP7 еще до его официального релиза, поэтому нам надо было плавно обеспечить регулярный rebase PHP7 upstream в наше дерево, чтобы иметь возможность получать обновления каждого релиз-кандидата. Все патчи и кастомизации (см. секцию «Патчи» нашего техсайта tech.badoo.com/open-source), которые мы используем в повседневной работе, также должны были быть портируемыми между версиями и работать корректно.

Мы автоматизировали выкачивание и сборку всех зависимостей, экстеншенов и дерева PHP под 5.5 и 7.0. Это не только упростило работу, но и дало хороший задел на будущее: когда выйдет версия 7.1, у нас уже все будет готово.

Над экстеншенами тоже пришлось попотеть. Мы подерживаем около 40 расширений, причем больше половины — внешние расширения open source с нашими доработками.

Для максимально быстрого перехода мы решили запустить параллельно два процесса. Первый — перепиcать самостоятельно самые критичные для нас расширения: шаблонизатор Blitz, кеш данных APcu в Shared memory, сбор статистики в Pinba и некоторые кастомные для работы с внутренними сервисами (в итоге около 20 расширений).
Второй — активно избавляться от расширений, которые используются в некритичных частях инфраструктуры. Легко избавиться нам удалось от 11 расширений — немало!

И, конечно, мы начали активно общаться с людьми, которые поддерживают основные открытые расширения, используемые нами, на предмет совместимости с PHP7 (отдельное спасибо Дерику Ретансу (англ. Derick Rethans), который разрабатывает Xdebug).

Далее мы немного подробнее остановимся на технических деталях портирования расширений под PHP7.

В 7-й версии PHP-разработчики изменили много внутренних API, что вызвало необходимость правки большого количества кода в экстеншенах. Самые важные изменения следующие:
  • zval * → zval. Ранее, при создании новой переменной, структура zval всегда аллоцировалась, а теперь используется структура из стека;
  • char * → zend_string. В PHP7 используется агрессивное кеширование строк в ядре PHP, поэтому в новом ядре повсеместно перешли с обычных строк на структуру zend_string, в которой хранится строка и ее длина;
  • изменения в API массивов. Теперь используется zend_string в качестве ключа, в имплементации массивов заменили double linked list на обычный массив, который выделяется одним блоком вместо множества маленьких.

Все это позволило кардинально уменьшить количество небольших аллокаций памяти и в результате ускорить ядро PHP на десятки процентов.

Нужно отметить, что все эти изменения повлекли за собой необходимость если не переписывать, то активно править все экстеншены. Если в случае со встроенными экстеншенами мы могли рассчитывать на их авторов, то наши разработки могли править только мы, а правок нужно было много: из-за изменения внутренних API некоторые части кода было проще переписать.

К сожалению, введение новых структур, использующих сбор мусора, одновременно с ускорением выполнения кода усложняет сам движок и нахождение проблем в нем. Одной из них стала проблема в OPcache, которая заключалась в следующем: при очистке кеша байт-код закешированного файла разрушался в тот момент, когда он еще мог использоваться в другом процессе, что приводило к падению процесса. Внешне это выглядело так: строки (zend_string) в названиях функций или констант вдруг разрушаются и вместо них появляется мусор.

Поскольку у нас используется значительное количество экстеншенов собственной разработки, многие из которых активно работают со строками, то в первую очередь подозрение пало на неправильное использование строк в них. Написали много тестов, провели много экспериментов, но всё безрезультатно. В итоге пришлось обратиться за помощью к основному разработчику ядра PHP — Дмитрию Стогову.

В первую очередь он спросил, очищался ли кеш. Выяснили, что, действительно, в каждом случае так и было. Стало понятно, что проблема все-таки не у нас, а в OPcache. Мы быстро воспроизвели проблему и Дмитрий исправил ее в течение пары дней. Без этого исправления, которое вошло в версию PHP 7.0.4, использовать ее стабильно в продакшене было нельзя!

Изменение инфраструктуры тестирования


Тестирование в Badoo — наша особенная гордость. PHP-код мы выкладываем в продакшен 2 раза в день, в каждую выкладку у нас попадает 20-50 задач (мы используем feature branch в Git и автоматизированную сборку билдов с тесной JIRA-интеграцией). При таком графике и объеме задач без автотестов никак.

На сегодняшний день у нас около 60 тысяч юнит-тестов примерно с 50%-м покрытием, которые проходят в среднем за 2-3 минуты в облаке (об этом мы уже рассказывали на Хабре). Помимо юнит-тестов, мы используем автотесты более высокого уровня — интеграционные и системные тесты, selenium-тесты для веб-страниц и calabash-тесты для мобильных приложений. Все это разнообразие позволяет нам в кратчайшие сроки сделать вывод о качестве каждой конкретной версии кода и принять соответствующие решения.

Переход на новую версию интерпретатора — кардинальное изменение. Возможных проблем может быть сколько угодно, поэтому крайне важно, чтобы все тесты работали. Для того чтобы стало понятно, что, как и почему мы делали, необходимо совершить небольшой экскурс в историю и рассказать про эволюцию развития тестов в нашей компании.

Часто люди, задумывающиеся о тестировании своих продуктов, сталкиваются в процессе экспериментов (а некоторые уже при внедрении) с тем, что их код к этому не готов. Действительно, разработчик должен помнить о том, что его код должен быть тестируемым. Архитектура должна позволять юнит-тестам подменять вызовы и объекты внешних зависимостей, чтобы изолировать тестируемый код от внешних условий. Надо сказать, что требование это усложняет жизнь, и многие программисты из принципа не хотят писать код так, чтобы его можно было тестировать — навязываемые ограничения вступают в неравную борьбу с прочими ценностями «хорошего кода» и обычно проигрывают. И часто, представив себе объем имеющегося кода, написанного не по правилам, экспериментаторы просто откладывают тестирование до лучших времен либо пытаются довольствоваться малым, покрывая тестами только то, что можно покрыть (в итоге тесты не всегда дают ожидаемый результат).

Наша компания — не исключение. Мы тоже начали внедрять тестирование далеко не сразу после старта проекта. Было уже написано немало строк кода, который вполне себе работал в продакшене и приносил хорошие деньги. Переписывать весь этот код ради возможности покрыть его тестами так, как рекомендуется, вышло бы слишком долго и дорого.

К счастью, на тот момент уже был отличный инструмент, который позволял решить большинство проблем с нетестируемым кодом — runkit. Это расширение для PHP, которое позволяет во время исполнения скрипта менять, удалять, добавлять методы, классы и функции, используемые в программе. Он может еще много чего, но другие функции расширения мы не использовали. Инструмент разрабатывался и поддерживался в течении нескольких лет (с 2005 по 2008 годы) Сарой Гоулман (англ. Sara Golemon), которая сейчас работает в Facebook, в том числе и над HHVM. А с 2008 года и по сегодняшний день проект поддерживает наш соотечественник Дмитрий Зенович (работал руководителем отделов тестирования в «Бегуне» и Mail.Ru). И мы тоже немножко «наконтрибутили» в проект.

Сам по себе runkit — очень опасный экстеншен. С его помощью можно менять константы, функции и классы прямо во время работы скрипта, который их использует. По сути, это инструмент, с помощью которого можно перестроить ваш самолет прямо во время полета. Runkit лезет в самые внутренности PHP на лету; одна ошибка или недоработка в runkit — и самолет красиво взрывается в воздухе, PHP падает, либо вы проводите много часов в поиске утечек памяти и прочей низкоуровневой отладке. Тем не менее, это был для нас необходимый инструмент: внедрить тестирование в проект без серьезного переписывания можно только так, через изменение кода на лету, просто заменяя его на нужный.

При переходе на PHP7 runkit оказался большой проблемой — эту версию PHP он не поддерживал. Был вариант спонсирования разработки новой версии, но этот путь не казался нам самым надежным в долгосрочной перспективе. Параллельно мы рассматривали несколько других вариантов.

Одним из перспективных решений было перейти с runkit на uopz. Это тоже расширение PHP c похожей функциональностью, появившееся в апреле 2014 года. Его нам предложили коллеги из «Mамбы», дав очень хорошие отзывы в первую очередь о скорости работы. Проект поддерживает Джо Уоткинс (англ. Joe Watkins) из First Beat Media (UK). Выглядел этот проект более живым и перспективным по сравнению с runkit. Но, к сожалению, перевести на uopz все тесты у нас не получилось. Где-то случались фатальные ошибки, где-то сегфолты — мы завели несколько репортов, но по ним, увы, движения нет (подробнее см. например этот баг на github). Обойтись переписыванием тестов в этом случае получилось бы очень дорого, да и не факт, что не выявилось бы что-то еще.

В результате мы пришли к очевидному для нас решению: раз нам и так необходимо переписать множество кода и при этом все равно зависеть от внешних проектов типа runkit или uopz, с которыми у нас постоянно появляются проблемы, которые очень дорого либо невозможно решать самостоятельно, то почему бы уже не переписать код так, чтобы по максимуму все зависимости убрать? Да так, чтобы подобных проблем у нас больше никогда не возникало, даже если мы захотим перейти на HHVM или любой другой подобный продукт. И тогда у нас появился свой фреймворк.

Система получила название SoftMocks. Слово soft подчеркивает, что система работает на чистом PHP вместо использования расширений. Это проект open source, он доступен в виде подключаемой библиотеки и находится в открытом доступе. SoftMocks не завязан на особенности реализации ядра PHP и работает с помощью переписывания кода на лету, по аналогии с фреймворком Go! AOP.

В нашем коде тестов в основном используются следующие вещи:
  1. Подмена реализации одного из методов класса.
  2. Подмена результата выполнения функции.
  3. Изменение значения глобальной константы или константы класса.
  4. Добавление метода в класс.

Все эти возможности прекрасно реализуются с помощью runkit. При переписывании кода это становится возможным, но с некоторыми оговорками.

Описание работы SoftMocks — материал для отдельной статьи, которую мы в ближайшее время напишем. А пока ограничимся лишь кратким описанием работы этой системы:

  • пользовательский код подключается через функцию-обертку rewrite. После этого все операторы include автоматически рекурсивно подменяются на обертки;
  • внутрь определения каждого пользовательского метода добавляется проверка на существование подмены, и если она есть, то выполняется соответствующий код. Прямые вызовы функций заменяются на вызов через обертку — это позволяет перехватывать как встроенные, так и пользовательские функции;
  • обращения к константам в коде также динамически подменяются на вызов обертки;
  • SoftMocks в работе использует PHP-Parser Никиты Попова. Эта библиотека не очень быстрая (парсинг примерно в 15 раз медленнее token_get_all), но предоставляет удобный интерфейс для обхода синтаксического дерева и дает удобный API для работы с синтаксическими конструкциями произвольной сложности.

Вернемся к нашей задаче — переходу на PHP7. После того как мы стали использовать в проекте SoftMocks, у нас осталось около 1000 тестов, которые требовалось «починить» вручную. Это можно считать неплохим результатом, если учесть, что изначально у нас было 60 000 тестов. Скорость их прогона по сравнению с runkit не уменьшилась, так что в плане производительности серьезных потерь от использования SoftMocks нет. Справедливости ради отметим, что uopz все-таки должен работать заметно быстрее.

Утилиты и код приложения


Помимо множества нововведений, PHP7 принес с собой и некоторые обратные несовместимости. Первое, с чего мы начали изучение проблемы — это чтение официального migration guide. Быстро стало понятно, что без исправления имеющегося кода мы рискуем как получить в продакшене фатальные ошибки, так и столкнуться с изменением поведения, которое не будет отражено в логах, но приведет к неправильной логике работы приложения.

Badoo — это несколько репозиториев кода на PHP, самый крупный из которых содержит более 2 миллионов строк кода. Причем на PHP у нас реализовано множество вещей: начиная от бизнес-логики веба и бекенда мобильных приложений и заканчивая утилитами тестирования и выкладки кода. Кроме этого ситуация осложнялась тем, что Badoo — проект с историей, ему уже 10 лет, и наследие PHP4, к сожалению, все еще присутствовало. Соотвественно, метод «пристального вглядывания» неприменим. Неприменима и «бразильская система», то есть выложить в продакшен как есть и смотреть, что сломается, чересчур увеличивает риски сломать бизнес-логику для слишком большого процента пользователей. Поэтому мы стали искать возможность автоматизировать поиск несовместимых мест.

Сначала мы попытались использовать наиболее популярные среди разработчиков IDE, но, к сожалению, на тот момент они либо просто не поддерживали синтаксис и особенности PHP7, либо обнаруживали подозрительно мало проблем, пропуская, очевидно, опасные места в коде. После небольшого исследования было решено попробовать утилиту php7mar. Это такой несложный статический анализатор кода, реализованный на PHP. Очень прост в использовании, работает довольно быстро, результат предоставляет в виде текстового файла, требует наличия PHP7. Конечно, данная утилита не является панацеей, имеются как ложные срабатывания, так и пропуски особенно «хитрых» мест в коде. Но около 90% проблем с ее помощью удалось обнаружить, что существенно ускорило и облегчило процесс подготовки кода к работе под PHP7.

Наиболее часто встречающимися и потенциально опасными проблемами для нас были:
  • изменение поведения функций func_get_arg() и func_get_args(). В пятой версии PHP эти фунции возвращали значения аргументов функций на момент их передачи, а в седьмой версии — на момент вызова func_get_args(). Таким образом, если внутри функции до вызова func_get_args() переменная агрумента изменяется, то есть риск получить поведение, отличное от пятой версии. Это тот самый случай, когда в логах будет пусто, а бизнес-логика приложения может оказаться сломанной;
  • непрямое обращение к переменным, свойствам и методам объектов. И снова опасность в том, что поведение может измениться «молча». В документации достаточно подробно описано, в чем именно заключаются отличия;
  • использование зарезервированных имен классов. В PHP7 стало нельзя использовать bool, int, float, string, null, true и false в качестве имени класса. Да-да, у нас был класс Null. К счастью, этот случай уже проще, потому как приводит к ошибке;
  • очень много было найдено потенциально проблемных конструкций foreach, которые используют ссылку. Но практически все из них вели себя одинаково в пятой и седьмой версии, так как мы и раньше старались внутри foreach не изменять итерируемый массив и не рассчитывать на его внутренний указатель.

Остальные случаи несовместимости либо встречались крайне редко (как, например модификатор ‘e’ для регулярных выражений), либо исправлялись простой заменой (например, теперь все конструкторы должны называться __construct(), использовать имя класса запрещено).
Но, перед тем как начать исправление кода, мы подумали, что пока одни разработчики вносят необходимые для совместимости изменения, другие будут продолжать писать несовместимый с PHP7 код. Для решения этой проблемы мы добавили pre-receive hook в каждый Git-репозиторий, который выполнял на изменяемых файлах php7 -l, т.е. проверял их на соответствие синтаксису PHP7. Это не гарантирует полную защиту от несовместимоcти, но уже устраняет ряд проблем. В остальных же случаях разработчикам просто приходилось быть чуть внимательнее. Кроме того, мы стали делать регулярный прогон полного набора тестов под PHP7 и сравнивать результаты с прогонами под PHP5. При этом использовать любые новые возможности PHP7 разработчикам было запрещено, т.е. старый pre-receive hook с php5 -l мы не выключали. Это позволило нам в определенный момент получить код, совместимый как с седьмой, так и с пятой версией интерпретатора. Почему это важно? Потому что помимо проблем с PHP-кодом, при обновлении на новую версию возможны проблемы с самим PHP7 и его расширениями (собственно, как сказано выше, мы с этими проблемами и столкнулись). И, к сожалению, не все из них воспроизводились в тестовом окружении, некоторые мы смогли увидеть только под значительной нагрузкой в продакшене.

«Запуск в бой» и результаты


Очевидно, нам требовался простой и быстрый способ менять версию PHP на любом количестве любых серверов. Для этого во всем коде пути к CLI-интерпретатору были заменены на /local/php, который, в свою очередь, являлся симлинком либо на /local/php5, либо на /local/php7. Таким образом, для изменения версии PHP на сервере требовалось изменить ссылку (операция атомарна — это важно для CLI-скриптов), остановить php5-fpm и запустить php7-fpm. Можно было бы иметь в nginx два upstream для php-fpm, запускать php5-fpm и php7-fpm на разных портах, но этот вариант нам не понравился усложением конфигурации nginx.

После того как все вышеперечисленное было выполнено, мы смогли перейти к прогону selenium-тестов в препродакшен-окружении, что позволило нам обнаружить ряд проблем, не замеченных ранее. Они каcались как PHP-кода (например, пришлось отказаться от устаревшей глобальной переменной $HTTP_RAW_POST_DATA в пользу file_get_contents(«php://input»)), так и расширений (разного рода ошибки сегментирования).

Исправив обнаруженные на предыдущем этапе проблемы и закончив переписывание юнит-тестов (в ходе которого нам тоже удалось обнаружить несколько багов в интерпретаторе, например, такой), мы наконец приступили к «карантину» в продакшене. «Карантином» мы называем запуск новой версии PHP на ограниченном числе серверов. Начали с одного сервера в каждом крупном кластере (бекенд веба и мобильных приложений, облако), постепенно увеличивая количество, если ошибок не возникает. Первым крупным кластером, полностью перешедшим на PHP7, стало облако. Причиной этому послужило отсутствие на нем потребности в php-fpm. Тем же кластерам, где работает fpm, пришлось подождать до тех пор, пока мы не обнаружили, а Дмитрий Стогов не исправил проблему с OPcache. После этого мы уже перевели и fpm-кластер.

Теперь о результатах. Если коротко, то они более чем впечатляют. Ниже приведены графики времени ответа, rusage, потребления памяти и использования процессора в самом крупном (263 сервера) из имеющих у нас кластеров, а именно — бекенда мобильных приложений в пражском дата-центре:

Распределение времён ответа:


RUsage (CPU time):


Memory usage:


CPU load (%) на всём кластере:


Таким образом, процессорное время сократилось в 2 раза, что улучшило общее время ответа примерно на 40%, так как некоторая часть времени при обработке запроса тратится на общение с базами и демонами, и с переходом на PHP7 эта часть никак не ускоряется, что ожидаемо. Кроме того, эффект несколько усиливается тем, что общая нагрузка на кластер упала ниже 50%, что указывает на некоторые особенности в работе технологии Hyper-Threading. Грубо говоря, при увеличении нагрузки выше 50% начинают работать HT-ядра, которые не настолько «полезны», как ядра физические, но это уже тема для другой статьи.
Потребление памяти, хотя никогда и не являлось для нас узким местом, снизилось примерно в 8 раз! И, наконец, мы сэкономили на оборудовании — теперь мы можем на том же количестве серверов выдерживать намного большую нагрузку, что, по сути, снижает затраты на его приобретение и обслуживание. Результаты на остальных кластерах отличаются незначительно, разве что выигрыш на облаке чуть скромнее (порядка 40% CPU) из-за отсутствия там OPcache.

Сколько мы сэкономили в деньгах? Давайте посчитаем. Кластер серверов приложений у нас состоит из 600 с лишним серверов. Снизив использование CPU в два раза, мы получаем экономию примерно в 300 серверов. Добавив начальную цену такого «железа» (порядка 4000$ за каждый) и амортизацию, получаем около миллиона долларов экономии плюс около ста тысяч в год на хостинге! И это не считая облака, производительность которого также выросла. Считаем, что это — отличный результат!

А вы уже перешли на PHP7? Будем рады услышать ваше мнение и вопросы в комментариях.
Автор: @fisher
Badoo
рейтинг 242,80

Комментарии (304)

  • +9
    Круто, молодцы!
  • +15
    Отлично отлично, живой пример оптимизации php7 на реальных данных, молодцы ребята
  • +5
    О, неожиданно ) Спасибо что сохранили копирайты на мою идею и на оригинальную реализацию в моем фреймворке!

    fisher а почему не стали использовать готовое? Сейчас у меня версия 2.0-dev фреймворка работает как раз на PHP-Parser, поддерживает 5.6 и 7.0, имеет интеграцию с опкэшем и прозрачный механизм дебага. Вроде все что вам нужно, уже там есть для тестов )
    • +1
      Про Soft Mocks ждите отдельную статью, в которой мы более подробно опишем, что и как :)
  • –40
    Вы не сэкономили $1M, а потеряли, т.к. теперь есть 300 лишних серверов
    • +23
      Л — Логика
      • –6
        В защиту первого коммента хочу сказать, что сервера не облачные и не в аренде ("… снижает затраты на его приобретение и обслуживание"), следовательно 300 освободившися серверов все равно будут стоять в ожидании роста числа посетителей (что не гарантировано) или увеличения нагрузки из-за растущей сложности приложений. То есть по факту перехода на PHP7 компания обнаружила, что уже потратила на закупку и будет тратить кучу денег на обслуживание уже ненужных серверов ;)
        • +5
          В большой компани всегда есть куда девать сервера, badoo — не исключение.

          Also, всегда можно их использовать для увеличения отказоустойчивости всех сервисов.
          • +10
            Или включения новых фич, запуск которых откладывали из-за создаваемой нагрузки (спойлер :))
        • +3
          При их скоростях роста и объемах закупок железа — как раз просто сэкономили денег, просто не понадобится в ближайшие полгода-год докупать.

          А если уж совсем излишек — можно банально продать: там Германия рядом, где полно low-end хостеров, вряд ли будет сложно найти покупателя.
    • +1
      Лишних серверов не бывает!
  • +6
    Есть ли подобная статья на английском? Коллегам показать.
  • +3
    Мнение о том, что узким местом в веб-проектах является база данных — одно из самых распространенных заблуждений.
    Золотые слова!

    Как появятся все необходимые расширения под PHP7, так будем пробовать перейти.
    • +2
      Подавляющее большинство расширений уже есть.
      Вам каких не хватает?
      • 0
        redis, например
        • 0
          Вижу там бранч php7: https://github.com/phpredis/phpredis/tree/php7
          Не пробовали его?
        • +5
          Тоже долго не переходили на PHP7 из-за Redis. Но потом почитали доки, оказалось у редиса же простейший протокол.
          В итоге перешли на PHP7 + TinyRedisClient. Только допилили немного, чтобы пайплайнинг работал.
        • +2
          Predis очень шустро работает и без расширений. От опционального ext/phpiredis профит заметен только на жирных pipeline-ах с огромными ответами, подозреваю, что от перехода на PHP7 профит намного заметнее.
  • +19
    Судя по графикам, на php7 вы переключились в пятницу?
    • +6
      Вы так говорите, как будто это что-то плохое :)
      • +2
        Не, ну если накатили и ушли в кабак праздновать — то, пожалуй, не очень хорошее :)
        • +5
          «Накатили и пошли накатить».
        • +1
          это было после карантина на части кластера, этот карантин не виден на графиках.
    • +4
      Это один из кластеров. До него несколько других работало уже три дня.
      Ну и накатили утром, так чтоб весь день держать руку на пульсе.
      • +17
        Ну и накатили утром

        Кто бы сомневался =)
    • +6
      Увлекательно. Графики будут нагляднее, если начинать их от нуля, а не 5 или 50. Визуально выглядит, что память теперь вообще не используется.
  • –2
    Подскажите, вместе с пхп7 не стоит ждать настоящий fast_cgi?
    • +2
      Дайте, пожалуйста, определение настоящего FastCGI.
      • +1
        это чтобы я мог написать где-то в коде контроллера echo $counter++ и и получить 1....2....3....4 на каждый заход.
        • 0
          Демона хотите из пыха сделать?) Ну вроде архитектура не та.
          Меня интересует вот такая часть этой области, которую я не могу понять (платформа винда правда)
          http://stackoverflow.com/questions/31731371/why-only-6-php-fastcgi-wokers-loaded-on-iis-8
          • 0
            http://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser
        • +2
          о, это очень старая история, но она от семёрки вообще не зависит
          в PHP принята абсолютно не побоюсь этого слова гениальная stateless модель fcgi, с полным очищением памяти после завершения выполнения запроса, практически гарантирующая отсутствие "распухание" по памяти и прочую радость в продакшене
          ну и отдельно скажу что для share nothing архитектур состояние в приложении — зло
          • 0
            Я все вот мечтаю, что рано или поздно они добавят shared-объекты между процессами с volatile-модификаторами для переменной, тогда в шаред-памяти можно хранить будет настоящие инстансы, например, подключений к базе или прогретые контейнеры классов и т.д.

            В этом случае все остальное бы благополучно чистилось, а специальные объекты могли бы переживать несколько запросов. Но! Это должно быть обязательно с реализацией нормального IPC API, чтобы не было как mysql_pconnect и всяким шлаком в нем при повторном запросе.
            • +3
              Зачем мечтать? Просто сделайте.
            • 0
              Какой смысл делать всё такие крутое если при рестарте всё равно пропадут данные?

              А persistent connections к сервисам можно и так делать на уровне расширений.
              • 0
                я не могу найти ссылку на документацию, где было бы рассказано, как имплементить persistent connection к своему кастомному сервису. Не подскажете, где почитать?
                • +2
                  На документацию по написанию PHP extension с поддержкой persistent connect?
                  На деле всё не так просто и о persistent connection нужно думать начиная с протокола взаимодействие клиента с сервером.
                  А уже во вторую очередь думать о том как это сделать в расширении для определённого языка.
                  Для начала, ИМХО, стоит начать отсюда: http://www.slideshare.net/rybaxek/pconnect-12329335.
                  • +1
                    Спасибо!
                  • +2
                    Дожили, уже slideshare приходится через tor смотреть
            • +2
              тогда в шаред-памяти можно хранить будет настоящие инстансы, например, подключений к базе
              Есть persistent connection ко всем распространнёным СУБД, к сокетам и к memcached.
            • +2
              В чем проблема? memcache, redis, mongodb и прочие — решают эту проблему. Плюс дает вам возможность выбора конкретного решения под конкретную задачу. Нужно хранить объекты в памяти? вот вам memcache. Нужно шарить в кластере? Вот вам redis или mongo. Еще есть сессии, который нативные, и которые можно перенести по требованию в memcache или любое другое место. Ну а если вам нужен демон, то пишите демона, php отлично с этим справляется.
              • 0
                Нужно хранить объекты в памяти? вот вам memcache.

                1. Сериализация-десериализация крупных объектов может стать проблемой. Гораздо логичнее использовать уже созданный объект в shared memory. Конечно, это добавляет головняка с race conditions и на любое обновление данных придётся вешать мьютекс, но производительность сего решения может стоить того. Особенно если задача состоит в хранении крупного иммутабельного объекта вроде конфига, редко меняющегося и часто читаемого.
                2. Данный подход хорош для атомарных сущностей. Если же для инициализации объекта необходима инициализация зависимостей, то тут уже без велосипеда на костылях не обойтись.
                • +2
                  Возможно тогда вам нужен не php? Есть же вон ruby, go, python, java (тут вообще ближе всего к пхп, так как из нее уже почти все перетянули). Там как раз с этим будет проще, и не надо будет извращаться.

                  Так же можно не ждать, а сделать самому) http://zephir-lang.com/
                  • +1
                    Я к тому, что идея shared memory в PHP имеет право на жизнь. Хранить сериализованные данные в одном из хранилищ — это не всегда выход. Собственно, APCU частично решает эту задачу. Но было бы круто вслед за мега-фичей в виде PHP FPM следующим шагом дать нативный инструмент работы с объектами в shared memory.
                    Мне довелось поработать с true Fast CGI на С++. Это ад. Но сама идея иметь объекты, живущие между запросами, жива и её вполне можно было бы органично имплементировать в стандарте языка.
                    • +1
                      Кстати есть же http://php.net/manual/en/book.shmop.php и http://php.net/manual/en/book.pthreads.php, так что можно что то придумать )
                      • +2
                        pthreads — совсем не то
                        shmop — почти то, если к нему ещё прикрутить мьютексы. И всё равно требует сериализации.
                        Идеально было бы: высокоуровневая языковая конструкция, позволяющая создавать и использовать объекты в разделяемой памяти с внутренней имплементацией exclusive&shared locking и TTL чтобы у дева голова об это не болела.
                    • 0
                      Ну и конечно же, у всего этого есть один большой минус который проигрывает микросервисному подходу. Вы будете ограниченны одним физическим сервером. Расшарить свой объект на 1+n серверов не получится.
                      • +1
                        Шарить что-то между серверами — это совсем другой уровень. Межпроцессный шаринг объектов очень пригодился бы для хранения тяжёлых read-only объектов вроде конфигов. На больших нагрузках может неплохо съэкономить на создании сокета, хендшейке, поиске информации в хранилище, отправке, закрытии соединения, десериализации. Всё это абсолютно лишнее, если уже готовый собранный конфиг лежит в виде zval где-то в памяти.
                        • +1
                          RO конфиги проще при деплое транслировать в PHP (или сразу писать их на PHP) и при первом обращении полученный для них байткод будет закеширован.
                          • 0
                            Да, это отличный подход, если конфиг не представляет собой здоровенное DOM-дерево с обёрткой вокруг для унификации и упрощения доступа.
                            • 0
                              DOM легко и просто транслируется во что угодно с помощью XSLT. ;-)
                              • 0
                                И что? Вопрос же не в том, как хранить и преобразовывать, а в том, чтобы вообще не создавать тяжёлые объекты на каждый запрос, а пользоваться расшаренными. Кеши байткода избавляют от стадии компиляции. Но не избавляют от процесса создания объекта. А это те самые потерянные миллисекунды и процессорное время, которое вполне можно было бы потратить на что-то полезное. Да и конфиги — это малая из бед. Половину аппликейшена можно было бы реюзать если был бы нормальный инструмент. Естественно, апплекейшн пришлось бы изначально проектировать как стейтлесс, но это уже тема для отдельного топика.
                                Конечно, можно было бы использовать язык, изначально заточенный под event-loop или с легковесными потоками как в Go. Но не вижу никаких препятствий запилить нечто подобное и в Пыхе. Всё равно имхо к этому идёт.
                                • +1
                                  Конечно, можно было бы использовать язык, изначально заточенный под event-loop или с легковесными потоками как в Go. Но не вижу никаких препятствий запилить нечто подобное и в Пыхе. Всё равно имхо к этому идёт.

                                  Много раз пытались "слезть с PHP" — везде свои плюсы и минусы.

                                  Меня тоже очень интересуют объекты(immutable типа), зашаренные в память. Задача похожая — считывание огромного конфига. На самом деле даже иногда быстрее создать объект с нуля, чем заниматься десериализацией. Мы сейчас используем apcu+igbinary, поглядываем на всякие reactphp\icicle\amphp, но вообще есть идея попробовать реализовать это самостоятельно, взяв за основу APCu расширение, пока не очень понятно — можно ли это на самом деле реализовать.
                                  • –2
                                    Так в чём оказалась проблема "слезть с PHP"?
                                    • +4
                                      Потому что это действие не решает ни одной конкретной бизнес задачи.
                                      А с выходом PHP7 желания куда-то дергаться сильно поубавилось, а в RFC PHP7.1 все тоже становится очень приятно.
                                      • –5
                                        А какие у вас бизнес задачи? Например, повышение эффективности процесса разработки является бизнес задачей или нет? А уменьшение багоёмкости? А уменьшение потребления ресурсов?

                                        PHP стал в два раза меньше тормозить, да. Но значит ли это, что он сравнялся по эффективности с компилируемыми языками?
                                        • +2
                                          Откуда у вас такая ненависть к PHP? Да, gcc -O2 быстрее. Но у него есть свои минусы. И и других компилируемых языков они есть. Как есть и у PHP. Просто есть задачи, а есть инструменты их решения. Вы же почему-то решили применять один инструмент ко всем задачам, да ещё и остальным это мнение навязывать.
                                          • –6
                                            А откуда у вас такая любовь к устаревшим языкам типа PHP и C? Для меня просто это уже пройденный этап. Современные компилируемые языки вполне позволяют писать выразительный и быстрый код одновременно.
                                            • +4
                                              Вы делаете утверждения без аргументов и вешаете ярлыки. Кроме этого, вы подменяете понятия: эффективность это не только и не столько скорость работы. PHP не сравнялся с компилируемыми языками по скорости исполнения, но вы говорите об эффективности, а это уже другое, значительно более широкое понятие. Всем этим вы в лучшем случае продемонстрируете свой идеализм и максимализм, а в худшем — очень скромный опыт коммерческой разработки, если не его отсутствие.
                                              Отвечая на ваш вопрос — у меня нет "такой любви" к PHP. У меня любовь к использованию подходящих решений для разных задач. PHP, например, подходит для веб-разработки. Потому что высокая скорость разработки, большое комьюнити, множество готовых решений, и большой рынок разработчиков. При этом, естественно, отдельные части логики могут и должны быть реализованы на более подходящих для этого технологиях. Например, для особо требовательных к производительности компонентов неплохо подходит C или Go.
                                              И, пожалуйста, перестаньте рассказывать сказки про 10-кратное превосходство 1 разработчика на D. Возможно, лично для вас некоторые языки это пройденный этап, но, к сожалению (или к счастью), есть очень много проектов, которые разрабатываются не только вами.
                                        • +3
                                          Но значит ли это, что он сравнялся по эффективности с компилируемыми языками?

                                          Нет конечно, до компилируемых еще далеко (хотя если jit добавят, а его добавят рано или поздно, хотя и уже есть всякие HippyVM и HHVM), но не для такого большого количества проектов производительность языка важнее производительности команды разработчиков. Удобство разработки (перезагрузил страничку и увидел результат), удобство деплоймента (stateless модель)… в целом для большинства проектов php — хороший выбор. Да и те, где производительность важна — опять же узкие места можно написать на всяких go/scala.
                                          • –3
                                            В статье же упомянули проблемы прогрева JIT. Тут разве что AOT помочь может, как в .NET.

                                            А можно сразу писать на чём-то типа Vibe.D, где рекомпиляция проекта проходит за секунды, сейчас пилят балансировщик, который сможет hot-swap, где не требуется установка интерпретатора (выложил бинарник и всё), не нужен прогрев, есть безопасная работа с shared memory, корутины, вебсокеты и прочее, прочее, прочее. А узкие места нет необходимости переписывать на другом языке и потом "дружить" с исходным.
                                            • +1
                                              hidden complexity. Увы, но разработчика который хорошо знает D надо еще поискать. D пока не получил такого распространения, что бы можно было безболезненно брать и делать весь проект только на нем. Даже тот же фэйсбук, в котором сидит Александреску, пилит на D только дев и внутренние тулы (в частности помниться был очень интересный проект статического анализатора для C++ и для ускорения сборки какие-то веселые штуки).

                                              есть безопасная работа с shared memory, корутины, вебсокеты и прочее, прочее, прочее.

                                              Если shared memory в качестве места хранения очень горячих данных — apcu — все есть, все даже относительно безопасно. Корутины — есть в php с версии 5.5 (2012-ый год), websockets — тут проще поднять сервачек на socket-io. Банально дешевле (как с точки зрения написания сервера так и с точки зрения написания клиентов, особенно если надо будет потом мобильные приложеньки пилить). Связать все каким pub/sub на zeromq (опять же готовые решения, все делается очень быстро если не нужно что-то нестандартное, а в рамках MVP оно не надо), и вот вам из коробки готовые солюшены, с подтверждением доставки сообщений, с готовыми реализациями чатиков и т.д.

                                              А узкие места нет необходимости переписывать на другом языке и потом «дружить» с исходным.

                                              YAGNI. Возможно проект, как и тысячи других, просто не доживет до проблем с производительностью и нагрузками. И в этом плане проще взять парочку толковых php разработчиков, запилить на нем MVP и в бой. А то что за сервак придется платить не 20 баксов а 50 — ну так и фиг с ним.

                                              Тут разве что AOT помочь может, как в .NET.

                                              В дискуссиях на php internals большая часть людей именно за AOT. Один из кор контрибьюторов php (ircmaxell) даже грозился сделать это дело в виде расширения хотя бы для кода, использующего сильную динамическую типизацию (информация о типах есть, что еще надо?). Но для этого надо решить еще парочку проблем.
                                              • –5
                                                Разработчика, который хорошо знает PHP тоже поискать придётся ;-) А толковому разработчику разобраться в D не составит особого труда. Особенно JS-разработчику, ведь VibeD похож на NodeJS+node-fibers.

                                                На самом деле это проблема многих руководителей — они ищут разработчиков на определённом языке, вместо того, чтобы искать разработчиков с опытом в определённой области.

                                                apcu насколько я понял — это просто сериализация в общую память. Это не особо эффективно.
                                                Корутин в PHP я не нашёл, только генераторы. Разница в наличие стека у корутин.

                                                php+nodejs+zeromq — ну да, это куда проще, чем несколько строчек на VibeD, любой PHP-шник с завязанными глазами за пару минут сделает :-D
                                          • +1
                                            Я конечно всё понимаю, но зачем писать о скале, будто это что-то сложное? Она же проще пыхи, лишь бы мозги были в правильную сторону развёрнуты (пяток акторов на акке, в слик и морду спрэя наружу = высокопроизводительное stateless [если конечно не совсем деревянный писал] приложение). Я конечно понимаю, что под скалу разрабов днём с огнём не сыщешь, да и тех, что найдёшь отправишь обратно (ЗП пхпшника * 3), но всё же.

                                            Касательно большинства проектов: нынче в моде ресты, а как по мне значительно проще накидать элементарные контроллеры на спринге, сотворить POJO для hibernate и приправить аннотациями (для небыдла: роуты на кэмэле + сервисы в osgi для логики + mybstis с парой запросов + опционально конфиги в зукипере), чем громоздить неведомо что на пыхе (да симфони, да доктрина, да jmsserializer, но по объёму и выразительности кода — беда, это уже не говоря о производительности и масштабируемости).
                                            • +1
                                              Я конечно всё понимаю, но зачем писать о скале, будто это что-то сложное?

                                              Некоторым компаниям у нас в Минске было настолько сложно найти адекватных Scala разработчиков, что они в итоге просто брали PHP разработчиков, жестко их фильтровали по "повернутости мозга" и переучивали на скалу. Причем делалось это все на перспективу.

                                              Если же вы планируете стартовать разработку продукта, скалу брать имеет смысл только если у вас уже есть команда разработчиков на скале. Ибо иначе придется месяца 3-4, за которые можно было бы набросать MVP, тупо потратить на поиск и обучение сотрудников.

                                              Вопрос банальной рациональнотси.

                                              по объёму и выразительности кода — беда

                                              У PHP и Java одна объектная модель. По функционалу Doctrine не сильно уступает Hibernate, Symfony — хороший такой клон Spring-а. А теперь объясните, как это при таком раскладе у PHP может быть все плохо с выразительностью? Вот честно, может быть вы просто видели плохие проекты на PHP? Их не мало, чуть больше чем для Java.

                                              Если уж говорить про Kotlin, то тут про выразительность поверю.

                                              не говоря о производительности и масштабируемости

                                              PHP разработчики дешевле, так что даже если надо будет в два раза больше серверов, до какого-то момента это всеравно будет дешевле чем брать джавистов. А с масштабироемостью у PHP вообще проблем нет — stateless модель выполнения же.

                                              Если огромное множество различных проектов, где я бы не стал брать PHP, с другой стороны, есть куда более огромное количество проектов, где PHP хорошо себе подходит. И больше встает вопрос о культуре разработки. Если разработчики на пыхе тесты пишут, знают что такое рефакторинг и технический долг — то я бы не особо парился. А еще есть ruby, там с культурой разработки в среднем получше. А есть java, где вроде бы все должно быть еще лучше, но практика показывает, что это такой же стериотип как "все php-ники быдло".
                                              • –2
                                                Вопрос банальной рациональнотси.

                                                По коммерческой стороне всё понятно. Я про сторону разрабов и про то, что мне не всегда понятен выбор неглупых разрабов в пользу пыхи.

                                                У PHP и Java одна объектная модель.

                                                Да, но у явы как ни странно сахара больше и кода для какого-нибудь реста писать надо порядочно меньше. Особенно ярко это на уровне сериализации/десериализации из json/xml и валидации всего этого чуда (посмотрите spring-rest (camel + camel-validation, для "небыдла") — поймёте о чём я).

                                                По функционалу Doctrine не сильно уступает Hibernate

                                                Ну не считая "магических интерфейсов" — да. А вот mybatis (запросы пишешь сам, маппятся автоматически) найти для пыхи несколько сложнее.

                                                Вот честно, может быть вы просто видели плохие проекты на PHP?

                                                Видел и плохие и хорошие, да и сам в общем-то писал. И как разработчик скажу — кода на пыхе нужно писать больше. А у ж хороший такой DSL в пыхе — очень большая редкость.

                                                Если уж говорить про Kotlin, то тут про выразительность поверю.

                                                Он кстати не плох, но если знаешь скалу, то не нужен совершенно (ИМХО). Груви с грельсами кстати пхпшнику будет ближе — очень похож на пыху, за счёт динамической типизации, а грельсы очень похожи на симфони.

                                                Если огромное множество различных проектов, где я бы не стал брать PHP, с другой стороны, есть куда более огромное количество проектов, где PHP хорошо себе подходит.

                                                Весь мой спич сводится к тому, что ниша пыха — динамические сайты, а мы живём в мире с одностраничными приложениями. А рест на пыхе — не самая приятная вещь. + в мире микросервисов пыха тоже достаточно ограничена (например хорошо спроектированные микросервисы на яве можно запустить как в одной jvm, так и на разных машинах)

                                                И больше встает вопрос о культуре разработки.

                                                Вот с этим-то в пыхе как раз всё и плохо. Большинство разрабов даже об ООП не слышало, какой там тех.долг, тесты и рефакторинг. Пару раз встречал кадров, которые смотрят на тебя круглыми глазами, когда ты им говоришь о тестах, кодстайле и CI.
                                                Конечно в яве такое тоже встречается, но это в целом редкость. И да я видел говнокод на яве, но по "силе запаха" он не так плох как говнокод на пыхе.

                                                Если разработчики на пыхе тесты пишут, знают что такое рефакторинг и технический долг — то я бы не особо парился.

                                                А я бы сильно удивился, что они до сих пор остаются в гнилом напрочь сообществе. (Хотя быть может это только я Иуда свалил)

                                                стериотип как «все php-ники быдло»

                                                Проблема в том, что этот стереотип процентов на 80 верен, как бы это ни было печально.
                                                • 0
                                                  мне не всегда понятен выбор неглупых разрабов в пользу пыхи.

                                                  Опять же вопрос экономической эффективности. Я на PHP пишу 50% времени, еще 40% — javasript, и еще 10% — всякие баши пайтоны и т.д. Могу на go пописать если нужно будет. Но с большего php решает все мои задачи.

                                                  Неглупый разработчик должен понимать, то язык программирования это всего-лишь инструмент, и становиться мастером молотка и при этом понятия не иметь как с отверткой работать… Надеюсь поняли сравнение.

                                                  А я бы сильно удивился, что они до сих пор остаются в гнилом напрочь сообществе

                                                  На самом деле наблюдается тенденция улучшения в этом плане последние пару лет. Если бы я ее не видел я бы уже давно крест на PHP поставил.
                                                  • –2
                                                    Опять же вопрос экономической эффективности.

                                                    Мы ж вроде про "со стороны разрабов" говорим… Или я просто что-то недопонял?

                                                    На самом деле наблюдается тенденция улучшения в этом плане последние пару лет.

                                                    Да, но для сравнения посмотрите как меняются js, python, java. Вот это тенденция к улучшению (особенно js), а у пыхи как-то с этим печально — да добавили нэймспэйсы с трейтами и тайпхинты, но при этом первым слабо пользуются, второе в принципе не понимают, а на третье частенько приходится забивать из-за отсутствия дженериков (про седьмую версию я просто молчу — это ж надо было додуматься ТАК сделать).
                                                    Да о чём вообще можно говорить если до сих пор живы kohana, codeigniter и т.п.?
                                                    • +1
                                                      КАК сделать?
                                                      • +1
                                                        Я про возвращаемые типы, которые не могут быть null и при этом напрочь отсутствуют дженерики, что убивает на корню возможность это хотя бы в монаду завернуть… Про массивы, итераторы и т.п. (вы думаю меня поняли)
                                                    • +3
                                                      до сих пор живы kohana, codeigniter и т.п.?

                                                      А они живы? Это же трупы.
                                                      • 0
                                                        Вы не поверите...
                                                • +2
                                                  у явы как ни странно сахара больше и кода для какого-нибудь реста писать надо порядочно меньше

                                                  require 'vendor/autoload.php'; // Slim + Eloquent + DB init via composer.json
                                                  $app = new Slim\Slim();
                                                  $app->add(new Slim\Middleware\ContentTypes()); // Parse application/json on request
                                                  $app->contentType('application/json;charset=utf-8'); // Return application/json on response
                                                  $app->get('/v1/users/:id/', function($id) {
                                                      return MyApp\Models\User::finOrFail($id)->toJSON();
                                                  });

                                                  Ещё меньше?

                                                  NB: это ещё я знаю толк в извращениях, скрестил когда-то ежа с ужом, Slim и Eloquent, и с тех пор ленюсь посмотреть на Lumen, для которого Eloquent родная ORM.
                                                • +1
                                                  у явы как ни странно сахара больше и кода для какого-нибудь реста писать надо порядочно меньше

                                                  require 'vendor/autoload.php'; // Slim + Eloquent + db init via composer.json
                                                  $app = new Slim\Slim();
                                                  $app->add(new Slim\Middleware\ContentTypes()); // Parse application/json on request
                                                  $app->contentType('application/json;charset=utf-8'); // Return application/json on response
                                                  $app->get('/v1/user/:id/', function($id) {
                                                      return MyApp\Models\User::finOrFail($id)->toJSON();
                                                  });

                                                  Ещё меньше?

                                                  NB: это я ещё из тех месье, что знают толк в извращениях — натянул Eloquent на Slim вместо Lumen, для которого Eloquent — родная ORM.
                                                  • +1
                                                    Как на счёт принять сложный json и мапнуть его на объект? (Кстати, что будет выведено в случае ошибки? [Правда интересно])

                                                    И после вышеописанного прикрутите сюда валидацию и каплю бизнес-логики.

                                                    P.S. Я ж не про крайности говорил, а про нормальный такой себе флоу.
                                                    P.P.S. Хотя надо признать этот пример впечатляет, особенно после продолжительного хватания за голову от документации Symfony + JMSSerializerBundle + PropertyЧЕГОТОТАМ (уже даже подзабыл)
                                                    • 0
                                                      Как на счёт принять сложный json и мапнуть его на объект?

                                                      Вы про всякие automappers — ну так реализации оных есть и в PHP, хоть и не пользуются особо популярностью. А так есть symfony/serializer которого мне с головой хватает. Однако в последнее время я просто убрал из головы эту дурную идею как "сложный json" в качестве реквеста принимать. У меня обычно это линейная коллекция или просто объект без особой вложенности — именно репрезентация ресурсов. Ничего лишнего. И не потому что сложно мэпить (это не сложно, есть papper, есть symfony/serializer который покрывает все кейсы) а просто потому что в этом смысла нет и я просто считаю это признаком плохо спроектированного API.

                                                      Кстати, что будет выведено в случае ошибки?

                                                      В случае любой ошибки? Можно повесить мидлвэр который будет отлавливать исключения и далее замутить error controller. Обычно это делается при помощи готовых мидлвэров так что можно просто определить хэш-мэпу "тип исключения" => статус код и все.

                                                      И после вышеописанного прикрутите сюда валидацию и каплю бизнес-логики.

                                                      Валидация происходит на уровне пришедшей структуры (у меня вообще через json schema либо стандартным symfony/validation валидирую массивчики). Далее валидация идет на уровне бизнес логики.

                                                      после продолжительного хватания за голову от документации Symfony + JMSSerializerBundle

                                                      А что вы за голову хватались то? Что до JMSSerializer — ну это как бы… не очень штука. Она как минимум недоделана и автор на нее забил года так 2-3 назад. Но люди почемуто досих пор пользуются, хотя уже есть решения получше.
                                                      • 0
                                                        Да я про автомапперы (из ява мира это — JAXB, Jackson, Spray-JSON,… + аннотации для любимого фреймворка).
                                                        Для symfony/serializer нужно порядочно всего объяснять, в том числе опционально через JMS, хотя быть может всё изменилось с последнего момента как я с этим заморачивался.
                                                        Уж не знаю как вы засовываете в лиейную коллекцию объект какой-нибудь сферической в вакууме CRM, но как по мне значительно проще использовать композицию.
                                                        В случае любой ошибки?

                                                        Я про fail от findOrFail.
                                                        Валидация происходит на уровне пришедшей структуры (у меня вообще через json schema либо стандартным symfony/validation валидирую массивчики). Далее валидация идет на уровне бизнес логики.

                                                        Я больше про объём кода для этого необходимый, я прекрасно знаю как валидировать что-либо через symfony/validation и какой для этого нужен объём кода, особенно если хочется изменить формат выводимого сообщения. Это же всё просто призыв к сравнению и обмозгованию.
                                                        А что вы за голову хватались то?

                                                        См. выше.
                                                        • 0
                                                          Для symfony/serializer нужно порядочно всего объяснять

                                                          Все упирается в предоставление информации о типах. В PHP 7.1 должны уже появиться typed-свойства, и может даже дженерики, при таком раскладе информации о типах будет более чем предостаточно для того что бы symfony/serializer просто все замэпил.
                                                          Вот только одно НО. Я категорически против того, что бы что-то мэпило данные на сущности. И Еще более против того, что бы у меня бизнес объекты были анемичны. Потому такие вот штуки у меня если бы и были то работали только на уровне "десериализовать реквест в DTO". А если так — я могу просто его десериализовать в динамическую структурку без плясок с бубном (мы же про скорость разработки говорим).
                                                          в лиейную коллекцию объект какой-нибудь сферической в вакууме CRM

                                                          Можете поподробнее? Причем тут сферический в вакууме CRM, автомэпперы и композиция? Может я вас не понимаю.
                                                          я прекрасно знаю как валидировать что-либо через symfony/validation и какой для этого нужен объём кода

                                                          Вы точно знаете какой объем кода нужен? Ибо я как-то… вообще код не пишу для этого. Ну то есть у меня есть маленькай мидлвэр который берет аннотации для экшена, забирает из него "что должно быть в реквесте" и валидирует. Правда в последнее время я вообще подумываю о том, что надо забить на это дело и валидировать чисто json schema.
                                                          • 0
                                                            Все упирается в предоставление информации о типах

                                                            Увы да, в этом и проблема.
                                                            Я категорически против того, что бы что-то мэпило данные на сущности. И Еще более против того, что бы у меня бизнес объекты были анемичны.

                                                            Вас никто не заставляет пилить DTO, это вполне могут быть нормальные такие сущности, с логикой. (Хоть я и не одобряю такой подход, но это уже вопрос вкуса)
                                                            А если так — я могу просто его десериализовать в динамическую структурку

                                                            Поверьте это ОЧЕНЬ замедляет разработку в итоге.
                                                            Можете поподробнее? Причем тут сферический в вакууме CRM, автомэпперы и композиция? Может я вас не понимаю.

                                                            Представьте себе некоторого сферического клиента, с адресом (да ещё и с регионом), с паспортными данными (да ещё и если только это ФЛ, а есть ещё ЮЛ, т.е. ИП, ЗАО, ООО,..), неким внутренним признаком, неким внутренним Л/Сч. Вот как это запихать в что-то плоское, не используя композицию объектов?
                                                            Вы точно знаете какой объем кода нужен?

                                                            Жутковатая, маловнятная охапка аннотаций, странного вида симфонические конфиги, мидлварь… FOSRest со всеми вытекающими странностями, магией с формами, если вдруг захотелось повалидировать и т.п.
                                                            • 0
                                                              Увы да, в этом и проблема.

                                                              Да как бы нет никаких проблем. Динамическая типизация же. Да и дело не стоит на месте.
                                                              Вы подумайте. Какую задачу решает автомепперы. Они нужны что бы можно было оперировать JSON как нормальной структурой данных. Почему так? Потому что для того, что бы было удобно, нам нужны нормальные объекты. Решает ли автомэппер проблемы мэппинга, когда структура json и целевого объекта сильно различается? Нет. Нужны ли такие штуки тогда, когда мы и так можем просто десериализовать json в динамический объект? Ну видимо нет. Точнее в языках с динамической типизацией в принципе не так много задач где нужно что-то среднее между полноценными DTO и нормальными мэпперами, и тупой работой с JSON в виде нативных структур.
                                                              Вас никто не заставляет пилить DTO, это вполне могут быть нормальные такие сущности,

                                                              Я как раз наоборот говорил — надо заставлять пилить DTO и к состоянию сущностей напрямую мэпперы доступа не должны иметь. И судя по вашим словам тут у нас точка зрения совпадает.
                                                              Поверьте это ОЧЕНЬ замедляет разработку в итоге.

                                                              Не поверю, у меня есть опыт работы с Java и есть опыт работы с PHP. Возможно я неправильно готовил мои структурки, но каких-то проблем в духе "там не то что нужно" я не испытываю, так как на эти структурки потом натравливается dredd который проверяет все на соответствие документации API. То есть я конечно сообщение об ошибке получу не в момент сборки проекта, а при прогоне тестов. А поскольку у меня нет необходимости в процессе сборки что бы тесты прогнать — производительность труда выше для подавляющего большинства сценариев.
                                                              Вот как это запихать в что-то плоское, не используя композицию объектов?

                                                              Для описываемого вами кейса я скорее всего буду дробить все на VO и у меня получится та самая композиция объектов. Но вот JSON скорее всего будет линейный.
                                                              магией с формами, если вдруг захотелось повалидировать и т.п.

                                                              Формами? Формы тут зачем? Ну а у нормальных ребят как? Типа "вместо аннотаций явное определение типов" — ну ок, это скоро и в php можно будет. Не вышло десериализовать потому что какой-то проперти не хватает — вот тебе и валидация.
                                                              На всякий случай уточню. У меня валидация происходит исключительно в контроллере и исключительно данных из реквеста. Дальше контроллеров валидация не нужна в принципе. Ну и из этого тоже следует вывод что symfony/validation тоже не нужен. Если достать информацию о типах не проблема — можно просто обертку над OptionsResolver написать и этого будет более чем достаточно. Но пока приходится явно это все задавать.
                                                              Однако в последнее время я все больше подумываю о том, что бы написать мидлвэрю, которая сравнивает json в запросе с json schema из спеки по API (у меня сначала пишется спека к API а потом уже сама API).
                                                              • 0
                                                                Да как бы нет никаких проблем. Динамическая типизация же. Да и дело не стоит на месте.

                                                                Да как бы есть, и как раз те RFC их решают. И да динамическая типизация — зло (в отличие от выведения типов).
                                                                Про первый RFC: будет круто когда запилят, но просто то, о чём я говорю получится — не будет разницы между груви (например, или котлином) и пыхой, помимо наличия/отсутствия мультитрединга и охапки апачнутых библиотек.
                                                                Про второй: а вот это может и яву уделать с её ублюдским type-erasure, если конечно почеловечески сделают.
                                                                Про третий: а это типичный пример решения проблем, которые сами и создали — "у нас есть трейты, но трейты != интерфейсы, мы сами слабо представляем что мы сотворили и какую проблему этим решаем (читай нам было лень глянуть в сторону скалы), но надо что-то менять"
                                                                Я как раз наоборот говорил — надо заставлять пилить DTO и к состоянию сущностей напрямую мэпперы доступа не должны иметь.

                                                                Да, совпадает, но я не вижу большой проблемы запилить и просто в POJO (я лучше напишу POJO, для русского языка это более политкорретно нежели аналог для PHP) в простых случаях.
                                                                Но вот JSON скорее всего будет линейный.

                                                                Вот ну хоть убейте не могу представить как такое можно провернуть...
                                                                Не поверю, у меня есть опыт работы с Java и есть опыт работы с PHP...

                                                                У меня был опыт где флоу состовлялся из неких методов принимающих Map<String, Object> и возвращающих ровно тоже самое, в итоге всё сводилось к бесконечным проверкам на null и тайпкастам, не самое приятное занятие на свете. В PHP конечно проблем с тайпкастами не будет, но от null не убежишь. Нынче кстати в этом проекте перешли на специализированные RequestContext и мир стал чуточку прекрасней.
                                                                Не вышло десериализовать потому что какой-то проперти не хватает — вот тебе и валидация.

                                                                Ну почти, не считая длин строк, определённых форматов (например, поиск по номеру телефона: разрешены числа, "_" и "%", если присутствует "%", то длина не больше 11 символов, иначе ровно 11 символов), и прочие подобные бизнес-правила.
                                                        • 0
                                                          Это же всё просто призыв к сравнению и обмозгованию.

                                                          Ну так давайте сравнивать и обмозговывать. Я может реально чего-то не знаю, потому был бы рад увидеть какие-то ссылки на пруфы (о том что валидация где-то работает круче или что автомэпперы в принципе нужны). Как никак если что-то где-то сделано лучше и удобнее (особенно в java) то это повод поворовать идей!
                                                          • 0
                                                            Да пожалуйста: google://apache+camel+tutorial, google://spring-rest+tutorial, google://apache+camel+validation, google://scala+spray-routing+example (для тех, кто любит минималистичный DSL для объявления роутинга), ну и остальные технологии, которые я перечислял. Могу собственно ещё сразу приписать сюда примеры кода, но для всего этого многовато будет + для спринга это достачно некомфортно вспоминать из головы и писать прям тут.
                                                    • +1
                                                      Кстати, что будет выведено в случае ошибки?

                                                      Дефолтный middleware от Slim в случае невалидного JSON просто молча обнуляет переменную $env['input'], перенося исходный в переменную $env['input_original']. Можно по этому факту понять, что что-то пошло не так, а можно в несколько строк унаследовать от дефолтного свой middleware, с валидацией и эксепшенами :)

                                                      Бизнес-логика, само собой, отправляется в контроллеры соответствующих сущностей, т.е. понятно, что никто не пишет весь REST инлайн-функциями, последняя строчка вживую выглядит скорее как:
                                                      $app->get('/v1/users/:id/', 'MyApp\Controllers\User::get_by_id');

                                                      Маппинг входящего json в объекты берёт на себя Eloquent, он же обрабатывает ошибки. Скажем PUT (и, кажется, даже PATCH) можно отработать так:
                                                      $app->put('/v1/user/:id/', function($id) {
                                                          return MyApp\Models\User::findOrFail($id)->update($env['input']);
                                                      });

                                                      Я это всё к тому, что PHP (в том числе к моему собственному удивлению) на сегодня эволюционировал в довольно пристойную экосистему, и не надо вот так через губу о нём свысока отзываться :) В активе у него — большая база разработчиков (я думаю, самая большая на сегодня, JS ещё пару лет догонять), удобный в освоении синтаксис "для ленивых" (чего стоит, например, разрешённая запятая после последнего элемента массива), множество вшитых быстрых функций для работы с актуальными для веба данными (всякие array_merge, array_column), отличный менеджер пакетов Composer и репозиторий Packagist для него, в отличие от Node не хранящий в себе всякий однострочный шлак (см. анекдот про left-pad).

                                                      Ну и над всем этим — open-source фреймворки (Laravel, Symfony) и CMS (Drupal и WordPress) с колоссальной накопленной базой кода и готовых решений. Так что если надо сегодня делать что-то, чему надо быстро взлететь, лихорадочно расти и начать приносить доход — я пожелаю удачи любителям Go, Erlang, F# и что там ещё придумали в последние годы, а сам буду набирать команду на PHP.
                                                      • 0
                                                        Роуты пораждают кучу копипасты. Вместо того, чтобы создавать сущности и через адаптер сделать единообразный доступ к ним хоть через http, хоть через websockets, хоть через консоль, хоть через что угодно, вы вручную мапите ссылки на методы.
                                                        Мидлвари порождают кучу лишней работы. Вместо того, чтобы лениво парсить разные части запроса, только когда в этом действительно есть необходимость, вы прогоняете запрос через кучу милдварей, которые что-то с ним делают, чтобы в последней ответить, что-нибудь типа "ресурс не найден, но спасибо, что распарсили куки, распарсили строку запроса, распарсили тело запроса, проверили права и бог весть что там ещё сделали."
                                                        Вот зачем эти глупости было копипастить у ноды я ума не приложу.
                                                        • 0
                                                          «Единообразный подход к сущностям» сработает только в вырожденном случае anemic models / active-record, когда вся бизнес-логика на клиенте, а на сервере — максимум валидация.

                                                          Генератор таких роутов можно написать строк в 10, но это ведь сработает только в очень вырожденных случаях с очень примитивным бэкендом, уж проще тогда какой-нибудь firebase использовать.
                                                          • 0
                                                            • Нет, он прекрасно работает и в случае полноценных моделей.
                                                            • Это первое, что я делаю, берясь за очередной шибко гибкий фреймворк, позволяющий и поощряющий местечковые решения, вместо системных.
                                                        • 0
                                                          Роуты пораждают кучу копипасты.

                                                          Ее пораждает логика в контроллере, который и есть реализацией адаптера к приложению.
                                                          Мидлвари порождают кучу лишней работы.

                                                          А как быть, если решение "есть ресурс или нет" зависит от:
                                                          • Это preflight запрос от CORS?
                                                          • У нас есть If-Modified-Since и надо отдать 304
                                                          • пользователь авторизован? Нет? 401

                                                          Вот зачем эти глупости было копипастить у ноды я ума не приложу.

                                                          Это как бы не у ноды, это как бы обычная пратика, паттерн "адаптер" и "декоратор" в действии. Сильно повышает реюз кода. Надо CORS прикрутить — одна строчка кода + маленькай конфиг и готово.
                                                          • 0
                                                            Ее пораждает логика в контроллере, который и есть реализацией адаптера к приложению.
                                                            Кривая архитектура порождает кривые решения.

                                                            Это preflight запрос от CORS?
                                                            Это обычный OPTIONS запрос.

                                                            У нас есть If-Modified-Since и надо отдать 304
                                                            Чтобы отдать 304 вовсе не нужно генерировать полный ответ.

                                                            пользователь авторизован? Нет? 401
                                                            То, что вы называете авторизацией на самом деле является проверкой прав доступа, котороая не по урлу должна триггериться, а по факту доступа в объектам, требующим проверку прав.

                                                            Это как бы не у ноды, это как бы обычная пратика, паттерн «адаптер» и «декоратор» в действии.
                                                            Паттерн `$app->put('/v1/user/:id/', function($id) {… });` впервые появился в express.js, как и подключение декораторов по кускам урлов.
                                                            • 0
                                                              Это обычный OPTIONS запрос.

                                                              Ок, делигируем вызов дальше, оверхэд = 0.
                                                              Чтобы отдать 304 вовсе не нужно генерировать полный ответ.

                                                              Простите, так в том то и соль. Мидлвэр глянул что с нужной даты ресурс не менялся и отдал ответ. Ну то есть дальше цепочка тригериться не будет.
                                                              То, что вы называете авторизацией

                                                              Вообще-то это аунтентификация по токену. JWT например. Проверка доступа к объектам происходит через воутеры (аналог спринговских) так или иначе. Ну и если бы у нас небыло прав я бы 403-ий статус отдавал, не находите?
                                                              Паттерн `$app->put('/v1/user/:id/', function($id) {… });` впервые появился в express.js

                                                              Ха, паттерн. Это просто приятная и лагоничная API для композиции адаптеров (контроллер = адаптер). Паттерны типа Mediating-controller MVC/MVA были сформированы до появления ноды, и мидлвэры писали ДО. То что хорошую идею с удобной композицией и приятным API начали таскать — ну так это всего-лишь детали реализации. Самой идее уже много лет.
                                                              • 0
                                                                Простите, так в том то и соль. Мидлвэр глянул что с нужной даты ресурс не менялся и отдал ответ. Ну то есть дальше цепочка тригериться не будет.
                                                                Куда это он глянул?

                                                                Это просто приятная и лагоничная API для композиции адаптеров (контроллер = адаптер).
                                                                В проекте чуть сложнее приветмира, это — большая портянка типового кода, а не приятная и лаконичная API.

                                                                Не знаю, почему вы защищаете адаптеры, в то время как я нападаю на роуты. Напомню свой тезис:

                                                                вместо того, чтобы создавать сущности и через адаптер сделать единообразный доступ к ним хоть через http, хоть через websockets, хоть через консоль, хоть через что угодно, вы вручную мапите ссылки на методы.
                                                          • 0
                                                            Это preflight запрос от CORS?
                                                            У нас есть If-Modified-Since и надо отдать 304
                                                            пользователь авторизован? Нет? 401

                                                            Эти вещи решаются написанием отдельно backend, отдельно frontend backend-a и отдельно морда. И тогда ваша бизнесс логика не будет страдать такой ерундой, делите обязанности.
                                                            • 0
                                                              frontend-backend — это что-то страшное :-D
                                                              Типичная схема: client <=> frontend-server <=> backend server <=> dbms
                                                              • 0
                                                                Ну смотрите: client <=> frontend (вкупе с сервером) <=> frontend-backend-а <=> backend (голая бизнес-логика)
                                                                Уж не знаю как корректней назвать "frontend backend-а", но в целом это некий прокси который и берёт на себя всю эту лабуду с авторизацией, кешированием, балансировкой и прочим не связанным с бизнесом
                                                        • 0
                                                          Роуты вообще должны генерироваться из RAML, окститесь. Middleware разменивают условную скорость (50ms или 60ms?) на удобство разработки и читаемость кода, ну и по уму их надо, конечно, подключать в правильном порядке. Вебсокеты, консоли, универсальные адаптеры и прочие разделы из CS 102 оставьте студентам. Люди, делающие реальные проекты и зарабатывающие себе этим на жизнь, только устало улыбнутся.
                                                          • +1
                                                            только устало улыбнутся

                                                            Меня больше улыбает слово "универсальный адаптер". Выглядеть он должен примерно так и код в мессиво он превращает намного быстрее.
                                                            • 0
                                                              То есть по остальным вопросам у нас разногласий не осталось, верно?
                                                              • 0
                                                                смотря по каким. Мне больше api blueprint для генерации контроллеров нравится.
                                                          • 0
                                                            • на удобство разработки и читаемость кода
                                                            • по уму их надо, конечно, подключать в правильном порядке

                                                            Особенно удобно и читаемо, когда в разных местах нужен разный порядок.
                                                            Простите меня, глупого теоретика, что не проникся ещё идеей писать портянки однотипного, гвоздями прибитого к одному единственному протоколу, кода :-)
                                                            • 0
                                                              Простите меня, глупого теоретика, что не проникся ещё идеей писать портянки однотипного, гвоздями прибитого к одному единственному протоколу, кода :-)

                                                              Мне кажется вы как-то не верно понимаете то, о чем говорит SergeAx
                                                              Мидлвэры и тд. это всего-лишь адаптеры к "кдинственному протоколу", они непосредственно к нашему приложению не имеют никакого отношения. Если нам вдруг придет мысль сменить http на amqp например (ну вдруг у нас там микросервисы и все такое) — то как бы не проблема, просто убираем слой адаптеров над http и вешаем слой адаптеров над mq. Причем скорее всего какие-то мидлвэры можно реюзать. Но на код нашего приложения это в любом случае не влияет ни сколечки.
                                                              А профит от мидлвэров — их можно легко и спокойно реюзать, у них нет никакой привязки к контексту использования. По поводу "порядка мидлвэров" — в большинстве случаев он не столь важен, все разруливается либо скоупами либо приоритетами.
                                                          • 0
                                                            Зачем два фронтенда друг за другом? Они же оба думают в терминах клиента, так что их разделение ничего не даёт, а цепочку удлинняет.
                                                            • 0
                                                              Имелось ввиду, что первый сервак с фронтом — просто хранилка ассетов.
                                                              А второй, как раз то, что я описал.
                                                              • 0
                                                                Всё равно не вижу смысла разделять. Разве что, если второй из CDN.
                                                                • 0
                                                                  Попробую объяснить подругому:
                                                                  • фронт + бэк на одном сервере (логическом) — плохо? — Да;
                                                                  • бизнес логика + логика кеширования/шардирования/авторизации на одном сервере (опять-таки логическом) — плохо (в контексте обсуждения)? — Да.


                                                                  Вот мы и получаем 3 логических сервера:
                                                                  1. Раздаёт фронт (что-то наподобие CDN).
                                                                  2. Проксирует запросы к третьему (читай сервер-декоратор для неких не связанных с бизнесом вещей).
                                                                  3. Наш сервак с беком. (бизнес)

                                                                  При этом, естественно, ничего не мешает держать их в пределах одного физического сервера.
                                                                  • 0
                                                                    Назовем вашу схему так:
                                                                    статика + балансировщик -> мидлвэря -> бэкэнд.
                                                      • 0
                                                        $app->get('/v1/users/:id/', 'MyApp\Controllers\User::get_by_id');

                                                        Когда я вижу подобное первая мысль в моей голове: "Пытались сотворить EIP, но не осилили". А предыдущий подход больше всего похож на spray-routing и он был бы не плох, если бы его сделали полноценым DSL-м, но мне так и не удалось его застать.
                                                        Я это всё к тому, что PHP (в том числе к моему собственному удивлению) на сегодня эволюционировал в довольно пристойную экосистему

                                                        Я и не отрицаю, просто подмечаю, что есть инструменты получше, как и то, что "эволюционирует" PHP всё же слишком медленно.
                                                        см. анекдот про left-pad

                                                        С пакагистом будет ровно тоже самое, если ВДРУГ Фабиен выпилит свои компоненты. + я почти уверен, что помимо них есть что-то подобное на что тоже всё завязано.
                                                        я пожелаю удачи любителям Go, Erlang, F#

                                                        Вот кстати с эрлангом вы промахнулись: Р. Он стар и у него своя ниша, где его никто в ближайшем будущем не потеснит. Да и я ж не про "СУПЕРМОДНЫЕНОВЫЕТЕХНОЛОГИИ", а про вполне обкатанные (Java, Scala, Groovy) с тучей инструментов.
                                                        • 0
                                                          С Packagist будет совсем не так. Во-первых там каждый вендор имеет свой неймспейс, и вопросов про права на названия пакетов просто не возникнет. Во-вторых там нет пакетов, обрабатывающих один кошачий чих. Есть обрабатывающие пять-шесть чихов, но другие серьёзные пакеты от них не зависят. Ну и если кто-то что-то оттуда выпилит — никто другой на его место через 10 минут своё не впилит (см. про неймспейс).
                                                • +1
                                                  Что-то комментарий не отправляется. Проверка связи.
                                                  • +1
                                                    Уже третий от вас.
                                                • +1
                                                  Всё это время комментарии добавлялись, но не в ту ветку. Facepalm.
                        • –1
                          Если хочется хранить только read-only объекты между запросами, то можно использовать reactphp, phppm или нечто подобное. Именно shared memory они не дают, но позволяют инициализировать окружение 1 раз и потом просто обрабатывать запросы.
                          • 0
                            то можно использовать reactphp, phppm или нечто подобное.

                            То что вы перечислили не решает проблему хранения read-only объектов, поскольку нам надо будет делать несколько процессов воркеров в любом случае. То есть нам опять же нужно key-value хранилище в shared memory, что предоставляет нам APC user cache. Что до того что вы написали...

                            reactphp — это просто обертка над event loop для php, позволяющая писать приложения в стиле ноды. Я не вижу перспектив у него, поскольку уже есть более удачная реализация amphp на корутинах.

                            php-pm — это реализация SAPI на php для проектов использующих абстракцию от http, со своим управлением процессами и несколькими стратегиями для оного. Основное предназначение — что бы невилировать время бутстраппинга приложения.
                            • 0
                              Основное предназначение — что бы невилировать время бутстраппинга приложения

                              По моему именно эту проблему человек хотел решить тем что у него будет 1 read-only объект в shared memory. Да в подходе php-pm будет несколько копий объекта на каждый процесс, но время на его чтение с диска будет потрачено 1 раз, на запуск сервиса, а не на каждый запрос.

                              По поводу reactphp и amphp.
                              Я пока глубоко не копал amphp, но на первый взгляд они с reactphp похожи, так как amphp так же построен вокруг event loop. Хотя реализация у них разная, основная идея по моему у них схожа.
                              Так что я думаю что они будут развиваться параллельно.
                              • 0
                                По моему именно эту проблему человек хотел решить тем что у него будет 1 read-only объект в shared memory.

                                Изначально человек хотел решить проблему реюза коннекшенов в базе, что бы держать расшаренный пул соединений, или там хэндлеры очередй и т.д. и т.п. Просто данные хранить — для этого apcu есть и не надо из-за этого отказываться от умирающей парадигмы пыха.

                                А проекты типа php-pm — тут нужен уже другой уровень разработчиков, которые понимают что "делать stateful сервисы плохо", или как справляться с сайд эффектами в их коде (мутация состояний и состояние в принципе). А так то что я видел на реальных проектах — такая же умирающая модель выполнения, просто время бутстраппинга воркера (по сути загрузка фреймворков и т.д.) не влияли на время обработки запроса. Профит в этом есть, но не снижение нагрузки. Слишком часто находятся сайд эффекты в вендорных библиотеках и т.д. Для того что бы все было хорошо нужен тотальный контроль за всем кодом, который присуствует в проекте.

                                Так что я думаю что они будут развиваться параллельно.

                                вся соль именно в том что reactphp это тупо event loop, с колбэками и промисами. А amphp — это уже чуть другой уровень, полноценные крутины, почти async/await. По сути reactphp не развивается уже года два. Я бы свое время инвестировал в amphp, поскольку там уже реализовано больше.
              • 0
                Ну положите в Memcached объект типа Closure, например
                • –1
                  В чем проблема то? Serialize и вперед. Другое дело что memcache ничего не хранится постоянно, это не база данных. И расчитывать, что то что вы туда положили, получится забрать нельзя.
                  • +2
                    Ну, расскажите, как Closure в кеш положить. Если в этом нет проблемы, как вы говорите.

                    Например, для массива:

                    echo serialize([1]);

                    мы положим в кеш это

                    a:1:{i:0;i:1;}

                    А теперь попробуйте так:

                    $example = function () use(&$example) {
                        return 1;
                    };
                    
                    if ($example instanceof Closure) {
                        echo serialize($example);
                    }

                    Что мы положим в кеш?
                    • 0
                      Способы-то есть. Либо через eval(), но тогда появляются проблемы со ссылками, либо через Reflection. Есть даже готовые библиотеки: https://github.com/opis/closure, https://github.com/jeremeamia/super_closure. Но, по-моему, сериализация лямбд представляет чисто академический интерес.
                      • 0
                        Далеко нет, имеет отличное применение во всяких job queue. Лично пользуюсь super_closure + jmsjob.
                        • 0
                          Лично моё мнение — сериализации подлежат только данные, но не логика работы с ними. Иначе это слишком много свободы, вопросы по безопасности (eval до добра не доведёт) и скорости работы. Хотя настаивать не буду, на вкус и цвет все фломастеры разные.
                          • 0
                            Все зависит от конкретных задач, если использовать closure как точку входа для асинхронных процессов, а всю логику хранить в моделях, то можно жить.
                    • 0
                      Closure нельзя но можно объект с методом __invoke или через рефлексию как super_closure сделать. Было бы желание )
                      • +1
                        картинка про троллейбус из буханки хлеба
                        • 0
                          Ни кто же не заставляет вас этим пользоваться. Но и говорить, что нет возможности это реализовать — не корректно.
                • +1
                  Начнем с того что смысла ложить Closure в memcached нет вообще никакого. Да и вообще держать "инстансы" в shared memory обычно ведет к диким сайд эффектам, особенно в руках неопытных php разработчиков. С другой стороны opcache и так держит опкоды в shared memory.

                  По поводу хранения ресурсов в shared memory — да как бы не проблема, любой вид IPC в принципе можно организовать. Другой вопрос — а оно вам надо?

                  Лично мне больше нравится подход всяких там php-pm, где можно просто по окончанию запросов прибивать все stateful сервисы (а их должно быть мало), где не нужно рвать коннект к базе (но надо следить за транзакциями и локами и т.д. то есть чистить после себя, а разработчики не очень хорошо с этим дружат, иначе не надо было бы изобретать сборщик мусора).

                  При очень большом желании для PHP можно даже файберы замутить.
                  • –1
                    Вы о чем вообще?

                    Скромно напомню что тред начат с желания того комментатора получить "полноценный" FastCGI. Затем другой автор сказал что FastCGI не нужен, ибо всё можно в кеш засунуть. На что я предложил засунуть в кеш Closure (что невозможно)
                    • 0
                      суть замыканий и анонимных функций в том, что бы они находились в нужном контексте, обычно это какие-то одноразовые штуки. Да и потом, opcache неплохо хэндлит такие штуки и устраняет большую часть оверхэда на рантайм. Хотя с обычными функциями получше будет конечно.

                      Обсуждалось не "половижить все в кэш" а положить все общее в shared memory (если речь о коде, то opcache так и делает), в том числе ресурсы, сокеты, коннекшены к базам и т.д. И работать со всем этим через какую-то красивую API на IPC.

                      А не "положить Closure" в кэш. В этом нет никакой практической пользы. Но да, сериализовать замыкания можно, хоть это и попахивает извращением.
                      • 0
                        "обычно это какие-то одноразовые штуки" — вы просто не умеете их готовить :)
                        Посмотрите хоть на код любого современного приложения на JS — замыкания в них идут сплошняком.

                        Суть замыканий в снижении связанности программы путём функционального DI, без необходимости создавать классы под каждую потребность. Если бы их можно было сериализовать, то можно было сохранять и повторно использовать экземпляры классов с произвольно измененным поведением. Впрочем, считайте как хотите. Не рассчитывайте на дальнейшие ответы.
                        • 0
                          в рамках функционального программирования функция не хранит состояния, то есть чистые функции — как раз таки "одноразовые", у них нет жизненного цикла.

                          Суть замыканий в снижении связанности программы путём функционального DI

                          Это не "суть", это один из вариантов применения. Для DI (dependency inversion) обычно модули все же юзают, а модули можно худо бедно сделать на замыканиях. Но в PHP таким заниматься как-то не очень удобно.
                    • 0
                      Ну и да, по поводу "честного" fast cgi я чуть ниже уже приводил ссылки на различных подходы для достижения этой цели.
                      • 0
                        Господа, ну зачем вы спорите? Те, кто говорят, что настоящий fastcgi для пхп есть и кидают ссылки на гитхаб правы. Просто потому, что PHP — это Turing complete язык и на нём можно написать всё, даже если на гитхабе этого нет. Те, кто говорят, что хотят из коробки быстро бесплатно без регистрации без смс — тоже правы. Потому что они не хотят выбирать из 10 библиотек, думать про каждую из них "а можно ли доверять" и плакать, когда библиотеку перестанут поддерживать.
                        Другое дело, что в PHP принята stateless модель. В этом и плюс, и минус PHP. Если вы хотите stateful и "настоящий fcgi"™ — может, вам не нужен PHP, а нужен кто-то другой?
                        И на всякий случай https://habrahabr.ru/company/badoo/blog/276353/ — там есть доклад про написание демонов на PHP и пара ссылок на статьи на эту тему.
        • 0
          Сделать-то не проблема, смотрите PHPFastCGI, этот товарищ занимается популяризацией этого подхода. Однако, там столько подводных камней с тем, чтобы процесс не умирал, например от "Mysql has gone away", "Remote connection closed" и т.д.

          Если интересно играться, то у меня есть реализация сырого FastCGI-протокола для PHP lisachenko/protocol-fcgi, там можно поиграться с подключением Nginx напрямую к PHP, и да, ваш пример прекрасно будет там работать.
        • +4
          FastCGI — это протокол. Не совсем понятно причём тут stateful/stateless реализации движка.
          Конкретно такого поведения никогда не будет, я уверен.
          Как минимум потому, что уже есть методы, которые позволяют добиться такого же результата без переписывания всего с нуля. Просто храните это значение где-то. В той же shared memory, например.
        • +3
          Вы можете это сделать на reactphp.
        • 0
          https://github.com/reactphp/react — Смотрите Usage
        • 0
          Советую тогда глянуть другие языки где с этим нету проблем (конечно там будут свои проблемы). PHP7 конечно знатный рывок но в сторону старой ниши. т.е. с PHP7 язык большим конкурентом Python/Ruby/Go/Rust/C++ и т.д. не стал.

          ЗЫ statefull модель полезна для WebSockets. В том же Python+Tornado я в одном коде могу писать statefull вебсокет хендлеры и stateless http хендлеры, мне не нужны разные языки/фреймворки для этого. Использовать для хранения информации всякие Redis между состояниями конечно можно, но это медленно и далеко не всегда удобно.
    • +3
      не стоит ждать настоящий fast_cgi?

      Он как бы был и под php5.3, просто увы пока этот подход не пользуется сильно популярностью. На вскидку вот вам посмотреть да потыкать:

      https://github.com/php-pm/php-pm — http сервер на php с управлением процессами-воркерами, совместимый с symfony/http-kernel (может уже и с psr-7). Можно прото невилировать время бутстраппинга приложения и его влияние на время запросов, либо полностью демонизировать приложеньки (но это уже сложно потому как надо учитывать сайд эффекты и чистить контейнер от stateful сервисов после ответа).

      https://github.com/PHPFastCGI — немного более стремный но перспективный проект. Именно реализация fastcgi сервера.

      https://github.com/amphp/aerys — мой любимчик, реализация http+websocket сервера на php7 и корутинах. Опять же можно завернуть в psr-7 и получить что-то типа php-pm но чуть более современное и удобное. Ну и маленькие проектики в принципе можно только на aerys писать (какие-то микросервисы критичные к нагрузкам, если нет возможности это на ноде делать).
  • –4
    > PHP7 действительно готов к продакшену
    К сожалению, нет :(
    • +4
      Специально для минусующих выкладываю скрин/ На скрине 7.0, но в 7.0.3 также повторяется.
      https://habrastorage.org/files/d44/92b/6fd/d4492b6fdd3d4d2cb487283be5ce2029.jpg
      • 0
        А что об этом пишут на https://bugs.php.net/?
        • 0
          Ничего.
          Я всё оттрассировал и нашёл строчку в исходниках, где вываливается segfault, но чтобы написать простой пример, демонстрирующий багу, мне нужна ещё неделя, а у меня этого времени нет.

          Скажу просто — если вы не занимаетесь обработкой данных / инстанцированием объектов на деструкторах, то бояться нечего
          • +14
            Всегда казалось, инстанцирование объектов в деструкторе дурным тоном. Одно неловкое исключение — fatal, порядок вызова неявный, заголовки отправлены, рабочая дирректория может отличаться… Для чего вам понадобилась сложная логика в деструкторе?
          • –1
            Ну не факт, что это вообще баг, а не фича.
            Деструктор может быть вызван языком из исключения, поэтому ни в коем случае не должен допускать исключения сам. Иначе на стэке начинается трэш и угар.
            В С++ это UAB например.
            • +14
              При чём здесь исключения? При чём здесь C++? Ни при каких обстоятельствах ошибка сегментирования в PHP не может являться фичей, как бы там ни было в плюсах.
              • +1
                C++ для примера приведён, как опорная реализация всяких языковых фич. Быстрая, но позволяющая отстрелить себе ногу.
                Когда ту же фичу реализуют в других языках и хотят реализовать это быстро, разрабы очень часто смотрят "а как оно в плюсах сделано".
                При чём здесь исключения: ну, вы не даёте бэктрейс и вообще никаких зацепок, при этом занимаетесь заведомо never-do практиками (инициализация в деструкторе). Поэтому я предположил, что ошибка вызвана исключением в деструкторе, вызванном во время раскрутки стэка во время обработки другого исключения.
                То, что оно не должно падать с сегфолтом — согласен. Но если ваш же багливый код будет падать с fatal error, пользователем вашей программы легче не будет.
                Короче, я предполагаю, что в вашей программе есть намного более жирный баг, чем тот, который имеется в пхп. И винить во всём только свежую пхп — ну, так себе идея.
      • +8
        Скриншот лога не очень помогает. Как минимум, нужен backtrace.
        Как его получить — написано тут: https://bugs.php.net/bugs-generating-backtrace.php
        Я понимаю, что у вас времени нет, но если просто жаловаться на Хабре, то ничего не изменится.
        • +1
          trace у меня есть, у меня минимального примера нет, я выше об этом писал.
          На одну из баг с обратной совместимостью мне ответили, что это фича и исправлять это они не будут. В документации по миграции это тоже не упомянуто.

          В общем, лично я принял решение ждать 7.2-7.3
          • +2
            Есть backtrace — делайте баг-репорт, только предварительно поищите репорт с таким же трэйсом, чтоб не плодить дубли.
            Ждать или делать — ваш выбор.
            • –7
              А тут дело скорее не в конкретном баге, а в том, что он не первый и нет никакой уверенности, что не последний
              • +19
                Почитайте чейнджлог пятой версии http://php.net/ChangeLog-5.php. Релиз состоялся 13 июля 2004 года, а в версиях от 3 марта 2016 года до сих пор фиксят баги. Я вам гарантирую, обнаруженный вами баг — не последний. Подождите хотя бы PHP 28.0, а лучше 29.0.
                • –3
                  Кто-то больше выиграет от экономии ресурсов, кто-то больше проиграет при появлении бага, пользователи php бывают разные. Вероятность появления бага в продукте, только недавно вышедшем на рынок гораздо больше, чем в продукте, которые работает уже несколько лет, но вероятность ниже не значит, что она равно нулю.
                  • 0
                    Баги есть всегда. У любых пользователей php. В пятой версии, в седьмой.
                    Что касается утверждения "Вероятность появления бага в продукте, только недавно вышедшем на рынок гораздо больше, чем в продукте, которые работает уже несколько лет" — оно неверно, начать получать ответ на вопрос "почему" можно с чтения https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D1%82%D0%B5%D0%BD%D1%81%D0%B8%D0%B2%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%BE%D1%82%D0%BA%D0%B0%D0%B7%D0%BE%D0%B2.
                    • +2
                      Удивительно, как можно применять правила для механизмов, т.е. продверженных в первую очередь износу, с ПО, не подверженному износу? У вас так хорошо получается гуглить, думаю что у вас не составит труда опровергнуть свои слова, у меня получилось найти аналогичные графики для ПО за минуту поиска. Они имеют другую форму.
                      • 0
                        Это очень интересно. Не могли бы вы показать эти графики? А если в составе какой-то статьи, где эти графики объясняются — так вообще прекрасно. Мне вот удалось быстро найти http://www.1manteam.com/index.php/2011/01/facebooks-developer-love-initiative-3-months-later/ — что больше похоже на выводы обычной теории надёжности, чем на ваши утверждения.
                        ПО подвержено износу, только в качестве износа выступает усложнение и изменения этого ПО с течением времени. Кроме того, количество ошибок определяется не только износом, иначе бы в нулевой момент времени оно было бы нулём.
                        • 0
                          А вы были правы. Действительно, довольно быстро гуглится — картинки по запросу "software failure rate".
                          И насчёт применимости правил — вас не смущает, что люди, которые вас окружают, голосуют на выборах в соответствии с распределением Гаусса, а на мобильные телефоны звонят потоком Пуассона?
                • 0
                  Ну вот и сравните кол-во багов а-ля segfault в php 5 до версии 5.3 и после.
                  • 0
                    Сравнил:
                    ➜ ~ wget -qO — http://php.net/ChangeLog-5.php | grep -iEc 'segfault|segmentation fault'
                    476
                    ➜ ~ wget -qO — http://php.net/ChangeLog-5.php | grep -in 'version 5.3.0'
                    10084:Version 5.3.0
                    ➜ ~ wget -qO — http://php.net/ChangeLog-5.php | head -n 10084 | grep -icE 'segfault|segmentation fault'
                    288
                    Правда, сравнение такое некорректно, потому что есть несколько веток развития пятой версии — 5.6 и 5.5, складывать количество сегфолтов неправильно. Кроме того, сегфолты часто происходят в расширениях, и тут надо смотреть в каких именно и насколько они часто используются.
                    Вы бы лучше сами привели статистику, которую посчитали. И выводы, которые сделали.
                    • 0
                      Кстати, даже чисто визуально по http://php.net/ChangeLog-5.php видно, что число исправляемых ошибок в 5.6 намного выше, чем в 5.5, а уж 5.4 там встречается еще реже.
                      • +1
                        Ага. 5.4 просто больше не поддерживают, вышел последний 5.4.45 и всё. По вашей логике надо четвёртую версию использовать, там последний раз ошибки исправляли в 2008 году.
                        • –2
                          Почему вы ограничиваете моё логику своими домыслами? Безусловно лучше иметь поддерживаемую версию.
                          Моя логика была проста — есть задачи, где цена ошибки очень высока, в таких задача, и только в таких, выгоднее использовать поддерживаемую версию где меньше шансов на ошибку, чем поддерживаемую версию с высокими шансами на ошибку, потому что цена ошибки, повторюсь, очень высока. Да, можно добавить сарказма в ответ и попыток подловить на чем-то, но смысл? Думаю, что вы меня поняли.
  • 0
    А объясните мне, пожалуйста, такой простой вопрос — почему при большом количестве проектов JIT для PHP с больших компаниях ни один из них не продвигали upstream?
    И почему вы сами не сделали его, раз у вас такая большая ферма серверов и большая зависимость?
    • +2
      Во-первых, очевидно, что никому это не надо настолько сильно, чтоб взяться за разработку.
      Во-вторых, почему вы решили, что это какая-то серебряная пуля?
      В Zend заимплементили JIT, поэкспериментировали и убрали пока в сторону:
      http://marc.info/?l=php-internals&m=142503908926686
      TL;DR: первое выполнение скрипта — вплоть до нескольких минут, второе — выигрыша особого не даёт.
      • 0
        Правильно ли я понял, что в итоге заброшенный JIT в Zend был сделан на LLVM? (Который не очень хорошо оптимизирован для JIT сценария и добавляет большой overhead...)
    • +1
      Потому что "сделать для себя" и "продвинуть в апстрим" — примерно равные по ресурсоёмкости задачи. Грубо, если один год девелопили, другой год будете двигать в апстрим. Мы это на своей шкуре несколько раз почувствовали и для не таких больших проектов. А почему не сделали сами — мы всё-таки слишком маленькие, чтобы такими задачами системно заниматься.
      • +2
        Понятно, что первый пуш в апстрим идет долго первый раз (в зависимости от сообщества и его лидера, конечно, в linux-kernel это будет совсем больно, в llvm — одно удовольствие). Но никому и не обещали что это будет легко. Но это только первый раз, со временем, с ростом репутации push в upstream может стать довольно быстрым мероприятием.

        Дело тут в политическом решении Если вы строите свой бизнес на наборе open-source продуктов, если вы инвестировали свою экспертизу и сильно развили эти продукты в нужном вам направлении, то вашей платой и благодарностью сообществу и авторам этих продуктов будет время потраченное на проталкивание этих наработок обратно в upstream.

        Вне зависимости от того большая вы контора или маленькая, проталкивание своих наработок обратно в продукт, запуск тестовых ботов на своих железках, написание тестов, и любая другая релевантная активность, измеряемая в человеко- и машино-часах — это возврат долга за использование изначально бесплатного продукта.

        Хотя, конечно, вам самим решать.
        • +1
          К сожалению многие не разделяют этого мнения и воспринимают свои патчи в оупенсорс как конкурентное преимущество и соответственно не просто не проталкивают в апстрим, но даже и не открывают изменения.
        • 0
          Дело не в политическом решении, я повторяю, это исключительно проблема структурная: Фейсбуку проще на всех покласть и сделать своими силами под себя. Ну и у нас никогда не было своего JIT, а это очень ресурсоёмкий проект — так что почему мы не сделали JIT — ну потому что очевидно это очень непростая задача, это человеко-годы, это может позволить себе компания размером в тысячу человек и больше. Насчёт платы и благодарности: ну мы-то отдаём до чёрта всего, см. http://github.com/badoo. Но open source проекты неэффективны c точки зрения бизнеса. Если Вы вдруг не знаете, мы пушили в апстрим php-fpm, это был просто сторонний патч когда-то, Андрея Нигматулина, нашего программиста. Мы запилили проект по исправлению косяка со вложенными локами в MySQL, его года три назад делал лид Тарантула Костя Осипов, так на исправление ушла пара недель, а на проталкиваение в апстрим ораклу, перконе и марии — несколько лет. Так что мы готовы тратить время, не вопрос, но мы не готовы убиваться, потому что мы — маленькие.
  • +1
    Спасибо за статью, как раз сейчас тоже переходим на PHP7. Хотел бы уточнить каким профайлером и дебаггером пользуетесь? XDebug? Спасибо
    • +1
      дебаггер XDebug, профайлер XHProf
  • 0
    Сарой Гоулман (англ. Sara Golemon), которая сейчас работает в Facebook, в том числе и над HHVM

    уже нет https://twitter.com/SaraMG/status/702264356348624896



    А вцелом повторюсь то, что написал в твиттере. Выложить на гитхаб — это одно, а сделать проект доступным сообществу — совершенно другое. Понятно, что скорее всего какие-то фишки из Go AOP вам не подошли, но вместо того чтобы делать ещё +1 решение для софт мокинга (AspectMock, Kahlan) можно было бы реально поделиться своими наработками, улучшить, и сделать более-менее универсальным существующий опенсорс движок. SoftMocks выглядит заманчиво, но будет ли кто-то им будет пользоваться за пределами Badoo...
  • +2
    О, и ещё вопросик: рассматривали ли вы Zephir в качестве инструмента для написания расширений?
    • 0
      Рассматривали, пока что не используем.
      • 0
        Руки не дошли? Вылезли ли какие-то проблемы? Текущий контекст (в виде наработанного кода) мешает? Другое?
        • 0
          У нас не так часто появляется необходимость в новых расширениях. Навскидку за последний год это был только tarantool 1.6, нецелесообразно было писать его на Зефире с нуля.
        • 0
          Я бы сказал, что больше всего "пугает" сырость и туманность перспектив. Не забывайте, что Badoo — это уже проект с 10-летней историей, и мы должны быть уверены, что те инструменты, которые мы используем, не будут заброшены авторами в обозримом будущем. Или же нам нужно будет у себя развить экспертизу по тому, как работает зефир и научиться самому его поддерживать и разрабатывать. Пока что оно не стоит того.
  • +2
    У Дмитрия Зеновича есть акк: dzenovich
  • +1
    Пытаемся перейти на php7 но libxl + php_excel стабильно падают в core dump (пересобраны, ессно). Починить не можем. Плачем.
    • +1
      Reproduce case внятный есть? Если есть — пришли мне, плз.
      • 0
        первая сложность в том, что код надо брать вот с этого pull request, так как master не собирается вообще
        https://github.com/iliaal/php_excel/pull/114 и я не уверен насколько это правильно.

        вторая сложность в том, что простые примеры работают на ура, а на реальных данных/запросах — падают 100%. постараюсь за выходные написать минимальный Reproduce case и отписаться.
      • +1
        Тестирование показало что все просто до не могу ))) Оно падет на проверке лицензии.

        Если убрать ключ — в trial mode все ок.

        А с реальным ключем падает вот так еще на создании обьекта:

        <?php
        $licenseName = 'Oleksandr Voytsekhovskyy';
        $licenseKey = 'linux-somekey';

        $a = new ExcelBook($licenseName, $licenseKey, true);

        реальный ключ готов выслать в приват
        • +1
          Как я понимаю имеется лицушная версия библиотеки. У неё нет поддержки?
          • +1
            Креш происходит на стороне модуля php, насколько вижу я
      • +2
        еще 2 часа тестирования показали что если сделать так

        [excel]
        excel.license_name="Oleksandr Voytsekhovskyy"
        excel.license_key="linux-somekey"
        excel.skip_empty=1


        new ExcelBook(null, null, true);

        то все работает
        • 0
          Как минимум в одном месте в патче не до конца исправлены типы, вот фикс:
          https://gist.github.com/391f7728dddeecc8cc34

          А вообще, это всё дебаг по телефону. Мне надо видеть, иметь возможность запустить это всё.
          Ну, и совсем неясно почему это всё обсуждается в этом топике =)
          • 0
            могу дать доступ на тестовый сервер
  • +3
    А почему у вас php-fpm на tcp, а не на сокетах? Неужели очереди в сокеты длиннее 0xFFFF бывают?
    • 0
      А расскажите, почему unix-сокет будет лучше?
      • 0
        Скрижали гласят, что сокеты быстрее. Но я, если честно, давно не измерял, и вот fisher пишет, что скрижали слегка устареть могли.
        • +1
          И да, и нет. На самом деле, в разных кластерах разные схемы балансировки нагрузки, и в одной из схем есть небольшое количество nginx на одних машинах, и большое количетво php-fpm на других. Собственно, это ответ на вопрос, почему AF_INET.
      • +1
        unix-сокет не требует для работы стэка ip протокола, который в данном случае и есть оверхед.
        • 0
          Спасибо, тут уже выяснили, что разница есть, хотя и небольшая, заметная только под очень большой нагрузкой.
          Покажите лучше графики количества багов в ПО в зависимости от времени, которые, как вы упоминали выше в комментариях, вам удалось найти за минуту. Мне очень интересна эта тема.
          • 0
            Например в на этих слайдах есть пример графики для софта и для железа.
            • 0
              Вы же читали все слайды, правда? График для софта справедлив при условии, что в софт не вносится никаких изменений, кроме исправлений ошибок. Мы изначально говорили про эволюцию PHP, в который изменения вносятся постоянно. Запрос, по которому надо гуглить, я уже писал выше.
              • 0
                Читал, разумеется, как раз описанная мною ситуация, что кому-то важнее иметь меньше шансов возникновения ошибок/фаталок, и в этом случае берется версия софта, в которой нет нововведений, есть только исправление ошибок, и для такого софта как раз такой график, а не пила, как для более новых версий, и разумеется график для железа не подходит для софта, так ведь?
    • –4
      когда-то на старых ядрах это типа может и отличалась но щас вроде разницы никакой
      • +4
        Фиш, не хочу тебя разочаровывать, но это не совсем так. В целом, нет причин, по которым TCP мог бы вообще когда-нибудь работать быстрее, чем unix socket. В качестве примера можно привести бенчмарк редиса: http://redis.io/topics/benchmarks

        $ numactl -C 6 ./redis-benchmark -q -n 100000 -s /tmp/redis.sock -d 256
        PING (inline): 200803.22 requests per second
        PING: 200803.22 requests per second
        MSET (10 keys): 78064.01 requests per second

        vs.

        $ numactl -C 6 ./redis-benchmark -q -n 100000 -d 256
        PING (inline): 145137.88 requests per second
        PING: 144717.80 requests per second
        MSET (10 keys): 65487.89 requests per second
        • –2
          а я не говорил, что "TCP мог бы вообще когда-нибудь работать быстрее, чем unix socket". я говорил, что теоретически могло быть наоборот на старых ядрах, unix сокеты могли быть быстрее tcp, ну и я тоже что-то когда-то слышал про скрижали, которые это говорили, но вроде давно уже без разницы. твой эксперимент это лишь подтверждает. выпей порто :)
    • +2
      Если перефразировать AntonStepanenko, то TCP используется потому, что он гибче — мы в некоторых случаях мы ходим напрямую на FPM
  • –4
    Сколько RPS оно выдает с одного ядра? На каком-нибудь Go этот показатель примерно 10k. Может можно еще 300 серверов освободить? :)
    • +2
      Вот только цена разработки (портирования) будет выше и вряд ли окупится когда либо )
    • +5
      Все-таки, справедливости ради, хотел бы сказать, что 10k rps на одно ядро на golang получить можно только в том случае, когда логика обработчика очень простая и не делает сотен запросов в другие сервисы по сложным условиям. В большинстве случаев на PHP пишут в том числе из-за сложности бизнес-логики, и на golang это все переводить будет нецелесообразно. Тем не менее, какие-то самые нагруженные части наверняка можно перевести на golang хотя бы из соображений низкого latency.
  • 0
    О своём опыте: перевёл пару проектов на WordPress, довольно плотно обвешанных плагинами и темами, под PHP7, разница в производительности впечатляет. 10-долларовый дроплет DigitalOcean отдаёт страницы за ~500ms (при правильной сборке и настройке nginx). Правда приходится регулярно ловить incompatibility issues в чужом коде. Особенно люто валятся всякие indirect references на функции или методы классов.
    • +1
      500ms??? У нас на 5-долларовой ноде DO простой сервис на php5.6 c Lumen отдает по 50-70мс
      • +1
        Сравнивать Wordpress и Lumen это как сравнивать тёплое с мягким.
        • +3
          Я не то что сравнивал, скорее констатирую и удивляюсь разнице.
          Я с wordpress плотно не работал, но все же кажется, что 500ms на 7 это слишком много. Что-то с wordpress не то
          • +1
            Для популярных CMS, да еще и "плотно обвешанных плагинами" это в принципе нормальный показатель. Не говоря уже о том, что сравнивать старую коробку и "простой сервис" совсем не корректно.
      • +1
        Вы большие молодцы, поздравляю вас. Но с развесистыми проектами на WP вы, вероятно, дела не имели.
  • 0
    Самое же прекрасное, что вы почему-то не упомянули, что в PHP7 нельзя использовать в качестве имени класса Error. А именно так назвать класс, унаследованный от Exception в PHP5, считает своим долгом в среднем каждый пятый разраб.
    • +3
      использование зарезервированных имен классов

      Вам не понравилось, что там не указано Error? На мой взгляд нет смысла заниматься копированием документации и migration guide, статья немного о другом.
      • 0
        Мне статья вообще очень понравилась, не хотелось бы, чтобы у вас сложилось обратное мнение. Так что просто просто поделился опытом. Хотя вот у коллег ниже статистика другая.
    • +1
      Я сейчас, для интереса, посмотрел кол-во коммитеров в проект, которым я руковожу (полмиллиона строк кода). 32 человека. Ни один не назвал класс ошибок «Error». Я сломал вашу статистику! :)
      • +1
        У нас кстати были и Error и String и прочие :).
        • +2
          «String» у нас тоже был :)
  • 0
    Модификатор 'e' в регулярках, а также конструктор в виде названия класса уже давно deprecated. Или вы раньше просто подавляли такие ошибки?
    • +1
      Модификатор e приводит к ошибке уровня E_DEPRECATED начиная с PHP 5.5.0. Во-первых, не сказать, что это очень давно. Во-вторых, по-умолчанию E_DEPRECATED отключены, так что я бы не сказал, что прям подавляли, но да, какое-то время просто не уделяли этому внимания.
      Что касается конструкторов — вы ничего не путаете? Они не приводят к ошибкам. Единственная особенность — начиная с 5.3.3 у классов внутри неймспейса конструктор должен называться __construct, иначе он просто не будет вызван при создании объекта.
      • 0
        Да, про конструктор ошибся. Просто так давно не встречал старых конструкторов, что был уверен, что deprecated
      • 0
        На самом деле конструкторы совпадающие с названием класса не рекомендуется использовать еще со времен выхода PHP 5.0 :) (да и неудобны они в живых проектах из-за parent::).

        For backwards compatibility with PHP 3 and 4, if PHP cannot find a __construct() function for a given class, and the class did not inherit one from a parent class, it will search for the old-style constructor function, by the name of the class.
  • +2
    Мнение о том, что узким местом в веб-проектах является база данных — одно из самых распространенных заблуждений. Хорошо спроектированная система сбалансирована — при увеличении входной нагрузки удар держат все части системы, а при превышении пороговых значений тормозить начинает все: и процессор, и сетевая часть, а не только диски на базах.

    Таким образом, процессорное время сократилось в 2 раза, что улучшило общее время ответа примерно на 40%, так как некоторая часть времени при обработке запроса тратится на общение с базами и демонами, и с переходом на PHP7 эта часть никак не ускоряется, что ожидаемо.

    Это прекрасно.
    • –5
      Да, и база — узкое место, потому как stateless инстансы приложений легко масштабируются увеличением их числа. А вот для базы важна консистентность, её так просто не отмасштабируешь.
    • 0
      Простите, а в чём вы видите несоответствие? Процессорное время сократилось в 2 раза, то есть на 50%. Если бы общения с базой не было — то и время ответа сократилось бы на 50%. Но общение с базой, очевидно есть, и оно не является узким местом, то есть занимает не так много времени — поэтому общее время ответа сократилось на 40%.
      • –8
        Видимо в том, что 80% времени тратилось на работу PHP, а на ожидание СУБД — жалкие 20%, что не очень похоже на сбалансированность. Скорее на существенный перекос в сторону PHP.
        • +3
          Вы, к сожалению, путаете сбалансированность и равномерность распределения нагрузки. Сбалансированность не означает, что каждый компонент системы занимает одинаковое время. Сбалансированность означает то, что написано в статье: "при увеличении входной нагрузки удар держат все части системы" и далее по тексту.
          • –7
            Не путаю. В данном случае эти два понятия эквивалентны, ибо узкое место — это то, оптимизация чего даёт наибольший эффект. Двукратная оптимизация PHP дала 40% прироста общей производительности. Аналогичная двукратная оптимизация работы СУБД дала бы не более 10%.
            • +3
              Вы, видимо, слабо представляете себе классические подходы к проектированию подобных систем. Двухкратная оптимизация PHP даёт 40% прирост производительности в кластере бекенда мобильных приложений потому, что наиболее тяжеловесные операции, нагружающие базу и демоны, вынесены в асинхронный процессинг, которым занимается упомянутое в статье облако. По этой же причине база занимает небольшой процент времени. И это очень хорошо. Потому что это упрощает масштабируемость кластера. Как вы сами заметили, базу масштабировать сложнее. Поэтому выгодно иметь такую архитектуру, где с увеличением трафика нужно в первую очередь просто нарастить мощности cpu, а не базы. Важно ответить пользователю быстро — именно поэтому при синхронном ответе всегда стремятся снизить количество взаимодействий со внешними по отношению к PHP сервисами — а асинхронно уже можно потратить 80% времени на работу с базой.
              • –5
                Если учесть, что большинство запросов в подобных сервисах являются чтениями, то не понятно, что вы там такое запускаете асинхронное на каждый запрос :-) Но даже если предположить, что каждый лайк запускал в СУБД пересчёт числа пи до последнего знака, что создавало существенную задержку ответа, поэтому было решено давать ответ пользователю не дожидаясь завершения операции, то да, было узкое место в расчёте числа пи, стало узкое место в интерполяции шаблонов в PHP, а нагрузка на сервера не поменялась.
                • –6
                  Да, и асинхронные ответы — это не оптимизация, а фикция :-)
                  • 0
                    Я ничего не говорил про асинхронные ответы. Ответ пользователю синхронный. Только часть операций выполняется уже после того, как пользователь получил ответ.
                    • 0
                      Это и называется асинхронный ответ, то есть не синхронизированный с вызванной запросом операцией :-) Но это мы ушли в терминологический спор. Как этот приём ни называй, а оптимизацией он не является.
                      • +3
                        Теперь становится понятнее. Вы считаете, что оптимизация — это исключительно ускорение работы системы. На самом деле оптимизация — это улучшение эффективности системы, совершенно необязательно являющееся сокращением времени работы. Иными словами — сделать лучше можно не только заставив код работать быстрее. Вам, как архитектору, это должно быть известно.
                        • –4
                          Разумеется, лучшая оптимизация — не делать то, что можно не делать :-)
                          • 0
                            Вы судите об оптимизации по тому, в чём она заключалась. А лучше судить по тому, что она дала.
                            • –5
                              А что она дала? Видимость скорости? Если клиенту не интересно завершилась ли операция, то он может и не дожидаться ответа, а сразу дропнуть соединение после отправки данных. :-)
                              • 0
                                Что она дала — указано в заголовке статьи и в её завершающей части. Вы ведь читали статью?
                                • –3
                                  Похоже вы совсем потеряли нить дискуссии :-)
                • +2
                  У вас неверное представление о том, что такое узкое место. Вы почему-то считаете, что компонент, занимающий по времени больше остальных, это и есть узкое место, которое следует оптимизировать. Именно так появляются так называемые premature optimization mistakes. Вы отталкиваетесь от того, что можно оптимизировать. Следует отталкиваться от того, что нужно оптимизировать. Что сделает приложение быстрее для пользователя. Не "теперь вместо 10 микросекунд мы рендерим щаблон за 2, 5x ускорение!", а быстрее для пользователя. Что сэкономит деньги. Не "мы заплатили разработчикам 20 миллионов зарплаты за год, чтобы они на 10% ускорили код, который работает на 10 серверах", а экономически выгодные решения.
                  Действительно, разделив обработку запроса на синхронную и асинхронную часть, не получится выиграть в суммарной нагрузке. Более того, поступив так, вы проиграете в нагрузке, потому что появятся накладные расходы на эту самую асинхронность. Но вы выиграете в гибкости, в масштабировании, в надёжности и во времени ответа.
                  И было бы очень интересно узнать, что такое интерполяция шаблонов? Это по имеющимся шаблону главной и шаблону профиля вычислить шаблон страницы поиска?
                  • –4
                    Вы почему-то считаете, что компонент, занимающий по времени больше остальных, это и есть узкое место, которое следует оптимизировать. Именно так появляются так называемые premature optimization mistakes. Вы отталкиваетесь от того, что можно оптимизировать. Следует отталкиваться от того, что нужно оптимизировать. Что сделает приложение быстрее для пользователя.
                    Так оптимизация того, что занимает больше всего времени и сделает приложение быстрее для пользователя. И далее по тексту вы подтверждаете мои слова. :-D

                    Сказать, что покрасил забор, хотя сам за этот забор ещё не брался — это не оптимизация скорости покраски забора. Это ложь ради показателей. Иногда она необходима. Например, чтобы соединение не таймаутилось или чтобы не исчерпать ограничение на число одновременных соединений… Но в этом случае следует понимать, что время ответа перестаёт показывать что-либо осмысленное. Оно даже может равняться нулю. Поэтому замерять нужно уже не время ответа, а время завершения вызванных запросом операций. В случае синхронного ответа эти два показателя эквивалентны. В случае асинхронного — нет.

                    en.wikipedia.org/wiki/String_interpolation
                    • +4
                      Замерять нужно то, что важно для пользователя. Очень много сценариев, где гораздо важнее отправить команду на выполнение вычислительно тяжелой или физически долгой задачи и дать пользователю возможность продолжить работу, не дожидаясь окончания задачи. Да, общее время будет дольше. Да, могут потребоваться дополнительные механизмы отслеживания статуса задач и/или уведомления об их изменении, а то и механизмы управления задачами типа очереди, отмены, приостановки и возобновления. Но пользователь будет счастлив, что ему не нужно ждать завершения выполнения одной задачи, чтобы начать другую или просто выключить комп.
                      • –3
                        Он и так может не ждать, если ему не интересен результат ;-)
                        • +1
                          Представьте себе, полно кейсов, где пользователю не важно даже получился результат или задача свалилась с ошибкой. Банальное техническое логирование — зачем пользователю ждать окончания записи в логи? А если не получилось записать, ему 500 выдавать? Или ресайзинг изображений при загрузке для оптимизации трафика сервера. Пользователю оно надо ждать окончания ресайзинга? Если что-то пошло не так при ресайзинге, ему надо повторно загружать оригинал?
                          • –5
                            О том и речь, что если пользователю не интересно, он всегда может дропнуть соединение после отправки данных. Это именно пользователю решать хочет он дождаться конца или нет. А вот если пользователь хочет дождаться конца, а сервер его обманул и ответил не дожидаясь, то какой прок от такой метрики? Что она показывает? Время создания асинхронной задачи?
                            • 0
                              Как писали выше пользователю точно не нужно ждать пока ошибка запишется в лог файл.
                              • 0
                                Вы так говорите, будто это долго.
                            • 0
                              А вот если пользователь хочет дождаться конца, а сервер его обманул и ответил не дожидаясь, то какой прок от такой метрики?

                              Вы о каких-то сферических в вакууме пользователях рассуждаете, для которых имеет ценность сидеть и ждать чего-то.

                              Пример с видео на ютубе более показательный. Залилось, могли быть ошибки, все хранится в очереди, когда закончится — не известно. Пользователю надо только файл залить, а когда там его full hd запроцессится ему особо не интересно.
                              • –3
                                Вообще-то очень даже интересно. Он же его не просто так заливает. И очень бесит, когда видео вроде как залилось, а посмотреть его нельзя или можно, но лишь в убогом качестве. Пользователя интересует не когда видео будет залито на сервер, а когда его можно будет нормально смотреть с сервера.
                                • 0
                                  Разница синхронной загрузки с асинхронной при больших объёмах данных на грани погрешности, но при синхронной пользователь будет вынужден ждать ещё и окончания обработки, которая может и фэйлом завершиться. А ему самому обработка особо и не нужна — у него оригинал есть. В редких случаях ему самому нужна обработка, чаще кто-то другой ждёт, если вообще ждёт.
                                  • 0
                                    Видео на ютуб закачивают не для того, чтобы посмотреть, а для того, чтобы поделиться.
                                    • 0
                                      Ну так делитесь, от того ценность асинхронной загрузки для пользователя выше. Он может быстро залить видос, скинуть ссылку, а лицезреть видяшки в паршивом качестве будут уже те, с кем поделились. А через пол часика уже и нормальное качество подтянется.
                                      • –2
                                        Получить ссылку можно и ещё до закачки файла, но зачем? Чтобы отвечать на тысячу вопросов "почему у меня не играет?" да "чего качество такое лажовое?"?
                                    • –1
                                      И именно поэтому пользователю нет нужды ждать окончания обработки — файл отправил и может заниматься другими делами.
                                      • –2
                                        А иначе он не может заниматься своими делами?
  • –5
    У вас же обычный дэйтинг-вымогатель. Чем таким важным занимаются эти 3 миллиона строк кода? Ну и не понятно стремление держаться за PHP, который требует ферму из 600 серверов и ораву кодеров. Давно бы уже распилили на микросервисы, да начали переводить их на что-то компилируемое.
  • +3
    Правильно ли я вас понял? Сначала вы называете узким местом базу, а потом предлагаете избавиться от оравы кодеров и переписать 3 млн. рабочего, отлаженного и оптимизированного кода с PHP на мифический компилируемый, который-то и решит все проблемы? Я просто уточнить...
    • –13
      То, что узким местом является база, не означает, что куча денег не вылетает в трубу из-за использования php ;-)

      Касательно "рабочего, отлаженного и оптимизированного кода" не буду повторяться:

      Чем больше кода, тем больше в нём ошибок. Более того, чем больше кода, тем больше процент этих ошибок. Так что если вы видите огромный зрелый фреймворк, то можете быть уверенными, что на отладку таких объёмов кода была потрачена уйма человекочасов. И ещё уйму предстоит потратить, как на существующие ещё не замеченные баги, так и на баги, привносимые новыми фичами и рефакторингами. И пусть вас не вводит в заблуждение «100% покрытия тестами» или «команда высококлассных специалистов с десятилетним опытом» — багов точно нет лишь в пустом файле. Сложность поддержки кода растёт нелинейно по мере его разрастания. Развитие фреймворка/библиотеки/приложения замедляется, пока совсем не вырождается в бесконечное латание дыр, без существенных улучшений, но требующее постоянное увеличение штата.

      Кроме как копипастой и костылями я не знаю чем можно забить 3 миллиона строк для этого не хитрого сервиса.

      Конкретно, я бы предложил язык D, в котором и метапрограммирование есть из коробки, а не в виде отваливающегося расширения, и статическая типизация с автоматическим выведением типов, и динамические типы, и многопоточность, и сборщик мусора, и перегрузка операторов, и удобная стандартная библиотека и ещё много всего, чего либо нет в PHP (например, ленивых параметров), либо только-только созрели ввести (например, строки, хранящие свою длину).
      • +7
        Перейти на D, который знают 1.5 человека? Нехитрый сервис? Серьезно?
        • –12
          Эти полтора человека стоят 15 пхпыхеров, которые без устали строчат шаблонный код. Есть у меня смутное подозрение, что пресловутые 2 релиза в день — это хотфиксы на хотфиксы.

          Ну а что там хитрого? Я весь во внимании.
          • +5
            Простите, но вы очень примитивно рассуждаете.

            Эти полтора человека стоят 15 пхпыхеров, которые без устали строчат шаблонный код. Есть у меня смутное подозрение, что пресловутые 2 релиза в день — это хотфиксы на хотфиксы.

            Оценивать качество и возможности разработки продукта разработчиком по тому на каком языке он пишет — совершенно неправильно, это оценивается его знаниями, опытом, а язык программирования выступает исключительно инструментом, да, язык может обладать своими недостатками, но как раз хороший разработчик часто может нивелировать это. Знания языка D ещё не делает разработчика сильным, он также может написать плохой код, которым потом будет тяжело поддерживать.

            Ну а что там хитрого? Я весь во внимании.

            Я уверен там очень много различной бизнес логики. Начиная от формирования контента для web/mobile версий со всей своей логикой, до поиска, рекомендаций, email-маркетинга, процессинга, сбора и обработки аналитики и много другого.
            Если так рассуждать, то и facebook простой, страничка профиля и связи с другими, вот и всё…
            В тему про размер кодовых баз, есть интересная статистика — http://www.informationisbeautiful.net/visualizations/million-lines-of-code/
            • –9
              Я утрирую.

              А вы говорите очевидные вещи. Но не обращаете внимание на то, что человек, который интересуется повышением своей эффективности, не сидит в пузыре одного единственного языка, слепленного из палок и изоленты, Тут дело не в том, знает ли программист язык D, а в том, знает ли он что-либо, кроме PHP. И если знает, то понимает насколько PHP ущербен, ведь единственное преимущество PHP перед другими языками — наличие большого пласта дешёвой рабочей силы, генерирующей типовой код методом генномодифицированной копипасты.

              Конечно там много бизнес логики. Целых 3 миллиона строк. Вопрос лишь в том, как эти строки написаны. Если не поддаваться копипасте, а хотябы минимально обобщать решения, то всё, что вы перечислили очень сложно растянуть на 3 миллиона. А фейсбук функционально и правда не ахти какой сложности проект. Подобную соцсеть пара толковых программиста с толковыми инструментами могут сваять за пол года.
              • +13
                Золотой фонд цитат хабра:
                А фейсбук функционально и правда не ахти какой сложности проект. Подобную соцсеть пара толковых программиста с толковыми инструментами могут сваять за пол года.

              • +1
                Про "пузырь" и php, как инструмента на все случаи жизни речи не было, посмотрите на список репозиториев badoo — https://github.com/badoo, там обилие разных языков программирования: PHP, С, Ruby, Python, Go, Lua, Java и другие, никто не ограничен, для разных задач используются более подходящие из ходя из множества требований и условий.
                • –4
                  Ох уж эта наивная вера в программистов, не подверженных когнитивным искажениям :-)

                  https://github.com/yandex — ни одного проекта на PHP. Более того, PHP-шный кинопоиск яндексоиды зачем-то решили переписать на Java. Наверно, ребята не знают, что для веб-сайтов, исходя из множества требований и условий, лучше подходит PHP. :-)

                  PS. И, если не понятно, то суть даже не в том, что Java лучше PHP, а в том, что у каждого свой пузырь. И в конечном счёте язык выбирают не самый эффективный, а тот который лучше знают.

                  PPS. Но объективно, старые огромные PHP-проекты поддерживать очень тяжко. Чувствуешь себя археологом.
                  • +2
                    Я думаю, многие хаброюзеры с удовольствием почитают статью о вашем опыте поддержки старых огромных PHP-проектов (да и вообще любых проектов), где вы расскажете о проблемах, с которыми приходится сталкиваться, и методиках их решения.
                    • –2
                      Нечто такое я как раз недавно писал про JS проекты.
                      • +3
                        Очень жаль, что там нет ни слова ни про один старый большой проект и ваш опыт его поддержки. Но фотография сухогрузов красивая.
      • +2
        «Кроме как копипастой и костылями я не знаю чем можно забить 3 миллиона строк для этого не хитрого сервиса»

        Предлагаю остановиться на том, что вы чего-то не знаете.
        • –7
          Я много чего не знаю, поэтому и попросил рассказать что делают эти 3 миллиона строк. А останавливаться на незнании — удел тех, кто сейчас рьяно сливает мне карму. :`-D
  • +1
    А сколько $$ вы потратили на все работы по переходу на PHP7?
    • +2
      Я думаю, не сильно ошибусь, если скажу, что примерно на порядок меньше
      • –2
        Хм, 100k$ — это, грубо, пара человеколет. Судя по статье, есть подозрение, что затрат было больше.
        • +2
          Совершенно точно мы потратили меньше, чем пару человеколет рабочего времени на то, чтобы перейти на PHP7. Даже разработка и внедрение Soft Mocks (самая тяжелая часть, по сути) заняли в сумме не больше пары месяцев рабочего времени.
    • +1
      У нас проект немного меньше, но все равно 200 000 строк кода

      вылезло только

      $this->$moduleVoc[$key]($callParams)

      в одном месте, все остальное взлетело на ура сразу
  • –4
    во всем коде пути к CLI-интерпретатору были заменены на /local/php, который, в свою очередь, являлся симлинком либо на /local/php5, либо на /local/php7

    Какой ужас. Ядро пыха патчите, а казалось бы такой простой штуки наподобие гентушного eselect в свой well-established и LSB не прикрутили. Хотя бы для себя. Чудеса)
  • 0
    А Blitz в семерке не работает?
  • +1
    Вот тут можно почитать английскую версию статьи: https://techblog.badoo.com/blog/2016/03/14/how-badoo-saved-one-million-dollars-switching-to-php7/
  • +4
    "The so-called Brazilian System", I've never heard this term before. Why is it called that? Did you guys coin the term? ))))))))))))))))
  • +1
    Маленькая просьба: очень хотелось бы видеть графики, начинающиеся с нуля.
  • 0
    Отличный кейс!
    Почему в другом кластере не используется OPCache?
    PHP у вас по прежнему живёт моделью always die, не рассматривали переход на phpDaemon/react-php?
    Кстати, почему igbinary до сих пор не включили в ядро?
    • +1
      переход на phpDaemon/react-php?

      Хочу заметить что на базе проекта amphp можно сделать вещи поинтереснее. В частности недавно вот вышел ayres-reverse для проксирования запросов, а стало быть можно прикрутить amphp/process для управления воркерами и получить на выходе более-менее православный php-pm, с хот-релоадом воркеров и т.д.
  • +3
    По мотивам вашего поста обновились на production на php7

    вылезла одна странная штука… Либо я не понимаю как оно работает либо это баг

    https://bugs.php.net/bug.php?id=71837&thanks=4
    • +6
      респект, зафиксили меньше чем за 24 часа
      • +1
        ну баг правда позорный
      • 0
        https://bugs.php.net/bug.php?id=67934 тоже не вот приятный баг, а висит с 2014г (кстати в 7ку он так же перекочевал)
        • +1
          А кому в голову пришло в принципе через empty проверять свойства интервала? Ну то есть там же не empty а на ноль проверку нужно делать.
          • 0
            Например, если ожидается не 0. По вашему есть разница?
             if(!empty($interval->d)){
              ...
             }
             // и
             if($interval->d >0){
              ...
             }
            

            • 0
              Да, второй вариант явно читается как «если количество дней в интервале больше нуля», а не «если количество дней в интервале не пустое».
              • 0
                На вкус и цвет, дело не в этом. Стандартная языковая конструкция не работает. По манулалу ожидается одинаковое поведение по факту нет.
  • 0
    Мне одному кажется, что вы сэкономили не 300 серверов, а 600?
    Вы увеличили производительность вдвое, как если бы вы без оптимизации добавили столько же серверов, сколько у вас было.
    То есть текущая производительность после оптимизации примерно равна двойной производительности до, то есть 600+600 серверов.
    В итоге экономия в $2 млн на железе и $200к на хостинге.
    • +1
      При текущих нагрузках экономия 300 серверов, которые можно, например, продать.
      • +1
        Я исходил из фразы автора
        теперь мы можем на том же количестве серверов выдерживать намного большую нагрузку, что, по сути, снижает затраты на его приобретение и обслуживание
        В этом случае выгода составляет 600 серверов.

        Если же рассматривать выгоду с точки зрения продажи освобождаемого оборудования, то Вы совершенно правы — 300 железных серверов. Но в этом случае цена каждого used сервера будет намного ниже $4000, что в итоге составит менее $1М.
        • –1
          Не стоит, думаю, строить вычисления на этом тексте. Потому что иначе из фразы
          выигрыш по скорости и использованию CPU составлял сотни процентов.
          выйдет, что использование