Сжимаем процессорное время
Базовый уровень, на котором происходит ускорение, — железо. Нельзя полагаться только на закон Мура. Сейчас надо сжимать процессорное время и выводить в продакшн как можно больше.
За 2023 год нам удалось сэкономить суммарно 100 тысяч процессорных ядер, и мы надеемся эту тенденцию продолжить.
Всякий, кто когда-либо занимался оптимизацией программ, знаком с Flame Graph. Это инструмент 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.
Сама по себе unwind table достаточно компактная, но для того, чтобы её получить, нужно было написать большое количество кода. Сейчас в Kernel Space крутится наш специальный плагин — eBPF. Это уже небольшая программа для раскрутки стека, которая на вход получает стек от процессора и предпосчитанную таблицу. Она эффективно пересылает стек адресов функций в User Space, и Perforator аналогично perf агрегирует информацию. На выходе получаются очень точные Flame Graphs.
Ещё одно преимущество Perforator в том, что обычный продакшен-бинарник не получает почти никакого замедления — существенно меньше 1%. И это настраиваемый параметр.
Сейчас Perforator растянут на несколько процентов наших сервисов, но в перспективе он должен охватить все 100%.
Ускоряем обработку данных
Если оптимизировать только железо, это никак не отразится на внешнем мире, на пользователях. Для этого нужно, чтобы огромное количество данных не просто летало во внутренней сети, но и очень быстро обрабатывалось.
Серьёзный прорыв в этом направлении произошёл в рекламе. У Яндекса обширная рекламная сеть — не только на Поиске, но и на сайтах. Всё это создаёт огромную нагрузку на рекламный движок.
Здесь выручает тот факт, что у нас много железа, но быстрая обработка данных требует инженерных решений. За последние пару лет нам удалось серьёзно продвинуться. Ещё несколько лет назад система была 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 тысяч лет в год, которые мы экономим нашим пользователям.