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

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

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

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

Как появятся все необходимые расширения под PHP7, так будем пробовать перейти.
Подавляющее большинство расширений уже есть.
Вам каких не хватает?
Тоже долго не переходили на PHP7 из-за Redis. Но потом почитали доки, оказалось у редиса же простейший протокол.
В итоге перешли на PHP7 + TinyRedisClient. Только допилили немного, чтобы пайплайнинг работал.
Predis очень шустро работает и без расширений. От опционального ext/phpiredis профит заметен только на жирных pipeline-ах с огромными ответами, подозреваю, что от перехода на PHP7 профит намного заметнее.
Не, ну если накатили и ушли в кабак праздновать — то, пожалуй, не очень хорошее :)
это было после карантина на части кластера, этот карантин не виден на графиках.
Это один из кластеров. До него несколько других работало уже три дня.
Ну и накатили утром, так чтоб весь день держать руку на пульсе.
Увлекательно. Графики будут нагляднее, если начинать их от нуля, а не 5 или 50. Визуально выглядит, что память теперь вообще не используется.
это чтобы я мог написать где-то в коде контроллера echo $counter++ и и получить 1....2....3....4 на каждый заход.
о, это очень старая история, но она от семёрки вообще не зависит
в PHP принята абсолютно не побоюсь этого слова гениальная stateless модель fcgi, с полным очищением памяти после завершения выполнения запроса, практически гарантирующая отсутствие "распухание" по памяти и прочую радость в продакшене
ну и отдельно скажу что для share nothing архитектур состояние в приложении — зло
Я все вот мечтаю, что рано или поздно они добавят shared-объекты между процессами с volatile-модификаторами для переменной, тогда в шаред-памяти можно хранить будет настоящие инстансы, например, подключений к базе или прогретые контейнеры классов и т.д.

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

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

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

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

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

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

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

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

А можно сразу писать на чём-то типа Vibe.D, где рекомпиляция проекта проходит за секунды, сейчас пилят балансировщик, который сможет hot-swap, где не требуется установка интерпретатора (выложил бинарник и всё), не нужен прогрев, есть безопасная работа с shared memory, корутины, вебсокеты и прочее, прочее, прочее. А узкие места нет необходимости переписывать на другом языке и потом "дружить" с исходным.
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) даже грозился сделать это дело в виде расширения хотя бы для кода, использующего сильную динамическую типизацию (информация о типах есть, что еще надо?). Но для этого надо решить еще парочку проблем.
Разработчика, который хорошо знает PHP тоже поискать придётся ;-) А толковому разработчику разобраться в D не составит особого труда. Особенно JS-разработчику, ведь VibeD похож на NodeJS+node-fibers.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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.
у явы как ни странно сахара больше и кода для какого-нибудь реста писать надо порядочно меньше

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.
Как на счёт принять сложный json и мапнуть его на объект? (Кстати, что будет выведено в случае ошибки? [Правда интересно])

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Дефолтный 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.
Роуты пораждают кучу копипасты. Вместо того, чтобы создавать сущности и через адаптер сделать единообразный доступ к ним хоть через http, хоть через websockets, хоть через консоль, хоть через что угодно, вы вручную мапите ссылки на методы.
Мидлвари порождают кучу лишней работы. Вместо того, чтобы лениво парсить разные части запроса, только когда в этом действительно есть необходимость, вы прогоняете запрос через кучу милдварей, которые что-то с ним делают, чтобы в последней ответить, что-нибудь типа "ресурс не найден, но спасибо, что распарсили куки, распарсили строку запроса, распарсили тело запроса, проверили права и бог весть что там ещё сделали."
Вот зачем эти глупости было копипастить у ноды я ума не приложу.
«Единообразный подход к сущностям» сработает только в вырожденном случае anemic models / active-record, когда вся бизнес-логика на клиенте, а на сервере — максимум валидация.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

При этом, естественно, ничего не мешает держать их в пределах одного физического сервера.
Назовем вашу схему так:
статика + балансировщик -> мидлвэря -> бэкэнд.
$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) с тучей инструментов.
С Packagist будет совсем не так. Во-первых там каждый вендор имеет свой неймспейс, и вопросов про права на названия пакетов просто не возникнет. Во-вторых там нет пакетов, обрабатывающих один кошачий чих. Есть обрабатывающие пять-шесть чихов, но другие серьёзные пакеты от них не зависят. Ну и если кто-то что-то оттуда выпилит — никто другой на его место через 10 минут своё не впилит (см. про неймспейс).
Всё это время комментарии добавлялись, но не в ту ветку. Facepalm.
Если хочется хранить только read-only объекты между запросами, то можно использовать reactphp, phppm или нечто подобное. Именно shared memory они не дают, но позволяют инициализировать окружение 1 раз и потом просто обрабатывать запросы.
то можно использовать reactphp, phppm или нечто подобное.

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

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

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

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

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

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

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

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

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

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

echo serialize([1]);

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

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

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

$example = function () use(&$example) {
    return 1;
};

if ($example instanceof Closure) {
    echo serialize($example);
}

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

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

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

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

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

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

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

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

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

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

ЗЫ statefull модель полезна для WebSockets. В том же Python+Tornado я в одном коде могу писать statefull вебсокет хендлеры и stateless http хендлеры, мне не нужны разные языки/фреймворки для этого. Использовать для хранения информации всякие Redis между состояниями конечно можно, но это медленно и далеко не всегда удобно.
не стоит ждать настоящий 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 писать (какие-то микросервисы критичные к нагрузкам, если нет возможности это на ноде делать).
Специально для минусующих выкладываю скрин/ На скрине 7.0, но в 7.0.3 также повторяется.
https://habrastorage.org/files/d44/92b/6fd/d4492b6fdd3d4d2cb487283be5ce2029.jpg
Ничего.
Я всё оттрассировал и нашёл строчку в исходниках, где вываливается segfault, но чтобы написать простой пример, демонстрирующий багу, мне нужна ещё неделя, а у меня этого времени нет.

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

В общем, лично я принял решение ждать 7.2-7.3
Есть backtrace — делайте баг-репорт, только предварительно поищите репорт с таким же трэйсом, чтоб не плодить дубли.
Ждать или делать — ваш выбор.
А тут дело скорее не в конкретном баге, а в том, что он не первый и нет никакой уверенности, что не последний
Почитайте чейнджлог пятой версии http://php.net/ChangeLog-5.php. Релиз состоялся 13 июля 2004 года, а в версиях от 3 марта 2016 года до сих пор фиксят баги. Я вам гарантирую, обнаруженный вами баг — не последний. Подождите хотя бы PHP 28.0, а лучше 29.0.
Кто-то больше выиграет от экономии ресурсов, кто-то больше проиграет при появлении бага, пользователи php бывают разные. Вероятность появления бага в продукте, только недавно вышедшем на рынок гораздо больше, чем в продукте, которые работает уже несколько лет, но вероятность ниже не значит, что она равно нулю.
Баги есть всегда. У любых пользователей 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.
Удивительно, как можно применять правила для механизмов, т.е. продверженных в первую очередь износу, с ПО, не подверженному износу? У вас так хорошо получается гуглить, думаю что у вас не составит труда опровергнуть свои слова, у меня получилось найти аналогичные графики для ПО за минуту поиска. Они имеют другую форму.
Это очень интересно. Не могли бы вы показать эти графики? А если в составе какой-то статьи, где эти графики объясняются — так вообще прекрасно. Мне вот удалось быстро найти http://www.1manteam.com/index.php/2011/01/facebooks-developer-love-initiative-3-months-later/ — что больше похоже на выводы обычной теории надёжности, чем на ваши утверждения.
ПО подвержено износу, только в качестве износа выступает усложнение и изменения этого ПО с течением времени. Кроме того, количество ошибок определяется не только износом, иначе бы в нулевой момент времени оно было бы нулём.
А вы были правы. Действительно, довольно быстро гуглится — картинки по запросу "software failure rate".
И насчёт применимости правил — вас не смущает, что люди, которые вас окружают, голосуют на выборах в соответствии с распределением Гаусса, а на мобильные телефоны звонят потоком Пуассона?
Ну вот и сравните кол-во багов а-ля segfault в php 5 до версии 5.3 и после.
Сравнил:
➜ ~ 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, складывать количество сегфолтов неправильно. Кроме того, сегфолты часто происходят в расширениях, и тут надо смотреть в каких именно и насколько они часто используются.
Вы бы лучше сами привели статистику, которую посчитали. И выводы, которые сделали.
Кстати, даже чисто визуально по http://php.net/ChangeLog-5.php видно, что число исправляемых ошибок в 5.6 намного выше, чем в 5.5, а уж 5.4 там встречается еще реже.
Ага. 5.4 просто больше не поддерживают, вышел последний 5.4.45 и всё. По вашей логике надо четвёртую версию использовать, там последний раз ошибки исправляли в 2008 году.
Почему вы ограничиваете моё логику своими домыслами? Безусловно лучше иметь поддерживаемую версию.
Моя логика была проста — есть задачи, где цена ошибки очень высока, в таких задача, и только в таких, выгоднее использовать поддерживаемую версию где меньше шансов на ошибку, чем поддерживаемую версию с высокими шансами на ошибку, потому что цена ошибки, повторюсь, очень высока. Да, можно добавить сарказма в ответ и попыток подловить на чем-то, но смысл? Думаю, что вы меня поняли.
А объясните мне, пожалуйста, такой простой вопрос — почему при большом количестве проектов JIT для PHP с больших компаниях ни один из них не продвигали upstream?
И почему вы сами не сделали его, раз у вас такая большая ферма серверов и большая зависимость?
Во-первых, очевидно, что никому это не надо настолько сильно, чтоб взяться за разработку.
Во-вторых, почему вы решили, что это какая-то серебряная пуля?
В Zend заимплементили JIT, поэкспериментировали и убрали пока в сторону:
http://marc.info/?l=php-internals&m=142503908926686
TL;DR: первое выполнение скрипта — вплоть до нескольких минут, второе — выигрыша особого не даёт.
Правильно ли я понял, что в итоге заброшенный JIT в Zend был сделан на LLVM? (Который не очень хорошо оптимизирован для JIT сценария и добавляет большой overhead...)
Потому что "сделать для себя" и "продвинуть в апстрим" — примерно равные по ресурсоёмкости задачи. Грубо, если один год девелопили, другой год будете двигать в апстрим. Мы это на своей шкуре несколько раз почувствовали и для не таких больших проектов. А почему не сделали сами — мы всё-таки слишком маленькие, чтобы такими задачами системно заниматься.
Понятно, что первый пуш в апстрим идет долго первый раз (в зависимости от сообщества и его лидера, конечно, в linux-kernel это будет совсем больно, в llvm — одно удовольствие). Но никому и не обещали что это будет легко. Но это только первый раз, со временем, с ростом репутации push в upstream может стать довольно быстрым мероприятием.

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

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

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

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



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

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

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

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

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

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

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

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


new ExcelBook(null, null, true);

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

