Ускоритель в масштабе планеты: как инженеры управляют временем

НачалоСжимаем процессорное времяУскоряем обработку данныхУпрощаем релизы Экономим время пользователей

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

Технический директор Яндекс Поиска Алексей Гусаков рассказал, как именно они это делают на разных уровнях.

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

За 2023 год нам удалось сэкономить суммарно 100 тысяч процессорных ядер, и мы надеемся эту тенденцию продолжить.

Всякий, кто когда-либо занимался оптимизацией программ, знаком с Flame Graph. Это инструмент perf, который позволяет увидеть слабые места в коде и понять, какие части кода необходимо оптимизировать.

Так выглядит perf, запущенный на одной из программ Яндекса, которая работает на каждый поисковый запрос

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

Бинарники с -fno-omit-frame-pointer скомпилированы специально для perf. Флаг не убивает frame pointers, поэтому perf с такими бинарниками работает отлично. Но за это приходится платить одним из 15 процессорных регистров. Программы, скомпилированные в таком режиме, работают до 10% дольше. Причём нельзя заранее предсказать, насколько именно.

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

На обычных бинарниках тоже можно запустить perf, и он всегда будет работать. Но Flame Graph будет неточным — пользоваться таким невозможно.

Почему perf для обычных бинарников не работает нормально? Загвоздка в устройстве Linux. У него есть два системных пространства: User Space и Kernel Space. В Kernel Space крутятся проверенные бинарники, которые имеют прямой доступ к процессору. В частности, функция раскрутки стека для perf. А сам perf относится к User Space.

Каждые 10 в 7 процентных тиков perf дёргает функцию раскрутки стека. Если бинарники скомпилированы специально для perf, всё работает хорошо. Но с обычными бинарниками выходит криво.

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

Примерно 70% любого бинарника составляет debug info. Это структура данных под названием DWARF. В ней сложена полезная информация, которая позволяет находить имена переменных, названия функции и прочее.

Если при раскрутке стека использовать структуру DWARF, всё будет работать нормально. Но Торвальдс (Linux) не любит DWARF и не доверяет ему.

И происходит следующее:

→ Стек нашего типичного приложения занимает примерно 8 ГБ — это очень много
→ Функция раскрутки стека пересылает верхние 64 КБ — мизерный процент от всего стека
→ Стек раскручивается уже в User Space
→ 99% отправленной информации совсем бесполезны для тулзы perf

В итоге perf работает неэффективно, а за счёт того, что пересылается только малая часть стека, Flame Graph получается неточным.

Нам в Яндексе важно было иметь возможность зайти на любую машину из облака и посмотреть статистику любого бинарника, который там крутится. Или войти в единый репозиторий, взять любую строчку кода и понять, во сколько буквально она обходится компании: сколько раз вызывается, насколько долго работает и так далее. Это сильно сэкономило бы процессорное время.

Мы решили эту проблему с помощью нашей модификации под названием Perforator.

Разница с perf в том, что Perforator использует в User Space структуру DWARF — конвертирует её в unwind table, который помогает раскручивать стек

Сама по себе unwind table достаточно компактная, но для того, чтобы её получить, нужно было написать большое количество кода. Сейчас в Kernel Space крутится наш специальный плагин — eBPF. Это уже небольшая программа для раскрутки стека, которая на вход получает стек от процессора и предпосчитанную таблицу. Она эффективно пересылает стек адресов функций в User Space, и Perforator аналогично perf агрегирует информацию. На выходе получаются очень точные Flame Graphs.

Ещё одно преимущество Perforator в том, что обычный продакшен-бинарник не получает почти никакого замедления — существенно меньше 1%. И это настраиваемый параметр.

Сейчас Perforator растянут на несколько процентов наших сервисов, но в перспективе он должен охватить все 100%.

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

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

Каждую секунду рекламный движок должен 500 тысяч раз отобрать из 10 млрд вариантов те, которые идеально подходят пользователю, и уложиться в 300 миллисекунд

Здесь выручает тот факт, что у нас много железа, но быстрая обработка данных требует инженерных решений. За последние пару лет нам удалось серьёзно продвинуться. Ещё несколько лет назад система была Full State: у неё было какое-то состояние, мы сутки копили updates, после этого запускали MapReduce, переваривали состояние и выкатывали новое.

Сейчас от Full State мы перешли к Streaming-режиму — обрабатываем относительно небольшие дельты, которые обновляют всю систему. Такой подход привёл к ускорению обработки: по тяжёлым данным — индексы, модели — мы перешли от суток к часам, по лёгким — счётчики, realtime-фичи — от часов к секундам. И, как это ни парадоксально, за счёт инкрементальных обновлений Streaming-режим обошёлся не дороже режима Full State. А в некоторых сервисах, в частности в Поиске, инкрементальные обновления базы привели ещё к экономии железа.

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

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

Допустим, в Яндексе есть команда, которой надо анализировать картинки. Кстати, у нас почти все продуктовые команды — от Рекламы до Яндекс Маркета — так или иначе с этим связаны. Было бы странно, если бы каждая создавала свои ML-модели с нуля или дорабатывала open source решения. Вместо этого у нас есть одна на всех базовая технология — с обвязкой и тулингом, чтобы быстро затюнить модель под свои задачи и не разбираться, что там у неё под капотом.

За последний год появились две новые — YandexART и YandexGPT.

YandexART начинался как прикол: «Попробуем погенерить картинки». Из этой технологии выросло приложение Шедеврум. Сейчас эта базовая технология, которая используется в нескольких сервисах, где надо генерить/улучшать/преобразовывать картинки. Например, с её помощью можно поместить товар на красивый фон.

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

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

Возьмём простой на первый взгляд продукт — Яндекс Клавиатуру. Даже у неё под капотом есть нейросети, которые умещаются в 50 МБ. Там есть разные режимы. К примеру, если пользователь промахнулся мимо клавиши, динамическая сетка позволяет на лету исправить ошибку. Есть режим «Свайп», который позволяет вслепую вводить слова и сильно экономит время пользователя. Всё это заметно ускоряет работу. Если помножить результаты на текущий масштаб аудитории, с помощью нейросвайпа мы экономим нашим пользователям суммарно 3,5 тысячи лет в год.

Недавно мы внедрили в Яндекс Браузер суммаризацию видео. Нажав на кнопку «Суммаризировать», пользователь видит краткий пересказ видео с буллитами и таймингом. Это позволяет:

  • Быстро ознакомиться с содержанием видео и решить, стоит ли его смотреть
  • Выбрать наиболее интересные фрагменты — если видео длится долго, это очень помогает

Пользователи Яндекса используют функцию «краткого пересказа» на видео средней продолжительностью 26 минут. На сам просмотр после этого они тратят в среднем минуту. Часто это происходит потому, что становится ясно: не стоит тратить на это время. Суммарно за месяц этой опцией воспользовались 10 миллионов раз, и это сэкономило нашим пользователям 475 лет.

Ещё один пример — Алиса. Умные устройства давно вошли в нашу жизнь, и сегодня ими пользуются порядка 7 млн человек. С помощью Алисы дома люди решают порядка пяти задач. Суммарно это экономит им по паре минут. Умножаем на количество пользователей и получаем порядка 10 тысяч лет в год, которые мы экономим нашим пользователям.

Поделитесь увиденным

Скопировать ссылку
ТелеграмВКонтакте