Ровно два года назад — в ту же самую дату и в то же самое время — я опубликовал статью «ВКонтакте снова выкладывает 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. Главное — делать то, что считаешь правильным. По-другому оно не работает.
Ссылки
Чат в телеграме — KPHP (Unofficial). Здесь можно задавать любые вопросы.