Ровно два года назад — в ту же самую дату и в то же самое время — я опубликовал статью «ВКонтакте снова выкладывает KPHP».

Сегодня рассказываю, куда мы продвинулись за эти два года: про язык, рантайм, использование KPHP вне ВКонтакте, другие open-source проекты и февраль 2022-го.

Мы ничего не забросили

В комментариях к прошлой статье было много опасений вида «ну выложили, а теперь снова уйдёте в закат». Не ушли.

Мы по-прежнему ведём разработку на GitHub и даже недавно набрали 1 000 звёздочек. 

Наша задача по-прежнему не «убить PHP», а быть с ним в симбиозе. KPHP — это не отдельный язык, а альтернативный рантайм для PHP-кода. В отличие от, например, Hack, на котором разрабатывают другую социальную сеть и в котором отказались от обратной совместимости, ВКонтакте разрабатывается на обычном PHP — а KPHP нужен для скорости в продакшене.

Кроме развития KPHP, наша маленькая команда делает многое для бэкенда VK и ведёт несколько других открытых проектов. О них тоже расскажу — они не зациклены на KPHP и их можно использовать даже в связке с другим стеком.

Как поживает ВКонтакте

Хорошо поживает, развивается. Фичи пилятся, релизы релизятся, пользователи пользуются, продуктовые метрики растут — вот это вот всё.

При этом, как и раньше, ВКонтакте написан на PHP, а в продакшене работает на KPHP. Понятное дело, за исключением баз данных, разных проксей и стриминга (там C++ и Go). Но вся бизнес-логика, весь «сайт», mvk и API — это всё гигантский монолит на KPHP.

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

Два года назад в монолите было 5,5 млн строк PHP-кода, а сейчас больше 8 млн, и это не считая ML-моделек вне монолита. Обычный продуктовый код, классы там, интерфейсы, запросы к базам, API-ответы — просто очень много. Бэкендеров всё больше и больше, кода всё больше и больше. Но KPHP собирается даже быстрее, чем тогда, потому что мы реально много вложили в скорость анализа и сборки такого количества кода.

Что изменилось в KPHP

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

Появился FFI. Это технология интеграции с сишными библиотеками без изменения самого KPHP. Возможности и синтаксис нашего FFI один в один как и в PHP, с поддержкой указателей, массивов и колбэков. Только мы в compile-time трекаем типы и практически не имеем оверхеда на внешние вызовы (в обычном PHP оверхед очень заметный). Благодаря FFI удалось написать графическую игру, подключить SQLite, Postgres и даже Lua

Появился честный параллелизм. KPHP однопоточный и всегда таким был. И те корутины, которые у нас есть, это такой умный шедулер между ветками исполнения на время ожидания сети. А теперь есть отдельные воркеры, и им можно через шаренную память кидать задачи из http-воркеров, и можно параллелить даже CPU-работу. Мы называем это job-воркерами. Ими удалось откусить 10–15% времени ответов API (которые через полгода обратно съелись продуктовым кодом, как оно всегда и бывает).

Мы постоянно боремся с объёмом PHP-кода. Те самые невидимые оптимизации: как во время компиляции 8-миллионного монолита сэкономить секунду-две и пару гигабайт оперативы. То данные по-хитрому упаковать, то алгоритм на графах распараллелить, то переписать парсинг phpdoc. Анализ 8 миллионов PHP-строк сейчас занимает около 25 секунд с кодогенерацией, а без этой работы было бы 40–50. Вроде мелочи, но когда сотни бэкендеров запускают KPHP постоянно — уже не мелочи. Жаль, конечно, что это не нужно для проектов разумного размера, но технические челленджи я тоже очень люблю.

Эксплуатация, железо, деплой. Опять-таки внутренние штуки, интеграция с Sentry и кубером, бесконечные метрики и логи в разных форматах, профилирование на продакшене, шифрование между ДЦ, поддержка Clang, разных версий дебиана, сборка под ARM, даже почти научились в кросс-компиляцию. Такая рутина, большей частью для ВКонтакте и скучная. Но такое есть везде, и будто бы у нас её даже относительно мало.

В феврале 2022-го всем пришлось туго. Когда заблокировали [некоторые ресурсы], нагрузка на ВКонтакте резко возросла. На поставки железа стало сложнее положиться, — а держать нагрузку нужно прямо сейчас. Срочно оптимизировать? Но что? В условиях дефицита ресурсов проще тем, кто оптимизациями раньше не занимался. Условно, привести в порядок инфру и расставить индексы в базе — вот тебе и ускорение на ровном месте. У нас же низко висящих фруктов почти нет, каждый % даётся со всё бóльшим трудом. Но ладно, это всё оправдания. Надо — значит, надо. Так что команда KPHP с командой эксплуатации не читает новости, а сидит и тюнит всё подряд, чтобы на текущем железе держать нагрузку ×1,5. Финальная цель — не чтобы работать быстрее, а чтобы деградировать медленнее, чтобы максимально оттянуть точку, когда системный шедулер сходит с ума, а тайминги улетают в небеса. Зато теперь KPHP поддерживает и NUMA, и CPU affinity, и множественные сокет-бэклоги, а nginx отстреливает бэкенды по-другому. Здесь вставлю важную, но почему-то для многих неочевидную ремарку: KPHP — это не только про трансляцию PHP в C++. Это большая технология: ведь сетевой реактор, prefork-модель, шаренная память, шедулер для корутин, вот эти все нумы и epoll’ы — это тоже часть KPHP, просто не компилятора, а рантайма.

И тысячи мелочей вокруг да около — типа реализации JSON в compile-time, фич PHP 7.4, DateTime, zstd, __toString, checked exceptions, 103 HTTP headers, generic-функций — куча всего, чтобы покрывать больше возможностей PHP, а где-то превосходить его.

Помимо KPHP

Кроме того, мы ведём ещё несколько открытых проектов.

Продолжаем поддерживать наш линтер noverify. Только он способен справиться с такой кодовой базой за приемлемое время.

В прошлом году я придумал интересную концепцию «цветных функций» и реализовал внутри KPHP. Идея зашла, и для PHP-сообщества мы выпустили независимую реализацию, назвали nocolor. Об этом я рассказывал на PHP Russia, а месяц назад писал на Хабре.

Чтобы упростить разработку бэкендерам, каждый из которых имеет свою версию сайта на dev-сервере, мы написали плагин для PhpStorm. Он позволяет не выходя из IDE выполнять рутинные действия, которые раньше делались в удалённой консоли: запускать удалённо PHPUnit, собирать KPHP-версию сайта, отзеркалировать коммиты с приватного гитлаба и прочее. Плагин мы тоже выложили и назвали AdmStorm. Если кто-то захочет для своей компании написать нечто похожее (ведь посыл «делать рутину не выходя из IDE» хорош), сможет подглядеть в исходники. Мы набили много шишек в плагинах, а подглядеть было некуда.

Для ускорения сборки гигантского количества C++ автогена мы раньше использовали distcc для распределённой компиляции. Но недавно сделали ему замену и назвали nocc, что дало колоссальный прирост скорости сборки. Он не привязан к KPHP и в целом может быть полезен для больших плюсовых проектов. О нём я рассказывал на HighLoad++, а недавно тоже писал на Хабре.

Сейчас мы делаем честную модульность внутри PHP. В языке PHP очень не хватает нативных модулей: internal-классов, private-неймспейсов, явных export'ов; а Composer не всегда применим и не всегда нужен. Но если скрестить весь наш опыт с плагинами для IDE, модульность получится прямо чёткая. Об этом я расскажу на HighLoad++ в Москве.

И наконец, мы начали вкладываться в образование. Так, студенты ВШЭ будут изучать устройство компиляторов и сред исполнения. А ещё мы с ними займёмся тем, до чего у команды не доходят руки: созданием KPHP-совместимых библиотек для сообщества. Их очень не хватает, чтобы начать полноценно использовать KPHP вне ВКонтакте.

KPHP вне ВКонтакте

Здесь сложности, очевидные.

Напомню, в чём они заключаются. KPHP — это не магический ящик, ускоряющий любой PHP-код. Код должен быть написан с учётом типизации, будто строгий язык (да-да, так даже PHP-код становится реально понятным). Плюс к этому, KPHP редко поддерживает фичи, не нужные VK.

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

Несмотря на это, есть успешные кейсы внедрения. Так, поставили на KPHP-рельсы отечественный аналог MS Project — и SaaS-решение превратилось в коробочную версию с лицензией. Сейчас владельцы успешно поставляют коробки своим B2B-клиентам, а недавно автор подробно делился своим опытом миграции.

Были и другие случаи. Плюс всякие энтузиасты, которые явно что-то пробовали. Но всегда все сталкиваются с одним: нет готовых пакетов, фреймворков, комьюнити. И после всего пройденного теперь и на это хочется направить фокус усилий.

Роадмап на следующие год-два

Обобщая мысли выше, я бы назвал это «развивать экосистему вокруг KPHP»: адаптировать полезные Composer-пакеты, сделать собственный веб-фреймворк и шаблонизатор, подключить через FFI популярные расширения по типу gd. В общем, обеспечить набор кубиков, чтобы энтузиастам было проще стартовать. И пока их обеспечиваем, дорабатывать сам язык и рантайм с учётом потребностей индустрии.

Продолжать развивать язык. В ближайшие месяцы я уж точно доделаю дженерики и скрещу это с IDE — и у нас наконец-то будут по-настоящему честные дженерики в обычном PHP. Потом сделаем vector<T> и map<K,V> вместо обычных PHP-шных array. Когда-то будут и алиасы, и фантомные типы, и nullability будем трекать. В общем, это всё про строгость, оставляя plain PHP как интерпретируемый способ разработки на KPHP. А, ну и PHP 8 ещё затянуть, да и из 7.4 много чего нереализованного, но для опенсорса нужного — тоже сделаем.

Почаще публиковать интересные вещи. Есть много чем поделиться и по компиляторным всяким штукам, и по системному программированию, и по устройству IDE. Уж точно соберём материал на несколько хороших статей — для разных по интересам аудиторий. Кстати, мы недавно завели канал KPHP dev blog, там раз в недельку-две делимся байками в формате коротких постов, которые не тянут на полноценные статьи. Продолжить митапы и конференции — сюда же входит. И маскота, наконец, нарисовать :)

Выводы

Под каждой технической статьёй от ВКонтакте первый же коммент: «Сайт тормозит, 20 мегабайт js’а, грузится 2 минуты». Окей, давайте разберём это в текущем контексте. Как думаете, если бы бэкенд был написан не на KPHP, а на <ваш-любимый-язык> — то разработчики писали бы код по-другому? Создавали бы меньше абстракций для перекладывания данных? Делали бы меньше запросов к базам? Гоняли бы меньше трафика между ДЦ? Мобилка бы сразу экономила батарейку, а на фронтенде стало бы меньше скриптов и стилей? Если бы я в это верил — я бы сегодня же уволился, и чтоб сайт стал быстрым уже, наконец :) Но я почему-то не верю.

Под каждой технической статьёй от ВКонтакте второй же коммент: «Да кому это интересно, вк давно уже никто не пользуется». Ну ок. Пойду гляну на график 3M QPS и дальше писать код :)

Сегодня круглая дата — отличный повод подытожить достижения и поделиться планами. А планы простые: движемся дальше. Развиваем язык. Развиваем рантайм. Обеспечиваем функционирование бэкенда ВКонтакте. Сами придумываем технические челленджи, сами их решаем. Иногда создаём инструменты, полезные сообществу. Иногда публикуем материалы, интересные сообществу. Хотим, чтобы такого было больше. Есть понимание, что будет дальше, но без конкретных чисел и сроков. Ведь главное — не сроки, не числа и не KPI. Главное — делать то, что считаешь правильным. По-другому оно не работает.

Ссылки

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


  1. namikiri
    11.11.2022 12:53
    +3

    «Сайт тормозит, 20 мегабайт js’а, грузится 2 минуты»

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


    1. klounader
      12.11.2022 11:21
      +1

      ну хз, у меня вк на компе грузится несколько секунд. интерфейс тормозной донельзя. чтобы куда-то добраться, нужно кучу кнопочек понажимать на ощупь, интуитивно пытаясь протискиваться через кучу хлама. раньше всё было намного быстрее, проще и не отжирало кучу места бесполезной информацией. чего только стоит один лишь фон аватарки на полэкрана. а в разделе музыки на вкладке моя музыка видна только одна песенка, самая первая в самом низу экрана, вот там и начинается мой главный плейлист. а весь остальной экран занят барахлом. они там все поголовно наверное уже давно переехали на 8к мониторы, 13900к, ртх4090, 500 гигабит и им норм, у них всё быстро летает и грузится.


    1. vadimk91
      12.11.2022 11:49
      +1

      Первые экраны (я про десктопную версию) отображается шустро, на самом деле. Но начинаешь листать ленту в каком-нибудь сообществе и после пары десятков постов начинается 'черт знает што'. Браузер - свежий хром, памяти свободной полно, загрузка процессора не вызывает опасений, а то кнопки нажимаются не те (хотел запустить трек, а выскочили эти кривляющиеся смайлы), то срабатывают только после нескольких кликов, то подгрузка тормозит. Справедливости ради, такая же ерунда при прокрутке нескольких экранов комментов к видео на ютюбе. Похоже эти бесконечные ленты новостей так реализованы.


  1. Apoheliy
    11.11.2022 15:51
    +1

    Нескромный вопрос: планируете ли отрезать пуповину (и когда)?: Объявить kphp и иже с ним отдельным языком, похожим на php.

    Судя по тому, что функционал языка ограничивается с одной стороны и планируются добавлять "нестандартный" функционал (поправьте, если ошибаюсь) с другой, то такое решение просто напрашивается.

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


    1. Chupaka
      11.11.2022 23:14

      оставляя plain PHP как интерпретируемый способ разработки на KPHP

      Видимо, таких планов пока нет


    1. unserialize Автор
      12.11.2022 00:25
      +6

      "Планируете ли отрезать пуповину?" — этот вопрос выглядит скромным, а вот "и когда?" уже и правда нет :D

      Ох, сколько же раз я над этим думал — и до сих пор не нахожу правильного ответа.

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

      Но правильно ли это? Интерпретируемая разработка на PHP — это очень удобно для бэкендеров. Максимально быстрое прототипирование: залил файл на сервер, F5, и готово. Плюс, используем привычные инструменты: пройтись по шагам в xdebug, прогнать тесты на PHPUnit, всякие там моки и рефлексия, всё это во время разработки — а KPHP это не поддерживает и не должен. Он для продакшена.

      Если отпочковываться — это как? Уходить от интерпретируемой разработки, заставляя бэкендеров после каждого изменения компилировать гигантский бинарь? Слишком долго, все взвоют. Сделать свой модный форк PHP, тоже интерпретируемый? Но сразу же разойдёмся и законфликнуем с основной версией. Да и любой язык — это далеко не синтаксис, это прежде всего экосистема вокруг. А дебаггер? А тесты? А написание кода в IDE, причём в разных? А подсветка в гитхабе/гитлабе? Уйма примеров. И всё это нужно делать? И поддерживать? Здесь bus factor не то что единичка, по-моему он отрицательный будет )

      (если интересно, в [другой социальной сети] Hack'ом занимается отдел более чем из 50-ти человек, уже 10 лет)

      В общем, вот такие примерно соображения. Так что — я не знаю, в какую сторону качнуть этот trade-off :)


      1. nikolas78
        12.11.2022 18:33

        я не знаю, в какую сторону качнуть этот trade-off :)
        Если нет инвестиций, то пока ни в какую. Будут — делайте новый яп (при условии его использования в ВК).


    1. sena
      12.11.2022 11:53

      Добавлять нестандартный функционал можно, почему нет? А вот исходный необходимо поддерживать, чтобы можно было переходить.


      1. MagisterAlexandr
        12.11.2022 12:14

        Но тогда в vk всё равно придётся на исходном php писать, да и почти везде. Откуда возьмётся мотивация для отпочкования?


      1. Apoheliy
        12.11.2022 14:51
        +1

        У них не получится поддерживать исходный функционал. Если почитать предыдущие статьи, то на php код накладывается ряд ограничений:

        • строгая типизация

        • нельзя обращаться к полям по имени или вызывать так методы

        и список можно продолжить.

        Поэтому php для kphp это не только нестандартный функционал, но и сужение стандартного. В общем, напрашивается новый язык.


  1. Kvento
    11.11.2022 23:18

    Большое вам спасибо за развернутую статью и интересные наработки полезные вне VK.


  1. MagisterAlexandr
    11.11.2022 23:32
    +1

    Мы называем это job-воркерами. Ими удалось откусить 10–15% времени ответов API (которые через полгода обратно съелись продуктовым кодом, как оно всегда и бывает).

    Ключевая фраза.

    Оптимизации на низком уровне это круто.

    А вот на других уровнях, где можно получить эффект не в полтора-два раза, а на порядок, безнадёжная обычность (ссылка не по технической теме и может вызвать противоречивые чувства, скорее всего лучше по ней не кликать).


    1. unserialize Автор
      12.11.2022 00:33
      +3

      Всё правильно. Не поспорить. Это эффект любых enterprise'ов и корпораций.

      Пока команда маленькая, знания хорошо пошарены и каждый представляет примерно весь проект — есть возможность всё контролировать. Как только начинают выделяться отдельные команды, юниты, иерархия, области ответственности, противоречивые KPI — начинается нагромождение, абстракции, перекладывания данных. И микросервисы в кубере конечно же давайте затащим!!! Но это уже личное :D

      Это везде так. Я не знаю, что с этим делать. В моих силах лишь максимально долго сохранять порядок на низком уровне. И пока это получается хорошо.


      1. MagisterAlexandr
        12.11.2022 10:18

        Писал комментарий, переросло в статью.

        https://habr.com/ru/post/698946/


    1. quasilyte
      12.11.2022 17:05
      +1

      Оптимизации на низком уровне это круто.

      Оптимизации на низком уровне часто позволяют создавать эффективные фундаментальные блоки. Например, какие-нибудь библиотеки, производительность которых важна для работы систем. Если сам язык не позволяет такую написать на нём же, то придётся в случае PHP писать расширения. Для таких библиотек эффективные низкоуровневые оптимизации могут давать прирост выше, чем 10-15%.

      KPHP интересен тем, что он позволяет многие такие фундаментальные вещи писать на самом же PHP и они будут приемлемы по производительности. Задача компилятора тут дать нужные оптимизации и распознавать идиомы.


  1. Hixon10
    12.11.2022 02:43
    +2

    Привет, я бы хотел задать пару вопросов.

    Зато теперь KPHP поддерживает и NUMA, и CPU affinity, и множественные сокет-бэклоги, а nginx отстреливает бэкенды по-другому.


    1. Что такое множественные сокет-бэклоги?
    2. Что тут имеется ввиду под CPU affinity? Один входящий запрос в приложение всегда обрабатывается одним и тем же ядром, или что-то другое?


    1. DrDet
      12.11.2022 13:26
      +2

      1. Под множественными имелось в виду просто несколько серверных сокетов, у каждого из которых свой backlog. Путем многочисленных экспериментов выяснили, что в случае с двумя сокетами, причем на разных портах, можем держать больший RPS без деградации, чем с одним. Пробовали разные варианты: и SO_REUSEPORT на 2 сокета + fork n раз, и отдельный listen сокет в каждом воркере с SO_REUSEPORT, и еще много всяких. Резльутат один: 2 слушающих сокета на разных портах выигрывают. Скорее всего причина тому -- contention в ядре на слушающий сокет на accept'е.

      2. Напомню, что в KPHP prefork сервер, то есть много воркер процессов которые обрабатывают запросы. Под CPU affinity имелось в виду прибивание этих воркер процессов к ядрам. Более точно - к наборам ядер, соответвующих конкретной NUMA ноде. Еще из подобных оптимизаций решили сделать прибитие проксей к NUMA нодам, чтобы каждый воркер взаимодействовал с проксей со "своей" ноды. В совокупности это все позволило выиграть несколько процентов CPU.


      1. Hixon10
        12.11.2022 13:38

        Спасибо за ответ.


  1. klimkinMD
    14.11.2022 12:19

    Я же правильно понимаю, что KPHP транслируется в C++? А зачем это вообще требуется, почему сразу не C++ (возможно я упустил часть статей, тогда прошу прислать ссылку)?