Узнайте, как Blue увеличил масштаб импорта и экспорта CSV в 10 раз, используя Rust, масштабируемую архитектуру и стратегические технологические решения в B2B SaaS.


В Blue мы постоянно расширяем границы возможного в программном обеспечении для управления проектами. За эти годы мы выпустили сотни функций.

Наше последнее инженерное достижение?

Полная переработка нашей системы импорта CSV и экспорта, что значительно улучшило производительность и масштабируемость.

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

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

Масштабирование для нужд предприятий

Наше путешествие началось с запроса от корпоративного клиента в индустрии мероприятий. Этот клиент использует Blue как свой центральный узел для управления обширными списками мероприятий, площадок и спикеров, интегрируя его с их веб-сайтом.

Для них Blue — это не просто инструмент — это единственный источник правды для всей их операции.

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

Когда этот клиент масштабировал свои операции, он столкнулся с серьезным препятствием: импортом и экспортом больших CSV файлов, содержащих от 100,000 до 200,000+ записей.

Это превышало возможности нашей системы на тот момент. Фактически, наша предыдущая система импорта/экспорта уже испытывала трудности с импортом и экспортом, содержащими более 10,000 до 20,000 записей! Так что 200,000+ записей были вне обсуждения.

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

Мультиарендность — это архитектура, где один экземпляр программного обеспечения обслуживает нескольких клиентов (арендаторов). Хотя это эффективно, это требует тщательного управления ресурсами, чтобы действия одного арендатора не негативно сказывались на других.

И это ограничение касалось не только этого конкретного клиента.

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

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

Поставщик, который выделялся, был SaaS-провайдером под названием Flatfile. Их система и возможности выглядели именно так, как нам нужно.

Но, после изучения их цен, мы решили, что это будет крайне дорогое решение для приложения нашего масштаба — $2/файл быстро накапливаются! — и лучше расширить наш встроенный движок импорта/экспорта CSV.

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

Вот как мы подошли к решению.

Введение фоновых служб

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

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

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

  • Формульные расчеты: Разгружает сложные математические операции, чтобы обеспечить быстрые обновления производных полей без влияния на производительность основного сервера.
  • Дашборды/Графики: Обрабатывает большие наборы данных в фоновом режиме для генерации актуальных визуализаций без замедления пользовательского интерфейса.
  • Индекс поиска: Постоянно обновляет индекс поиска в фоновом режиме, обеспечивая быстрые и точные результаты поиска без влияния на производительность системы.
  • Копирование проектов: Обрабатывает репликацию больших, сложных проектов в фоновом режиме, позволяя пользователям продолжать работу, пока копия создается.
  • Автоматизация управления проектами: Выполняет автоматизированные рабочие процессы, определенные пользователем, в фоновом режиме, обеспечивая своевременные действия без блокировки других операций.
  • Повторяющиеся записи: Генерирует повторяющиеся задачи или события в фоновом режиме, поддерживая точность расписания без нагрузки на основное приложение.
  • Пользовательские поля продолжительности времени: Постоянно вычисляет и обновляет разницу во времени между двумя событиями в Blue, предоставляя данные о продолжительности в реальном времени без влияния на отзывчивость системы.

Новый модуль Rust для парсинга данных

Сердцем нашего решения по обработке CSV является пользовательский модуль Rust. Хотя это стало нашим первым шагом за пределы нашего основного технологического стека на Javascript, решение использовать Rust было обусловлено его исключительной производительностью в параллельных операциях и задачах обработки файлов.

Сильные стороны Rust идеально соответствуют требованиям парсинга CSV и сопоставления данных. Его абстракции нулевой стоимости позволяют высокоуровневое программирование без ущерба для производительности, в то время как его модель владения обеспечивает безопасность памяти без необходимости в сборке мусора. Эти функции делают Rust особенно эффективным для обработки больших наборов данных безопасно и эффективно.

Для парсинга CSV мы использовали библиотеку csv от Rust, которая предлагает высокопроизводительное чтение и запись данных CSV. Мы объединили это с пользовательской логикой сопоставления данных, чтобы обеспечить бесшовную интеграцию с структурами данных Blue.

Кривая обучения для Rust была крутой, но управляемой. Наша команда посвятила около двух недель интенсивному обучению этому языку.

Улучшения были впечатляющими:

Наша новая система может обрабатывать такое же количество записей, которое наша старая система могла обрабатывать за 15 минут, за около 30 секунд.

Взаимодействие веб-сервера и базы данных

Для компонента веб-сервера нашей реализации на Rust мы выбрали Rocket в качестве нашего фреймворка. Rocket выделялся благодаря сочетанию производительности и удобных для разработчиков функций. Его статическая типизация и проверка на этапе компиляции хорошо согласуются с принципами безопасности Rust, помогая нам выявлять потенциальные проблемы на ранних этапах разработки.
В области баз данных мы выбрали SQLx. Эта асинхронная SQL-библиотека для Rust предлагает несколько преимуществ, которые сделали ее идеальной для наших нужд:

  • Безопасный SQL: SQLx позволяет нам писать сырой SQL с проверяемыми на этапе компиляции запросами, обеспечивая безопасность типов без ущерба для производительности.
  • Поддержка асинхронности: Это хорошо согласуется с Rocket и нашей необходимостью в эффективных, неблокирующих операциях с базой данных.
  • Независимость от базы данных: Хотя мы в основном используем AWS Aurora, совместимую с MySQL, поддержка SQLx для нескольких баз данных дает нам гибкость на будущее, если мы когда-либо решим изменить базу данных.

