На каком фреймворке написан вконтакте
Создатели ML-моделей рассказали, почему не доверяют своих пользователей ботам.
Руководитель службы поддержки «ВКонтакте» Анастасия Фёдорова и продакт-менеджер AI Research Иван Самсонов выступили на конференции по Machine Learning, прошедшей в Selectel. В тексте — про первые попытки автоматизировать службу поддержки и целый ансамбль ML-моделей, которые заменяют 30 сотрудников.
Команде поддержки «ВКонтакте» исполнилось 10 лет. За это время ее сотрудники ответили на 43 млн вопросов и помогли 26 млн пользователей (примерно столько же человек живет в Австралии).
У любой службы поддержки есть три основные точки контроля качества работы, рассказывает Иван:
- Время от первого ответа до решения проблемы. UX-исследования показывают, что качество ответа не окупает долгого ожидания.
- Содержательные и доброжелательные ответы.
- Время до первого ответа пользователю. Всем знакомо чувство раздражения, когда у вас какая-то проблема, а чат поддержки молчит. Нужно реагировать быстро, но ботов с их «Спасибо за обращение» во «ВКонтакте» использовать не хотят.
Очень не хочется, чтобы даже в далекой перспективе, когда это станет технологической нормой, пользователю отвечал робот. Мы максимально против ботов и переписки, где мы не контролируем общение с нашим пользователем. Потому что сохранять человеческое общение очень важно.
С момента внедрения ML-моделей пользователи «ВКонтакте» стали получать первые ответы в 5 раз быстрее. Чтобы понять, как команда пришла к таким результатам, вернемся в 2011 год.
Все это повысило скорость ответа поддержки, но настоящим бустом для соцсети стала коллаборация с командой прикладных исследований.
Первую модель машинного обучения для поддержки «ВКонтакте» создали в 2019 году. На тот момент технологии искусственного интеллекта уже были достаточно развиты, а соцсеть накопила большое количество данных для обучения модели — и вопросы пользователей, и классные ответы агентов.
Модель генеративная, то есть она учится генерировать данные на существующем массиве данных. Назвали Долорес — в честь героини сериала «Мир дикого Запада», который был популярен в то время.
Когда запустили модель, агентам было страшно, что вот, пришел искусственный интеллект, который лишит их работы. Но мы быстро поняли, что ИИ никогда не заменит живого человека. Он — помощник, который снимает часть работы с агентов, избавляет их от скучной рутины, позволяет сконцентрироваться на более важных задачах
Допустим, модель сгенерировала три ответа, как на картинке ниже, и агент должен выбрать наиболее подходящий.
Сотруднику поддержки не нужно руками вписывать ответ. Он просто выбирает корректный вариант и кликает «Использовать ответ».
Рядом есть кнопка «Передать». Ее агенты используют, если их компетенций не хватит, чтобы поддержать дальнейший разговор с пользователем. Юзер получает быстрый ответ, но модель переадресовывает переписку на «суперагентов», которые отвечают на сложные и специфические вопросы.
Бывают ситуации, когда сгенерированный ответ Долорес не подходит. Для этого есть две кнопки в интерфейсе: «Не подходит» и «Не подходит совсем». В первом случае модель правильно угадала направление мысли, но неправильно или неполно сформулировала. Агент может дописать или скорректировать ответ. «Не подходит совсем» дает понять, что ИИ сгенерировал какую-то дичь — сотрудник пишет ответ сам.
во столько раз увеличилась скорость первого ответа пользователю с появлением ML-инструментов
Долорес развивается не одна, внутри нее есть целый ансамбль моделей, которые закрывают разные задачи службы поддержки. Все они носят имена каких-то маскотов — Нео, Принцесса Лея и другие узнаваемые персонажи. Так разработчикам «ВКонтакте» проще и веселее общаться между собой.
Не всегда людям, которые пишут в поддержку, действительно нужна помощь. Чтобы агенты не тратили свое время и силы на таких пользователей, «ВКонтакте» внедрила систему антитроллинга. Модель оценивает семантику запросов и классифицирует их. Так, разделяются вопросы, где пользователь реально хочет закрыть свою боль, и ехидные замечания со сленгом, нецензурной лексикой, которые не связаны с продуктом «ВКонтакте». Последние идут в урну, куда иногда заглядывают агенты для домодерации.
Есть отдельная категория вопросов, которую во «ВКонтакте» называют «Life is». В таких запросах нет отсылки к продукту, но нет и токсичной составляющей. Например, пользователь пишет: «Слушайте, мне так здорово сидеть на своей страничке, слушать музыку, но захотелось вьетнамской еды. Может, посоветуете доставку?» На таких вопросах агенты поддержки отдыхают. Никаких сложных технических моментов, можно просто человечно ответить и порадовать пользователя.
Также есть модель, которая идентифицирует язык вопроса и отправляет агентам-носителям. За десять лет работы сотрудники поддержки ответили на запросы на 24 языках.
Эта модель позволяет разработчикам «ВКонтакте» быстрее фиксить баги и находить проблемы в системах. Например, запустили новый продукт или выполнили маленькое или крупное обновление. Если что-то пошло не так, пользователи заметят это первыми. С помощью семантического анализа можно достаточно быстро из пачки странных запросов вычленить зерно смысла. Может, нужно докрутить UX продукта или дописать пояснение, как что-то работает?
Не обязательно быть «ВКонтакте», чтобы внедрять ML-инструменты в работу.
Используйте готовый докер-контейнер с установленными фреймворками и инструментами, чтобы снизить порог входа в разработку решений с ИИ.
Узнать больше →
Не все модели, которые делают разработчики «ВКонтакте» живут долго и счастливо. Летопись некоторых довольно скоротечна: они быстро затыкают дыры в процессах, разгружая агентов поддержки, а потом идут в утиль. Абсолютно нормально, что не все модели эволюционируют. Команда AI Research постоянно экспериментирует с ними, чтобы делать поддержку более адаптивной и современной, снабжать ее новыми технологиями.
Вот так по-разному можно написать слово «верификация».
«Но все это не безнадежные случаи. Да, люди задают вопросы в странных формулировках, но на них тоже находятся ответы. А значит, Долорес будет обучаться и в будущем поймет, что на самом деле хочет пользователь. Сейчас наша модель понимает: когда ее спрашивают, любит ли она “Группу крови”, имеют в виду песню, а не биологическую жидкость. И это здорово», — говорит Иван Самсонов.
Мы снова выложили на GitHub наш PHP-компилятор — KPHP. Он проделал большой путь, и чтобы рассказать о нём, сначала телепортируемся на шесть лет назад.
Но два года назад мы взялись за него, чтобы вдохнуть в эту разработку новую жизнь. Что сделали и какой получили результат — расскажу в этой статье. Она будет не о громком релизе, который можно прямо сейчас внедрять в свои проекты, а о внутренней разработке ВКонтакте, которую мы показываем сообществу и продолжаем развивать. Представлюсь: меня зовут Александр Кирсанов, я руковожу командой Backend-оптимизаций.
А теперь — телепортация.
Из 2020-го в 2014-й
Идёт 2014 год, и ВКонтакте опенсорсит репозиторий kphp-kdb. Наверняка многие из вас помнят этот момент.
Там было много движков от VK, а также первая версия KPHP. Тогда многие заинтересовались и пошли смотреть, но… Но. На тот момент там не было подробной инструкции по сборке, а также документации и сравнения с аналогами. Не было канала связи с разработчиками и поддержкой. Дальнейших апдейтов на GitHub также не случилось. И всё равно некоторые энтузиасты пробовали пользоваться этими инструментами — возможно, кому-то даже удалось, но доподлинно не известно.
Что касается KPHP — на тот момент он поддерживал версию PHP… даже не знаю. Что-то среднее между 4 и 5. Были функции, примитивы, строки и массивы. Но не было классов и ООП, не было современных (на момент 2014-го) паттернов разработки. И весь бэкенд-код ВКонтакте был написан в процедурном стиле, на ассоциативных массивах.
В общем, инфоповод был интересным, но во что-то большее не развился.
Из 2014-го в 2020-й
Сейчас, в конце 2020 года, весь бэкенд-код ВКонтакте по-прежнему на PHP. Пара сотен разработчиков, миллионы строк.
Но наш нынешний PHP-код мало чем отличается от актуального в индустрии. Мы пишем на современном PHP: у нас есть классы, интерфейсы и наследование; есть лямбды, трейты и Composer; а ещё строгая типизация, анализ PHPDoc и интеграция с IDE. И KPHP делает всё это быстрым.
В середине 2018 года мы возродили работу над KPHP — и за пару сумасшедших лет не только подтянули его к современным стандартам, но и добавили фичи, которых нет и не может быть в PHP. Благодаря этому провели ряд ключевых оптимизаций бэкенда, и это позволило продуктовым командам интенсивно наращивать функциональность. Да, тем самым снова замедляя бэкенд.
И сейчас мы решились на второй дубль: готовы поделиться инструментами, которые помогают нам в работе. Какими именно и что о них стоит знать — расскажу далее.
Давайте про KPHP: что это и как работает
KPHP берёт PHP-код и превращает его в С++, а уже этот С++ потом компилирует.
Эта часть — техническая, она большая. Мы заглянем внутрь и увидим, что происходит с PHP-кодом: как из него получается С++ и что следует за этим. Не слишком кратко, чтобы обозначить базовые вещи, но и не чересчур детально — в дебри не полезем.
KPHP выводит типы переменных
В PHP любая переменная — это ZVAL , то есть «что угодно». В переменную можно записать число, объект, замыкание; в хеш-таблицу — добавить одновременно числа и объекты; а в функцию — передать любое значение, а потом это разрулить в рантайме.
Если бы KPHP пошёл по такому пути, он бы не смог стать быстрым. Залог скорости — прежде всего в типизации. KPHP заставляет думать о типах, даже когда вы их явно не указываете.
В PHP мы не пишем типы переменных (за исключением редких type hint для аргументов) — поэтому KPHP сам выводит типы. То есть придумывает, как бы объявить переменную в C++, чтобы это было лучше.
Давайте посмотрим сниппеты на примерах.
Тут KPHP понял, что $a — это целое число, то есть int64_t в C++, и сгенерил такой код.
Казалось бы, просто изменили умножение на деление — но уже другое. Деление в PHP работает не так, как в C++. 8/9 в С++ будет целочисленный 0, поэтому есть функция divide() с разными перегрузками. В частности, для двух интов она выполняет сначала каст к double .
Следующий пример:
KPHP проанализировал все вызовы функции demo() и увидел, что она вызывается только с целыми и дробными числами. Значит, её аргумент — это double . Перегрузки нет в PHP, нет её и в KPHP (и не может быть, пока типы выводятся, а не указываются явно). Кстати, если внутри demo() будет вызов is_int($val) , то на аргументе 1 это будет true в PHP, но false в KPHP, так как 1 скастится к 1.0 . Ну и ладно, просто не надо так писать. Во многих случаях, если KPHP видит, что поведение может отличаться, выдаёт ошибку компиляции.
Здесь KPHP понял, что $a — это массив и в нём могут быть только целые числа. Значит, array<int64_t> . В данном случае array<T> — это кастомная реализация PHP-массивов, которая ведёт себя идентично. В PHP массивы могут быть и векторами, и хеш-таблицами. Они передаются по значению, но для экономии используют copy-on-write. Индексация числами и числовыми строками — это (почти) одно и то же. Всё это в KPHP реализовано похожим образом, чтобы работало одинаково.
В этом массиве (в хеш-таблице) мы смешиваем числа и строки. В KPHP есть специальный тип mixed , обозначающий «какой-нибудь примитив». Это напоминает ZVAL в PHP, однако mixed — это всего лишь 16 байт ( enum type + char[8] storage ). В mixed можно сложить числа и строки, но нельзя — объекты и более сложные типы. В общем, это не ZVAL , а что-то промежуточное.
Например, json_decode($arg, true) возвращает mixed , так как значение неизвестно на этапе компиляции. Или даже microtime() возвращает mixed , потому что microtime(true) — это float, а microtime(false) — массив (и кто это только придумал. ).
И последний пример:
А здесь мы получим Compilation error. Потому что нельзя вызывать функции по имени — нельзя и всё. Нельзя обращаться по имени к переменным, к свойствам класса — KPHP напишет ошибку, несмотря на то что это работает в PHP.
KPHP хоть и выводит типы, но позволяет их контролировать
Выше мы видели: когда разработчик типы не пишет, они выводятся автоматом.
Но их можно писать — с помощью PHPDoc @var/@param/@return или через PHP 7 type hint. Тогда KPHP сначала всё выведет, а потом проверит.
Ручной контроль позволяет избегать непреднамеренных ухудшений типов. Без @var переменная $ids вывелась бы как mixed[] , и никто бы этого не заметил. А когда разработчик пишет PHPDoc — значит, всё скомпилированное вывелось так же, как написано.
KPHP превращает PHP class в C++ struct
Если в обычном PHP классы — это более-менее те же хеш-таблицы, то в KPHP не так. На выходе получаются обычные плюсовые структуры, которые ведут себя ссылочно, как и в PHP (очень похоже на std::shared_ptr идеологически).
Каждое поле получается своего типа. Обращение к полю — это обращение к типизированному свойству с известным на момент компиляции смещением в памяти. Это в десятки раз эффективнее, чем хеш-таблицы, — как по скорости, так и по памяти.
Наследование — плюсовое (за исключением late static binding, но оно разруливается на этапе компиляции). Интерфейсы — это тоже плюсовое множественное наследование, там главное — refcount запрятать куда нужно. Правда, методы классов — это отдельные функции, принимающие this явно, так оно логичнее с нескольких позиций.
Это же значит, что у KPHP-классов много ограничений. Например, нельзя обращаться к полям по имени или вызывать так методы. Нет и не может быть магических методов. Классы совсем никак не стыкуются с mixed . Нельзя из функции вернуть «либо класс, либо массив» — не сойдётся по типам. Нельзя в функцию передать разные классы без общего предка (впрочем, в KPHP есть шаблонные функции, но это уже сложнее). Нельзя в хеш-таблицу сложить одновременно числа, строки и инстансы — нет, иди и делай типизированный класс или используй именованные кортежи.
В общем, когда разработчики пишут код, они всегда думают о типах и об их сходимости. Глупо ожидать, что напишешь фигню, а она заработает. Если ты следуешь ограничениям, получаешь скорость — иначе не бывает.
Как конкретно происходит конвертация PHP в C++
Многие знакомы с этой терминологией — те, кто занимался языками, или компиляторами, или статическим анализом.
Сначала PHP-файл превращается в линейный список токенов. Это такие минимальные неразрывные лексемы языка.
Потом линейный набор токенов превращается в синтаксическое дерево (abstract syntax tree). Оно согласовано с приоритетами операций и соответствует семантике языка. После этого этапа есть AST для всех достижимых функций.
Далее выстраивается control flow graph — это связывание функций и получение высокоуровневой информации о том, откуда и куда может доходить управление. Например, try/catch и if/else синтаксически похожи, но изнутри try можно добраться до внутренностей catch, а из if до тела else — нет. На выходе получается информация о соответствии вершин и переменных, какие из них используются на чтение, а какие на запись, и тому подобное.
Потом происходит type inferring. Это тот магический вывод типов, который ставит в соответствие всем PHP-переменным — переменные С++ с явно проставленными типами, а также определяет возвращаемые значения функций, поля классов и другое. Этот этап согласуется с тем, как код впоследствии будет исполняться на С++, какие там есть функции-хелперы, их перегрузки и прочее.
Имея типы, можно провести ряд оптимизаций времени компиляции. Например, заранее вынести константы, безопасно заинлайнить простые функции, а нетривиальные аргументы только для чтения передавать по const-ссылке, чтобы не вызывать конструктор копирования и не флапать рефкаунтер лишний раз.
И наконец, кодогенерация: все PHP-функции превращаются в С++ функции, а PHP-классы — в С++ структуры. Изменённые файлы и их зависимости перезаписываются, и код проекта на С++ готов.
Что дальше происходит с С++ кодом
Сгенерировать С++ из PHP — этого мало. Собственно говоря, это самое простое.
Во-первых, в PHP мы используем кучу функций стандартной библиотеки: header(), mb_strlen(), curl_init(), array_merge() . Их тысячи — и все должны быть реализованы внутри KPHP с учётом типизации и работать так же, как в PHP. Реализация всего PHP stdlib (а также KPHP-дополнений), всех PHP-типов с операциями и допущениями — это называется runtime, вон там квадратик сверху.
Во-вторых, PHP-сайт — это веб-сервер. Следовательно, и в KPHP должна быть вся серверная часть, чтобы можно было в том же nginx подменить PHP-шный upstream на KPHP-шный — и всё продолжало работать так же. KPHP поднимает свой веб-сервер, оркестрирует процессы, заполняет суперглобалы и переинициализирует состояние, как и PHP… Это тоже хардкорная часть — называется server, квадратик снизу.
Многие технические проблемы остаются за кадром — их не опишешь в статье на Хабре. Чего стоит один только сбор трейсов при ошибках: ведь в С++ не получить человекочитаемый стек, а хочется разработчику вообще его на PHP-код намаппить. Гигантское количество внутренних нюансов, множество подпорок и легаси — но в итоге продукт хорошо работает и развивается.
KPHP vs PHP: что мы не поддерживаем
По итогам предыдущей части статьи должно было сложиться чёткое понимание: KPHP не может взять любой PHP-код и ускорить его. Так не работает.
Если код работает на PHP — это не значит, что он заработает на KPHP.
KPHP — это отдельный язык, со своими ограничениями и правилами.
- KPHP не компилирует то, что принципиально не компилируемо. Например, выше мы говорили про вызов функции по имени. Туда же — eval, mocks, reflection. PHP extensions тоже не поддерживаются, так как внутренности KPHP пересекаются с Zend API примерно на 0%. Так что PHPUnit запустить на KPHP не выйдет. Но и не нужно! Потому что мы пишем на PHP, мы тестируем на PHP, а KPHP — для продакшена.
- KPHP не компилирует то, что не вписывается в систему типов. Нельзя в массив сложить числа и объекты. Нельзя накидать рандомных интерфейсов с лямбдами и разгрести это в рантайме. В KPHP нет волшебного типа any .
- KPHP не поддерживает то, что нам в VK никогда не было нужно. ВКонтакте куча своих движков — и мы с ними общаемся по специальному протоколу, который описан в TL-схеме. Поэтому нам никогда не нужна была человеческая поддержка MySQL, Postgres, Redis и прочего.
- Часть PHP-синтаксиса просто ещё не покрыта. Текущий уровень поддержки находится примерно на уровне PHP 7.2. Но отдельных синтаксических вещей нет: что-то сделать очень сложно, до другого не дошли руки, а оставшееся мы считаем ненужным. Например, KPHP не поддерживает генераторы и наследование исключений — мы не любим исключения. Ссылки поддержаны только внутри foreach и в аргументах функций. Всё так, потому что мы разрабатывали KPHP как удобный инструмент для наших задач, — а компилировать сторонние библиотеки в планы не входило.
KPHP vs PHP: в чём мы превосходим
В скорости. Если использовать KPHP грамотно, то код будет работать значительно быстрее, чем на PHP 7.4. А некоторых вещей нет в PHP — и чтобы при разработке он не падал с ошибками, там просто заглушки.
Итак, в чём наш профит:
- строгая типизация, примитивы на стеке, а классы — это не хеш-таблицы;
- асинхронность (аналог корутин);
- шаренная память для всех воркеров одновременно, живущая между исполнениями скрипта;
- оптимизации времени компиляции;
- оптимизации времени рантайма, чаще всего при чистых типах.
Например, нам нужно загрузить пользователя и одновременно посчитать какую-то подпись запроса (CPU-работа — допустим, это долго). В обычном (синхронном) варианте это выглядит так:
Но эти действия независимы — пока грузится пользователь, можно считать хеш, а потом дождаться загрузки. В асинхронном варианте это происходит так:
То есть отличие от паттерна async/await в том, что мы никак не меняем сигнатуру функции loadUser() и всех вложенных. Просто вызываем функцию через конструкцию fork() , и она становится прерываемой. Возвращается future<T> , и потом можно подождать результат через wait() . При этом в PHP отдельно реализованы PHP-функции fork и wait, которые почти ничего не делают.
В итоге: с одной стороны, мы следим за типами. С другой, можем делать запросы к движкам параллельно. С третьей, zero-cost abstractions (плохой термин, но пусть) — константы напрямую инлайнятся, всякие простые геттеры и сеттеры тоже, и оверхед от абстракций в разы меньше, чем в PHP.
Если говорить про бенчмарки, то на средних VK-страничках у нас профит от 3 до 10 раз. А на конкретных участках, где мы прицельно выжимали максимум, — до 20–50 раз.
Это не значит, что можно просто взять PHP-код и он будет работать в 10 раз быстрее. Нет: рандомный сниппет, даже будучи скомпилированным, может и не впечатлить, потому что чаще всего там навыводится mixed .
Это значит, что PHP-код можно превратить в быстрый, если думать о типах и использовать built-in KPHP-функции.
KPHP и IDE
Система типов в KPHP значительно шире и строже, чем в PHP. Мы уже говорили, что нельзя смешивать в массиве числа и объекты — потому что какой тогда тип элементов этого массива?
Нельзя! А как можно? Например, сделать отдельный класс с двумя полями и вернуть его. Или вернуть кортеж (tuple) — специальный KPHP-тип.
К функции можно даже PHPDoc написать, KPHP его прочитает и после стрелочки (->) поймёт:
Но вот проблема: KPHP-то понимает, а вот IDE нет. Ведь tuple — это наша придумка, как и разные другие штуки внутри PHPDoc.
Не так давно у нас появился KPHPStorm — плагин для PhpStorm, который расширяет подсказки, оставляя рабочим рефакторинг. А ещё сам трекает сходимость типов значительно строже нативного.
Если вы интересуетесь разработкой плагинов для IDEA — загляните, все исходники открыты. KPHPStorm глубоко внедряется во внутренности IDE (через кучу недокументированного API). Многое пришлось пройти, чтобы всё заработало. Спасибо ребятам из JetBrains за помощь.
Закругляемся: вот он Open Source, что дальше?
Мы усовершенствовали KPHP и показываем его вам: можно посмотреть, покомпилировать что-то простое — теперь есть все инструкции и даже Docker-образ. Но будем честны: KPHP пока остаётся инструментом, заточенным под задачи VK, и для более широкого применения в реальных сторонних проектах он ещё не адаптирован.
Почему так? Мы всегда поддерживали в первую очередь собственные движки ВКонтакте. KPHP не умеет в Redis, MongoDB и другое. Даже Memcache у нас свой, который по RPC работает. Даже перед ClickHouse, который у нас развёрнут, стоит собственная proxy, куда мы тоже ходим по TL/RPC.
Мы никогда не поддерживали стандартные базы, потому что это не было нужно. Но знаете, в чём прикол? Если мы не выйдем в Open Source, этого никогда и не произойдёт — потому что это так и не потребуется. За последние два года KPHP прошёл огромный путь, возродился. Мы можем ещё пару лет продержать его у себя. Можем покрыть возможности PHP 8, сделать ещё ряд оптимизаций, освоить микросервисы и интеграцию с Kubernetes — но нам не будут нужны стандартные базы. И через два года будет то же самое.
Только открытость и внешняя заинтересованность помогут выделить дополнительные ресурсы, чтобы пилить фичи не только для нас, но и наружу. Может, уже среди читателей этой статьи найдутся те, кому интересно с нами развивать это направление? Почему нет — у нас очень маленькая команда, и мы занимаемся интересными, глубокими и совершенно не продуктовыми вещами.
Теперь вся разработка KPHP будет вестись на GitHub. Правда, CI пока останется в приватной инфраструктуре. Движки по-прежнему будут закрыты — но когда-нибудь команда движков, надеемся, тоже решится вынести в сообщество хотя бы часть кода.
У вас может возникнуть вопрос: а сложно ли добавить поддержку протоколов MySQL, Redis и других? И да и нет. Если пробовать интегрировать готовые модули — скорее всего, будет фейл. Особенно если они порождают дополнительные потоки, ведь воркеры принципиально однопоточные. К тому же, просто поддержать протокол, может, и не проблема — но сложно сделать его «прерываемым», чтобы это стыковалось с корутинами. А вот к этому сейчас код совершенно не готов: там корутины тесно переплетены с сетью и TL. Непростая история, в общем :) Но выполнимая, и над этим надо работать.
Итак: где ссылки, как попробовать
Мы рассчитываем, что в дальнейшем нашей команде — возможно, при помощи сообщества — удастся развить KPHP так, чтобы он стал полезным инструментом и вне ВКонтакте. Не так важно, как быстро это произойдёт. В любом случае, это тот ориентир, который теперь стоит перед проектом.
Самая популярная социальная сеть в рунете пролила немного света на то, как же она работает. Представители проекта в лице Павла Дурова и Олега Илларионова на конференции HighLoad++ ответили на шквал вопросов по совершенно разным аспектам работы Вконтакте, в том числе и техническим. Спешу поделиться своим взглядом на архитектуру проекта по результатам данного выступления.
Платформа
-
Linux - основная операционная система - балансировка нагрузки + XCache + mod_php
- Собственная СУБД на C, созданная "лучшими умами" России - прослойка для реализации XMPP, живет за HAProxy
- Изображения отдаются просто с файловой системы xfs - конвертирование видео
Статистика
Архитектура
Общие принципы
Волшебная база данных на C
Этому продукту, пожалуй, уделялось максимум внимания аудитории, но при этом почти никаких подробностей о том, что он собственно говоря собой представляет, так и не было обнародовано. Известно, что:
Аудио и видео
Эти подпроекты являются побочными для социальной сети, на них особо не фокусируются. В основном это связанно с тем, что они редко коррелируют с основной целью использования социальной сети - общением, а также создают большое количество проблем: видео траффик - основная статья расходов проекта, плюс всем известные проблемы с нелегальным контентом и претензиями правообладателей. Медиа-файлы банятся по хэшу при удалении по просьбе правообладателей, но это неэффективно и планируется усовершенствовать этот механизм.
1000-1500 серверов используется для перекодирования видео, на них же оно и хранится.
Как известно, некоторое время назад появилась возможность общаться на Вконтакте через протокол Jabber (он же XMPP). Протокол совершенно открытый и существует масса opensource реализаций.
По ряду причин, среди которых проблемы с интеграцией с остальными сервисами, было решено за месяц создать собственный сервер, представляющий собой прослойку между внутренними сервисами Вконтакте и реализацией XMPP протокола. Основные особенности этого сервиса:
Интеграция со внешними ресурсами
Во Вконтакте считают данное направление очень перспективным и осуществляют массу связанной с этим работы. Основные предпринятые шаги:
- Максимальная кроссбраузерность для виджетов на основе библиотек easyXDM и fastXDM
- Кросс-постинг статусов в Twitter, реализованный с помощью очередей запросов
- Кнопка "поделиться с друзьями", поддерживающая openGraph теги и автоматически подбирающая подходящую иллюстрацию (путем сравнивание содержимых тега <title> и атрибутов alt у изображений, чуть ли не побуквенно)
- Возможность загрузки видео через сторонние видео-хостинги (YouTube, RuTube, Vimeo, и.т.д.), открыты к интеграции с другими
Интересные факты не по теме
- Процесс разработки близок к Agile, с недельными итерациями
- Ядро операционной системы модифицированно (на предмет работы с памятью), есть своя пакетная база для Debian
- Фотографии загружаются на два жестких диска одного сервера одновременно, после чего создается резервная копия на другом сервере
- Есть много доработок над memcached, в.т.ч. для более стабильного и длительного размещения объектов в памяти; есть даже persistent версия
- Фотографии не удаляются для минимизации фрагментации
- Решения о развитии проекта принимают Павел Дуров и Андрей Рогозов, ответственность за сервисы - на них и на реализовавшем его разработчике
- Павел Дуров откладывал деньги на хостинг с 1 курса :)
Подводим итоги
Завеса тайны насчет технической реализации Вконтакте была немного развеяна, но много моментов все же остались секретом. Возможно в будущем появится более детальная информация о собственной СУБД Вконтакте, которая как оказалось является ключом к решению всех самых сложных моментов в масштабируемости системы.
Если хотите быть в курсе новых веяний в сфере масштабируемости высоконагруженных интернет-проектов - по традиции рекомендую подписаться на RSS.
Без малого 100 миллионов пользователей — такова аудитория ВКонтакте, которую
надо обслуживать. Быстро и без перебоев. Долгое время подробности технической
реализации ВКонтакте оставались секретом. Но недавно самая популярная в России
социальная сеть пролила немного света на то, как она все-таки устроена. В конце
октября в Москве состоялась конференция HighLoad++, на которой представители
ВКонтакте в лице Павла Дурова и Олега Илларионова, наконец, рассказали кое-что
об архитектуре социальной сети.
Парней буквально завалили вопросами по совершенно различным аспектам работы
ВКонтакте, в том числе и техническим. Еще бы. Легко представить нагрузку на
серверную часть сервиса: как много людей ты знаешь, которые не пользуются этой
социальной сетью? А сколько времени ты там проводишь, тратя бесценные часы своей
жизни на общение с друзьями, просмотр видео, игры, музыку? Математика довольно
проста: баснословное количество пользователей * масса проведенного времени на
ресурсе = запредельное количество запросов к веб-серверам и базе данных +
терабайты постоянно загружаемых и просматриваемых фотографий, видео и аудио.
Взаимодействие участников социальной сети происходит практически в режиме
реального времени: все друзья должны немедленно узнавать о том, что произошло с
каждым из участников. Сайт должен быть доступен 100% времени. Как это удается?
Статистика ВКонтакте
Платформа
Для нас, конечно, особый интерес представляет именно архитектура проекта: как
взаимодействуют основные компоненты системы, какие собственные разработки
потребовались, какими трюками пришлось воспользоваться. Но прежде, чем перейти к
ней, необходимо ознакомиться с базовыми вещами — используемыми технологиями и
продуктами.
Ситуация с хранением данных выглядит достаточно размыто: с одной стороны,
активно используется собственная система управления базами данных, написанная на
C и созданная "лучшими умами" России, с другой — часто упоминалась MySQL в роли
основного хранилища. Подробнее про собственную базу данных ВКонтакте я расскажу
ниже. Говоря о хранении данных, нельзя не упомянуть о таком важном аспекте, как
кэширование часто используемой информации (расположение её в оперативной памяти
для быстрого доступа). Для этого используется очень популярный продукт в этой
области — memcached. Если ты не слышал: эта система позволяет осуществлять очень
простые атомарные операции, такие как расположение и получение произвольных
данных по ключу. Основной фишкой является молниеносно быстрый доступ и
возможность легкого объединения оперативной памяти большого количества серверов
в общий массив для временного хранения "горячих" данных.
Основные используемые технологии
-
—
- Собственная СУБД на C, созданная "лучшими умами" России — прослойка
для реализации протокола XMPP, живет за HAProxy (haproxy.1wt.eu) — файловая система
для хранения изображений и отдачи пользователю —
конвертирование видео
основная операционная система —
балансировка нагрузки +
XCache + mod_php
Архитектура
Самым заметным отличием от архитектуры многих других крупных
интернет-проектов является тот факт, что сервера ВКонтакте многофункциональны.
Т.е. нет четкого разделения на серверы баз данных, файловые серверы и т.д. — они
одновременно используются в нескольких ролях. При этом перераспределение
ролей происходит в полуавтоматическом режиме с участием системных
администраторов. С одной стороны, это оптимизирует эффективность использования
системных ресурсов, что хорошо, но с другой — повышает вероятность конфликтов на
уровне операционной системы в рамках одного сервера, что влечет за собой
проблемы стабильности. Впрочем, несмотря на использование серверов в разных
ролях, вычислительные мощности проекта обычно используются менее чем на 20%.
Балансировка нагрузки между серверами происходит по многоуровневой схеме,
которая включает в себя балансировку на уровне DNS (домен обслуживается с
помощью 32 IP-адресов), а также маршрутизацию запросов внутри системы, причем
разные сервера используются для разных типов запросов. Например, генерация
страниц с новостями (теперь это принято называть микроблогом) работает по хитрой
схеме, использующей возможности протокола memcached по параллельной отправке
запросов на получение данных по большому количеству ключей. В случае отсутствия
данных в кэше, аналогичный запрос отправляется системе хранения данных, а
полученные результаты подвергаются сортировке, фильтрации и отбрасыванию лишнего
уже на уровне PHP-кода. Похожим образом этот функционал работает и в Facebook
(они недавно обменивались опытом), только вместо собственной СУБД в Facebook
используют MySQL.
В стенах ВКонтакте было разработано большое количество софта, который более
точно удовлетворяет потребностям проекта, чем доступные opensource и
коммерческие решения. Помимо упоминавшейся собственной СУБД у них есть система
мониторинга с уведомлением по СМС (Павел сам помогал верстать интерфейс),
автоматическая система тестирования кода и анализаторы статистики и логов.
В проекте используется достаточно мощное оборудование, ориентировочно были
названы следующие характеристики серверов:
Примечательно, что сервера не брендированные, а собираются специализированной
российской компанией. Сейчас оборудование проекта расположено в 4 датацентрах в
Санкт-Петербурге и Москве, причем вся основная база данных располагается в
питерском датацентре, а в Москове хостится только аудио и видео. В планах
сделать репликацию базы данных с другим датацентром в Ленинградской области, а
также использовать Content Delivery Network для повышения скорости скачивания
медийного контента в регионах.
Многие проекты, сталкивающиеся с большим количеством фотографий, часто
изобретают собственные решения по их хранению и отдаче пользователям. Об этом
был первый вопрос, заданный Павлу из зала: "Как вы храните изображения?" — "На
дисках!". Так или иначе, представители ВКонтакте заявили, что вся эта куча
фотографий всех цветов и размеров просто хранится и отдается с файловой системы
(используют xfs) большого количества серверов, без дополнительных изысков.
Смущает разве что тот факт, что у других крупных проектов такой подход не
сработал — наверное, они не знали волшебного слова :).
Не менее волшебной представляется та самая собственная база данных на C.
Этому продукту, пожалуй, было уделено основное внимание аудитории, но при этом
почти никаких подробностей о том, что он, собственно говоря, собой представляет,
так и не было обнародовано. Известно, что СУБД разработана "лучшими умами"
России, победителями олимпиад и конкурсов TopCoder, а также что она используется
в самых высоконагруженных сервисах ВКонтакте:
В отличие от MySQL используется нереляционная модель данных, а большинство
операций осуществляется в оперативной памяти. Интерфейс доступа представляет
собой расширенный протокол memcached. Специальным образом составленные ключи
возвращают результаты сложных запросов (чаще всего специфичных для конкретного
сервиса).
Система проектировалась с учетом возможности кластеризации и автоматической
репликации данных. Разработчики хотели бы сделать из данной системы
универсальную СУБД и опубликовать под GPL, но пока не получается из-за высокой
степени интеграции с остальными сервисами.
Интересные факты о ВКонтакте
- Процесс разработки близок к методологии Agile с недельными
итерациями (циклами), в рамках которых проходят все этапы разработки:
планирование, анализ требований, проектирование, разработка и
тестирование. - Ядро операционной системы модифицировано (на предмет работы с
памятью), есть своя пакетная база для Debian. - Фотографии загружаются на два жестких диска одного сервера
одновременно, после чего создается резервная копия на другом сервере. - Есть много доработок над memcached, в.т.ч. для более стабильного и
длительного размещения объектов в памяти; есть даже версия,
обеспечивающая сохранность данных. - Фотографии не удаляются для минимизации фрагментации.
- Решения о развитии проекта принимают Павел Дуров и Андрей Рогозов,
ответственность за сервисы — на них и на реализовавшем его разработчике. - Павел Дуров откладывал деньги на хостинг с 1 курса :).
Подпроекты
Сервисы аудио и видео являются побочными для социальной сети, на них
создатели проекта особо не фокусируются. В основном это связано с тем, что они
редко коррелируют с основной целью использования социальной сети — общением, а
также создают большое количество проблем. Видеотрафик — основная статья расходов
проекта, плюс всем известные проблемы с нелегальным контентом и претензиями
правообладателей. 1000—1500 серверов используются для перекодирования видео, на
них же оно и хранится. Медиа-файлы банятся по хэшу при удалении по просьбе
правообладателей, но это неэффективно и планируется усовершенствовать этот
механизм. Очевидно, речь идет о разработке более интеллектуального алгоритма
распознавания аудио- и видео-контента по тегам, как это, к примеру, реализовано
в YouTube, где загруженный видеоролик, нарушающий лицензию, может быть
автоматически удален уже через несколько минут после загрузки.
При выборе системы хранения данных думали о нереляционных системах хранения
данных (в частности, о MongoDB), но в итоге решили воспользоваться привычной
MySQL. Сервис функционирует на 5-ти серверах разной конфигурации, на каждом из
которых работает код на node.js (по 4 процесса на сервер), а на трех самых
мощных — еще и MySQL. Интересной особенностью является отсутствие связи между
группами друзей в XMPP с группами друзей на сайте — сделано по просьбе
пользователей, которые не хотели, чтобы их друзья из-за плеча видели, в какой
группе они находятся.
Важным подпроектом является также интеграция с внешними ресурсами, которую в
условиях высоконагруженного сервиса реализовать далеко не так просто. Все чаще
на страницах сторонних проектов можно увидеть виджеты "Мне нравится",
позволяющими быстро поделиться интересным постом со своими друзьями, а также
небольшие блоки "Мы ВКонтакте" с данными о пользователях внутри привязанной
группы. Основные шаги, предпринятые в этом направлении, с небольшими
комментариями:
- Максимальная кроссбраузерность для виджетов и IFrame-приложений на
основе библиотек easyXDM и fastXDM, обеспечивающих взаимодействие между
сторонним ресурсом и программным интерфейсом ВКонтакте. Таким образом была
решена проблема кроссдоменного взаимодействия и вопрос работы во всех
браузерах. - Кросс-постинг статусов в Twitter, реализованный с помощью очередей
запросов. - Кнопка "поделиться с друзьями", поддерживающая openGraph-теги и
автоматически подбирающая подходящую иллюстрацию (путем сравнивания
содержимого тега <title> и атрибутов alt у изображений. - Возможность загрузки видео через сторонние видео-хостинги (YouTube,
RuTube, Vimeo, и т.д.).
Не секрет
Завеса тайны насчет технической реализации ВКонтакте была немного развеяна,
опубликовано куча интересных аспектов, но все же многие моменты по-прежнему
остаются секретом. Возможно, в будущем появится более детальная информация о
собственной СУБД ВКонтакте, которая, как оказалось, является ключом к решению
всех самых сложных моментов в масштабируемости системы. Сейчас, как бы кто ни
относился к ВКонтакте, сервис является очень интересным с точки зрения
построения высоконагруженных систем. Все-таки 11 миллиардов запросов в день,
высочайший аптайм и почти 100 миллионов пользователей — дорогого стоят.
Warning
Далеко не все крупные проекты публично раскрывают аспекты построения
архитектуры. Даже примерная информация о том, что у них происходит и как они
работают, часто держится в секрете. Источником информации чаще всего
оказываются либо выступления представителей проектов на конференциях, либо
различные интервью/публикации сотрудников. Информация для этого материала
была собрана автором из этих же источников и не является официально
подтвержденной со стороны ВКонтакте.
Читайте также: