Мы побеседовали с руководителем направления системного программирования в «Криптоните» Александром Авраменко о карьерном пути Rust-разработчика, особенностях языка Rust и его применении к моделям машинного обучения в высоконагруженных системах.

— Александр, расскажи о своём карьерном пути.

Я учился в МАИ, получил диплом с отличием по специальности «бортовые системы». Всегда любил вычислительную технику и программирование. Уже в те времена был язык С, на котором я помогал писать пользовательские интерфейсы, заготовки для лабораторного САПРа и т.д.

Затем работал в ОКБ Сухого, делал ПО лётного тренажёра. В «живой» кабине с вмонтированными экранами подключался наш софт. Мы визуализировали облака, землю, аэродромы, рисовали карты, план полёта, индикаторы...

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

После этого в 2020 году поступило предложение от «Криптонита». Я принял его, так как мне как раз хотелось погрузиться в новый масштабный проект.

— Чем ты занимаешься в «Криптоните»?

Я возглавляю группу системного программирования на Rust. Мы создаём сетевые сервисы и конвейеры обработки потоков больших данных с применением моделей машинного обучения (ML) в реальном времени.

Ранее Александр поделился с нами лайфхаками по управлению группой разработчиков: он рассказал о «подводных камнях» на собеседовании, мотивации команды и ситуации на рынке труда «растистов».

Это могут быть разные данные: картинки, видео- и аудиозаписи… любые файлы, которые наш пользователь хочет как-то обрабатывать. Обычно такие большие объёмы данных обрабатываются моделями машинного обучения. И здесь возникает технически сложная задача: написать такой софт, который, с одной стороны, обеспечит непрерывный поток входных данных, а с другой — подаст их на вход моделям. А ещё он будет накапливать результаты, которые эти модели формируют, складывать их в хранилище, систематизировать и делать это в режиме 24/7 в течение месяцев без перезагрузки.

— То есть должна быть сбалансированная система с буферизацией, классификацией, сортировкой данных…

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

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

Всё верно. Ещё, когда приступаешь к такой задаче, слегка обескураживает обилие процессорных ядер и вычислительных потоков, которые нужно балансировать динамически. Поток данных то увеличивается, то уменьшается, когда-то необходимо отправлять результаты на сохранение, поскольку они постоянно накапливаются. В зависимости от текущих потребностей необходимо перераспределять общие вычислительные ресурсы между внутренними заданиями.  Эти и похожие частные задачи в комплексе решаются в нашем программном обеспечении. Однако, обработка потока данных в реальном времени — не единственное применение наших приложений.

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

— Сейчас вы используете для облачных вычислений графические процессоры?

Конечно! В половине наших разработок приходится использовать CUDA-библиотеки, чтобы передавать пакеты подготовленных специальным образом данных для моделей и забирать оттуда результаты.

— Вы на OpenCL пробовали что-то делать?

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

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

Для совместной работы в компании используется GitLab — в разработке, Confluence — в более общих областях. Мы пользуемся общим инструментарием: так удобнее взаимодействовать с другими командами и руководством.

Технологический стек также определяется для отдела разработки в целом, с учётом общих задач: OpenShift, Kafka, Clickhouse, Scylla и т.д.

Что касается инструментов собственно разработки, то в Rust есть де-факто стандарт: cargo + rust-analyzer + некоторый выбор IDE, например, VSCode, IntelliJ, CLion, Neovim, Emacs.

— Что ещё должен знать Rust-разработчик для эффективной работы над реальными проектами?

— Мы создаём довольно сложный софт, работающий в условиях:

  • высоких нагрузок по потоку данных;

  • недопустимости потерь при обработке данных;

  • длительной работы во времени, месяцами без перезапуска;

  • использования всех доступных вычислительных мощностей;

  • задействования и обмена данными с GPU;

  • отсутствия интерфейса пользователя.

Поэтому мы используем проверенные временем сторонние решения отдельных задач, например, для буферизации данных, хранения результатов, мониторинга состояния.

С нашими сервисами взаимодействует другой софт на общей платформе, поэтому нужно понимание принципов и технологий такого взаимодействия.

Чем шире у разработчика знания в использовании принятого у нас технологического стека, тем более эффективно он работает.

С точки зрения программирования, помимо знания самого языка, создание качественного софта требует навыков профилировки и написания бенчмарков, опыта в использовании CI, развёртывания в Openshift, работы с докером и пр.

— Почему твой выбор пал на Rust? Каковы особенности разработки на этом языке?

Я пропагандирую коллегам переход на Rust:)

  • он превосходит С++ по выразительности: код с одинаковой функциональностью в разы короче на Rust;

  • не уступает C++ по производительности итогового приложения;

  • компилятор даёт существенные гарантии надёжности кода и безопасности работы с памятью, одной из основных проблем в системном и серверном софте;

  • цикл разработки существенно короче (написать код — примерно 80% готовности, оставшиеся 20% — отладка приложения, как правило, логики);

  • огромное количество библиотек и фреймворков для любых областей написано на Rust;

  • совместим с наследием на С++.

— Какие языки программирования являются лучшей базой для перехода на Rust?

Компилируемые языки без среды исполнения и механизмов сборки мусора с поддержкой шаблонного программирования и полиморфизма. Получается, это С++.

— У тебя в команде все бывшие «сишники»?

Нет, не все. Есть те, кто писал на Go, Haskell и Java.

Почему «Rust – не Си на стероидах» читайте в интервью с ведущим системным программистом департамента разработки компании «Криптонит» Михаилом Дорониным.

— То есть с Haskell вполне можно перейти на Rust?

Да. На самом деле Rust не Си-подобный. Когда вижу конструкции на Scala/Haskell или программу на Go, мне кажется, что команда, которая проектировала Rust, старалась взять лучшее из разных языков. Соответственно, программист, знающий Scala, Haskell или Go, увидит что-то близкое, понятное ему. Но программисту с опытом работы на С++ меньше других придётся подстраиваться под ограничения, которые другим на начальном этапе кажутся непривычными.

В общем, на Rust можно перейти хоть с C#. Но надо понимать, что меняется концепция: отсутствует среда исполнения, автоматическое управление памятью. И тебе придётся заботиться о том, о чём ты заботиться не привык.

— Думать, как код внутри исполняется?

Да. И понимать, к чему каждая твоя строчка кода приводит на машинном уровне.

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

На других языках — да. А для разработчика на С++, наоборот. Компилятор какие-то вещи, о которых ты раньше должен был думать сам, берёт на себя и запрещает тебе сделать то, что потенциально может привести к созданию ненадёжной или аварийной программы.

— Как началось твоё знакомство с Rust?

— С книги «Программирование на языке Rust». Мы её называли «книга с крабиком» :) Она вышла в издательстве O'Reilly, была переведена у нас, и, по-моему, была такая первая и единственная. Удачной эта книга была потому, что её авторы как будто, также, как и я, до Rust работали на C++. Их аналогии и поясняющие примеры построены на сравнении этих языков. Разработчику на С++ она очень подходит.

— Ты учился только по книге?

— Да. Мне сперва надо понять правила игры, а потом их на чём-то попробовать. На проекте по выпуску блокчейна я написал наше программное обеспечение на Rust, и в процессе самостоятельно проходил все привычные для программиста пути: и пользовался советами Stack Overflow, и возвращался к учебнику, и смотрел каталоги библиотек, которые есть на Rust, и экспериментировал. Но, чтобы никого не напугать, напоминаю, что есть и обучающие курсы.

— Поделись полезными материалами и ресурсами для Rust-разработчиков.

Могу рекомендовать серию видео с погружением в отдельные темы от Jon Gjengset https://www.youtube.com/@jonhoo. В них вполне понятный английский, глубокий уровень погружения в выбранную тему и увлекательный стиль изложения.

Есть ещё интересный ресурс https://cheats.rs. Этот ресурс больше всего похож на удобный набор «шпаргалок» по Rust, очень наглядных, с полезными советами и готовыми примерами.

P.S. Дополнительные полезные материалы смотрите также в нашем полном обзоре языка программирования Rust. В статье рассказываем о его особенностях, применении, плюсах и минусах.