Оптимизация пакетной обработки

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

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

После анализа результатов мы обнаружили, что обработка 5 параллельных транзакций с размером пакета в 500 записей обеспечивала наилучший баланс скорости и использования ресурсов. Эта конфигурация позволяет нам поддерживать высокую пропускную способность, не перегружая нашу базу данных и не потребляя чрезмерное количество памяти.

Интересно, что увеличение параллелизма более чем до 5 транзакций не дало значительных приростов производительности и иногда приводило к увеличению конкуренции за ресурсы базы данных. Аналогично, большие размеры пакетов улучшали скорость, но за счет большего использования памяти и более длительного времени отклика для небольших и средних импортов/экспортов.

Экспорт CSV через ссылки на электронную почту

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

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

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

Безопасность этих ссылок для загрузки была нашим главным приоритетом в дизайне. Каждая ссылка:

  • Уникальна и случайно сгенерирована, что делает ее практически невозможной для угадывания
  • Действительна только в течение 2 часов
  • Шифруется при передаче, обеспечивая безопасность данных во время загрузки

Этот подход предлагает несколько преимуществ:

  • Он снижает нагрузку на наши веб-серверы, так как им не нужно обрабатывать большие загрузки файлов напрямую
  • Он улучшает пользовательский опыт, особенно для пользователей с медленными интернет-соединениями, которые могут столкнуться с проблемами тайм-аута браузера при прямых загрузках
  • Он предоставляет более надежное решение для очень больших экспортов, которые могут превышать типичные лимиты тайм-аута веб-приложений

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

Экспорт отфильтрованных данных

Другим очевидным улучшением было позволить пользователям экспортировать только данные, которые уже были отфильтрованы в их представлении проекта. Это означает, что если есть активный тег "приоритет", то только записи с этим тегом окажутся в экспорте CSV. Это означает меньше времени на манипуляции с данными в Excel для фильтрации несущественной информации и также помогает нам сократить количество строк для обработки.

Взгляд в будущее

Хотя у нас нет немедленных планов по расширению использования Rust, этот проект показал нам потенциал этой технологии для операций, критически важных для производительности. Это захватывающий вариант, который теперь есть в нашем инструменте для будущих потребностей в оптимизации. Этот пересмотр импорта и экспорта CSV идеально соответствует обязательству Blue по масштабируемости.

Мы стремимся предоставить платформу, которая растет вместе с нашими клиентами, справляясь с их расширяющимися потребностями в данных без ущерба для производительности.

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

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

  • Подход «проблема в первую очередь»: Мы всегда начинаем с четкого определения проблемы, которую мы пытаемся решить. В данном случае нам нужно было значительно улучшить производительность импорта и экспорта CSV для больших наборов данных.
  • Исчерпывающее использование существующих решений: Прежде чем искать решения вне нашего основного стека, мы тщательно исследуем, что можно достичь с помощью наших существующих технологий. Это часто включает профилирование, оптимизацию и переосмысление нашего подхода в рамках знакомых ограничений.
  • Квантование потенциальной выгоды: Если мы рассматриваем новую технологию, мы должны четко сформулировать и, желательно, количественно оценить преимущества. Для нашего проекта CSV мы прогнозировали улучшения производительности на порядок.
  • Оценка затрат: Введение новой технологии — это не только вопрос немедленного проекта. Мы учитываем долгосрочные затраты:
    • Кривая обучения для команды
    • Постоянное обслуживание и поддержка
    • Потенциальные осложнения при развертывании и эксплуатации
    • Влияние на найм и состав команды
  • Сдерживание и интеграция: Если мы вводим новую технологию, мы стремимся ограничить ее конкретной, четко определенной частью нашей системы. Мы также обеспечиваем наличие четкого плана по ее интеграции с нашим существующим стеком.
  • Будущее: Мы учитываем, открывает ли этот выбор технологии будущие возможности или может загнать нас в угол.

Одним из основных рисков частого принятия новых технологий является возможность оказаться в том, что мы называем "зоопарком технологий" — фрагментированной экосистеме, где разные части вашего приложения написаны на разных языках или фреймворках, требующих широкого спектра специализированных навыков для поддержки.

Заключение

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

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

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

Следите за новыми глубокими погружениями в инженерию, которая поддерживает Blue!

AI Ассистент

Ответы генерируются с использованием ИИ и могут содержать ошибки.

Как я могу вам помочь?

Спросите меня о чем угодно, связанном с Blue или этой документацией.

Введите для отправки • Shift+Enter для новой строки • ⌘I для открытия