А вообще, это всё дебаг по телефону. Мне надо видеть, иметь возможность запустить это всё.
Ну, и совсем неясно почему это всё обсуждается в этом топике =)
А почему у вас php-fpm на tcp, а не на сокетах? Неужели очереди в сокеты длиннее 0xFFFF бывают?
Скрижали гласят, что сокеты быстрее. Но я, если честно, давно не измерял, и вот fisher пишет, что скрижали слегка устареть могли.
И да, и нет. На самом деле, в разных кластерах разные схемы балансировки нагрузки, и в одной из схем есть небольшое количество nginx на одних машинах, и большое количетво php-fpm на других. Собственно, это ответ на вопрос, почему AF_INET.
unix-сокет не требует для работы стэка ip протокола, который в данном случае и есть оверхед.
Спасибо, тут уже выяснили, что разница есть, хотя и небольшая, заметная только под очень большой нагрузкой.
Покажите лучше графики количества багов в ПО в зависимости от времени, которые, как вы упоминали выше в комментариях, вам удалось найти за минуту. Мне очень интересна эта тема.
Вы же читали все слайды, правда? График для софта справедлив при условии, что в софт не вносится никаких изменений, кроме исправлений ошибок. Мы изначально говорили про эволюцию PHP, в который изменения вносятся постоянно. Запрос, по которому надо гуглить, я уже писал выше.
Читал, разумеется, как раз описанная мною ситуация, что кому-то важнее иметь меньше шансов возникновения ошибок/фаталок, и в этом случае берется версия софта, в которой нет нововведений, есть только исправление ошибок, и для такого софта как раз такой график, а не пила, как для более новых версий, и разумеется график для железа не подходит для софта, так ведь?
когда-то на старых ядрах это типа может и отличалась но щас вроде разницы никакой
Фиш, не хочу тебя разочаровывать, но это не совсем так. В целом, нет причин, по которым 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
а я не говорил, что "TCP мог бы вообще когда-нибудь работать быстрее, чем unix socket". я говорил, что теоретически могло быть наоборот на старых ядрах, unix сокеты могли быть быстрее tcp, ну и я тоже что-то когда-то слышал про скрижали, которые это говорили, но вроде давно уже без разницы. твой эксперимент это лишь подтверждает. выпей порто :)
Если перефразировать AntonStepanenko, то TCP используется потому, что он гибче — мы в некоторых случаях мы ходим напрямую на FPM
Сколько RPS оно выдает с одного ядра? На каком-нибудь Go этот показатель примерно 10k. Может можно еще 300 серверов освободить? :)
Вот только цена разработки (портирования) будет выше и вряд ли окупится когда либо )
Все-таки, справедливости ради, хотел бы сказать, что 10k rps на одно ядро на golang получить можно только в том случае, когда логика обработчика очень простая и не делает сотен запросов в другие сервисы по сложным условиям. В большинстве случаев на PHP пишут в том числе из-за сложности бизнес-логики, и на golang это все переводить будет нецелесообразно. Тем не менее, какие-то самые нагруженные части наверняка можно перевести на golang хотя бы из соображений низкого latency.
О своём опыте: перевёл пару проектов на WordPress, довольно плотно обвешанных плагинами и темами, под PHP7, разница в производительности впечатляет. 10-долларовый дроплет DigitalOcean отдаёт страницы за ~500ms (при правильной сборке и настройке nginx). Правда приходится регулярно ловить incompatibility issues в чужом коде. Особенно люто валятся всякие indirect references на функции или методы классов.
500ms??? У нас на 5-долларовой ноде DO простой сервис на php5.6 c Lumen отдает по 50-70мс
Сравнивать Wordpress и Lumen это как сравнивать тёплое с мягким.
Я не то что сравнивал, скорее констатирую и удивляюсь разнице.
Я с wordpress плотно не работал, но все же кажется, что 500ms на 7 это слишком много. Что-то с wordpress не то
Для популярных CMS, да еще и "плотно обвешанных плагинами" это в принципе нормальный показатель. Не говоря уже о том, что сравнивать старую коробку и "простой сервис" совсем не корректно.
Вы большие молодцы, поздравляю вас. Но с развесистыми проектами на WP вы, вероятно, дела не имели.
Самое же прекрасное, что вы почему-то не упомянули, что в PHP7 нельзя использовать в качестве имени класса Error. А именно так назвать класс, унаследованный от Exception в PHP5, считает своим долгом в среднем каждый пятый разраб.
использование зарезервированных имен классов

