В современной области аналитики данных эффективность работы систем играет решающую роль. Каждый миллисекундный выигрыш в скорости обработки может стать критическим для бизнеса, который строится на实时 аналитике и большом объёме входящих данных. Tinybird, компания, ориентированная на предоставление платформы быстрой и масштабируемой аналитики, недавно поделилась опытом оптимизации своего инжестионного пайплайна, достигнув улучшения производительности порядка 30% благодаря переходу на C++. Пайплайн обработки данных служит связующим звеном между входящими потоками информации и аналитической базой данных ClickHouse, которая использует колоночное хранение для максимальной эффективности запросов. Вся поступающая информация приходит в формате JSON, который необходимо преобразовать в внутренний бинарный формат ClickHouse — RowBinaryWithDefaults.
Его особенность в том, что он позволяет учитывать пропущенные поля с последующей подстановкой значений по умолчанию, что обеспечивает гибкость при работе с неоднородными исходными данными. До изменений преобразование JSON в этот бинарный формат выполнялось на Python, с некоторыми вспомогательными функциями на C, что, несмотря на начальную эффективность, стало узким местом, ограничивающим дальнейший рост производительности. Кроме того, этот подход требовал постоянного дублирования логики кодирования, синхронизированной с внутренними форматами ClickHouse, что усложняло сопровождение и расширение кода. Выбор C++ как базового языка для реализации нового модуля обработки был продиктован желанием максимально использовать внутренние механизмы ClickHouse. Было решено обернуть их через небольшую прослойку на C++, которая позволила бы напрямую использовать существующие в базе преобразования форматов, исключая дублирование кода и снижая риск ошибок при обновлениях и добавлении новых типов данных.
Однако на практике задачей оказалась куда более сложная, чем казалось изначально. Формат RowBinaryWithDefaults не является выходным форматом ClickHouse, а предназначен исключительно для ввода. Чтобы не нарушать совместимость с тысячами существующих кейсов и не создавать риск считывания некорректных данных, разработчикам пришлось реализовать дополнительные возможности, которые Tinybird добавлял в свой пайплайн годами. Важным аспектом стало использование jsonpath — механизма для выбора значений из вложенных структур JSON. Tinybird активно использует jsonpath, чтобы задавать отношения между входными данными и структурой таблиц в базе.
Обработка путей с общими префиксами, позволяющими не несколько раз проходить по одним и тем же элементам, потребовала создания специального дерева путей. Это решение повысило производительность, поскольку каждый сегмент JSON-структуры разбирается единожды, а потом значения эффективно сопоставляются с колонками. Для парсинга исходного JSON был выбран simdjson — библиотека на C++, признанная одной из самых быстрых в мире. Она позволила увеличить скорость чтения и обработки данных примерно в три раза, при этом сохранив низкое потребление памяти. Особое внимание в работе с simdjson уделялось ограничениям ondemand-режима, где объекты являются временными и не могут храниться в памяти длительное время без риска сбоев.
Это потребовало аккуратной архитектуры и продуманного обращения с памятью. Следующим этапом стало преобразование извлечённых значений в структуры Field — универсального внутреннего типа данных ClickHouse, способного аккуратно хранить значения любого типа, включая сложные составные типы и дату с высокой точностью. Для некоторых типов потребовалась реализация кастомных парсеров, например, для дат и времени, поскольку стандартные библиотеки не поддерживают нужный уровень точности и работу с часовыми поясами. Работа с ошибками стала важным пунктом в реализации. В Tinybird каждый сбой при обработке данных не просто игнорируется или приводит к полной остановке, а документируется и помещается в отдельную таблицу карантина с подробным описанием проблемы.
Такая гибкая схема дает возможность контролировать качество данных, не теряя важную информацию и позволяя оперативно реагировать на некорректные записи. Вынужденная совместимость с предыдущей логикой обработки породила режим legacy-conversion-mode, который активируется по умолчанию и позволяет воспроизводить все до сих пор существующие в системе «странности» и нетипичные кейсы без нарушения. Это дает возможность в будущем поэтапно переходить к более строгой и предсказуемой обработке данных без ущерба для существующих клиентов. Переход на новый модуль сопровождался многократным тестированием. Чтобы избежать сюрпризов, разработчики сравнивали результаты старого и нового методов на реальных объемах данных, выявляя и отлавливая отклонения.
Новая логика включалась поэтапно в продуктив, сначала в тестовых регионах, потом — в основных, где проводился мониторинг нагрузки и поведения платформы. При возникновении проблем система гибко переключалась обратно на предыдущий вариант, что полностью исключало потерю данных. Для выявления редко встречающихся и граничных случаев был даже разработан генератор случайных тестовых данных при помощи искусственного интеллекта. Это дало возможность охватить множество скрытых ошибок и подготовить систему к работе в самых разнообразных условиях. Результатом стала заметная экономия ресурсов — около 30% снижения загрузки процессоров в ключевых сервисах обработки событий.
Это означало возможность обслуживать больший объем данных за тот же бюджет, повысить пропускную способность клиентов и гармонизировать поддерживаемую функциональность с внутренними механизмами ClickHouse. Более того, упрощение архитектуры повысило надежность системы и уменьшило риски возникновения скрытых ошибок, сделав код более читаемым и удобным для сопровождения. Команда Tinybird существенно расширила свои знания в области C++ и внутренностей ClickHouse, что открывает новые возможности для дальнейших улучшений. Несмотря на успех, проект занял гораздо больше времени, чем планировалось изначально. Некоторые аспекты еще предстоит довести до совершенства, например, отключение режима legacy, увеличение эффективности использования памяти и полностью новая логика обработки исключений.
Тем не менее, опыт Tinybird демонстрирует, насколько важна глубокая интеграция с инфраструктурой хранения данных и продуманное инженерное решение в достижении высоких показателей производительности и устойчивости систем в эпоху больших данных. Этот кейс может служить вдохновением для инженеров, работающих с потоками данных и масштабируемыми аналитическими платформами, показывая, что не боясь обращаться к сложным решениям, можно добиться значительных улучшений и создать надежные, гибкие и быстрые продуктовые сервисы.