Вам не понравилось, что там не указано Error? На мой взгляд нет смысла заниматься копированием документации и migration guide, статья немного о другом.
Мне статья вообще очень понравилась, не хотелось бы, чтобы у вас сложилось обратное мнение. Так что просто просто поделился опытом. Хотя вот у коллег ниже статистика другая.
Я сейчас, для интереса, посмотрел кол-во коммитеров в проект, которым я руковожу (полмиллиона строк кода). 32 человека. Ни один не назвал класс ошибок «Error». Я сломал вашу статистику! :)
Модификатор 'e' в регулярках, а также конструктор в виде названия класса уже давно deprecated. Или вы раньше просто подавляли такие ошибки?
Модификатор e приводит к ошибке уровня E_DEPRECATED начиная с PHP 5.5.0. Во-первых, не сказать, что это очень давно. Во-вторых, по-умолчанию E_DEPRECATED отключены, так что я бы не сказал, что прям подавляли, но да, какое-то время просто не уделяли этому внимания.
Что касается конструкторов — вы ничего не путаете? Они не приводят к ошибкам. Единственная особенность — начиная с 5.3.3 у классов внутри неймспейса конструктор должен называться __construct, иначе он просто не будет вызван при создании объекта.
Да, про конструктор ошибся. Просто так давно не встречал старых конструкторов, что был уверен, что deprecated
На самом деле конструкторы совпадающие с названием класса не рекомендуется использовать еще со времен выхода 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 раза, что улучшило общее время ответа примерно на 40%, так как некоторая часть времени при обработке запроса тратится на общение с базами и демонами, и с переходом на PHP7 эта часть никак не ускоряется, что ожидаемо.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Предлагаю остановиться на том, что вы чего-то не знаете.
Я много чего не знаю, поэтому и попросил рассказать что делают эти 3 миллиона строк. А останавливаться на незнании — удел тех, кто сейчас рьяно сливает мне карму. :`-D
Я думаю, не сильно ошибусь, если скажу, что примерно на порядок меньше
UFO landed and left these words here
Совершенно точно мы потратили меньше, чем пару человеколет рабочего времени на то, чтобы перейти на PHP7. Даже разработка и внедрение Soft Mocks (самая тяжелая часть, по сути) заняли в сумме не больше пары месяцев рабочего времени.
У нас проект немного меньше, но все равно 200 000 строк кода

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

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

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

Какой ужас. Ядро пыха патчите, а казалось бы такой простой штуки наподобие гентушного eselect в свой well-established и LSB не прикрутили. Хотя бы для себя. Чудеса)
"The so-called Brazilian System", I've never heard this term before. Why is it called that? Did you guys coin the term? ))))))))))))))))
Маленькая просьба: очень хотелось бы видеть графики, начинающиеся с нуля.
Отличный кейс!
Почему в другом кластере не используется OPCache?
PHP у вас по прежнему живёт моделью always die, не рассматривали переход на phpDaemon/react-php?
Кстати, почему igbinary до сих пор не включили в ядро?
переход на phpDaemon/react-php?

Хочу заметить что на базе проекта amphp можно сделать вещи поинтереснее. В частности недавно вот вышел ayres-reverse для проксирования запросов, а стало быть можно прикрутить amphp/process для управления воркерами и получить на выходе более-менее православный php-pm, с хот-релоадом воркеров и т.д.
А кому в голову пришло в принципе через empty проверять свойства интервала? Ну то есть там же не empty а на ноль проверку нужно делать.
Например, если ожидается не 0. По вашему есть разница?
 if(!empty($interval->d)){
  ...
 }
 // и
 if($interval->d >0){
  ...
 }

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

Если же рассматривать выгоду с точки зрения продажи освобождаемого оборудования, то Вы совершенно правы — 300 железных серверов. Но в этом случае цена каждого used сервера будет намного ниже $4000, что в итоге составит менее $1М.
Не стоит, думаю, строить вычисления на этом тексте. Потому что иначе из фразы
выигрыш по скорости и использованию CPU составлял сотни процентов.
выйдет, что использование CPU стало отрицательным.
А подскажите пожалуйста, как себя ведет APcu при больших нагрузка? И на сколько большие данные вы там храните? Спасибо.
Данные храним небольшие, в основном нам это нужно для нашего аналога circuit breaker (https://en.wikipedia.org/wiki/Circuit_breaker) — механизма, который предотвращает исчерпание всех воркеров при «затупах» одного сервиса (не важно, mysql это, memcache или самописный демон).
На больших нагрузках он начинал упираться во внутренние mutex'ы, и вроде бы с тех пор ситуация стала получше. Мы также переписали свой код с использования cas на использование inc/dec (атомарные операции, также как и cas), и с тех пор вообще проблем с этим механизмом не имеем.
Какие бы курсы пройти что бы понимать о чем эта статья в деталях?

Судя по предыдущим публикациям вы используете handlersocket. Какую либу используете в php7 для этого?
tony2001 jfyi. Либу вроде стандартную, полагаю что вот это: https://github.com/tony2001/php-ext-handlersocketi но пусть уж Тони меня поправит
Ага. Вижу бранч под php7. Буду пробовать собирать инсталировать
Only those users with full accounts are able to leave comments. Log in, please.
Information
Founded

1 January 2006

Location

Россия

Website

badoo.com

Employees

201–500 employees

Registered

15 December 2009

Habr blog