Большие данные и искра

Большинство людей, работающих с большими данными, знают Spark (если нет, ознакомьтесь с их сайт) в качестве стандартного инструмента для извлечения, преобразования и загрузки (ETL) кучи данных. Spark, преемник Hadoop и MapReduce, во многом работает как Pandas, пакет обработки данных, в котором вы запускаете операторы над коллекциями данных. Затем эти операторы возвращают новые наборы данных, что позволяет функционально объединять операторы в цепочки, не забывая при этом о масштабируемости.

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

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

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


Скромное начало

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

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

В частности, мы в значительной степени полагаемся на управляемые сервисы нашего облачного провайдера Google Cloud Platform (GCP) для размещения наших данных в управляемых базах данных, таких как BigTable и Spanner. Для преобразования данных мы изначально сильно полагались на DataProc — управляемый сервис от Google для управления кластером Spark.


Управление управляемыми службами

Нашей первой реализацией была собственная установка Spark в сочетании со службой Kafka, содержащей нашу очередь заданий. У этого были явные недостатки, и, оглядываясь назад, мы не считаем, что это удалось. Необходимо было сделать много побочных разработок, чтобы охватить все крайние случаи развертывания и его потребности в масштабировании. Такие вещи, как работа в сети, сбои узлов и параллелизм, должны быть исследованы, смягчены и смоделированы. Это сильно повлияло бы на нашу эффективность разработки. Во-вторых, стоимость запуска полного кластера Spark со 100% временем безотказной работы была довольно высокой, и создание для него стратегий автоматического масштабирования было довольно сложным. Наша вторая реализация была перенесена для использования того же потока событий Kafka, который передавал сообщения рабочей нагрузки в экземпляры Spark DataProc вместо первоначально размещенного экземпляра Spark.

Комбинация Kafka-Dataproc служила нам некоторое время, пока GCP не выпустила собственную реализацию очереди сообщений: Google Cloud Pub/Sub. В то время мы исследовали значение переключения. Всегда есть неотъемлемая стоимость переключения, но что мы недооценили в Kafka, так это существенные накладные расходы на обслуживание системы. Это особенно верно, если объем принимаемых данных быстро увеличивается. В качестве примера: служба Kafka требует, чтобы вы вручную сегментировали потоки данных, в то время как управляемая служба, такая как Pub/Sub, выполняет (повторное) сегментирование за кулисами. С другой стороны, Pub/Sub также имел некоторые недостатки, например, он не позволял хранить данные в течение длительного времени, что можно легко обойти, сохранив данные в облачном хранилище после обработки. Сохранение данных и ведение журналов интересных сообщений сделали Kafka устаревшей для нашего варианта использования.

Теперь, когда у нас больше не было службы Kafka, мы обнаружили, что использование DataProc также менее эффективно в сочетании с Pub/Sub по сравнению с альтернативами. Изучив наши варианты относительно наших типов рабочих нагрузок, мы выбрали другой путь. Дело не в том, что DataProc был плох для наших вариантов использования, но у DataProc были некоторые явные недостатки, и некоторый анализ показал нам, что есть варианты получше.

Во-первых, у DataProc в то время были проблемы с масштабированием, поскольку он в основном был сосредоточен на пакетных заданиях, в то время как все наши основные конвейеры работали на потоковых данных. С введением Spark Streaming эта проблема была немного решена, хотя и не полностью для нашего случая. Spark Streaming по-прежнему работает в (микро-) пакетном режиме под капотом, что необходимо для соответствия шаблону однократной доставки. Это создает проблемы для рабочих нагрузок, которые не имеют одинакового времени выполнения. Нашим процессорам требуется потоковая передача полностью в реальном времени без однократной доставки из-за идемпотентности наших сервисов.
Во-вторых, в то время продукт был не очень стабилен, а значит, нам приходилось очень внимательно следить за происходящим и тратить довольно много времени на оповещения. Наконец, большая часть нашей оркестровки и планирования выполнялась с помощью пользовательских написанных компонентов, что усложняло поддержку и обновление до более новых версий.


Строительство для будущего

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

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

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

Изучив цены на различные услуги и типы машин, мы получили довольно хорошее представление о том, как мы можем комбинировать различные услуги, чтобы получить идеальный баланс между ремонтопригодностью и эксплуатационными расходами. На этом этапе мы приняли решение для большинства наших конвейеров объединить контейнеры Cloud Pub/Sub и Kubernetes. Иногда лучшее решение — самое простое.

Причина использования Kubernetes была довольно проста. Kubernetes существовал около пары лет и использовался для размещения большинства наших внутренних микросервисов, а также внешних приложений. Таким образом, у нас были обширные знания о том, как автоматизировать большую часть ручного управления от инженеров к Kubernetes и нашему CI/CD. Во-вторых, поскольку у нас уже были другие сервисы, использующие Kubernetes, эти знания можно было быстро перенести в конвейеры, что позволило создать единый ландшафт между нашими различными рабочими нагрузками. Простота масштабирования Kubernetes — его главное преимущество. Соедините это с управляемым автоматическим масштабированием, которое дает Kubernetes Engine, и вы получите идеальное сочетание.

Экономическая эффективность того же типа машин в Kubernetes по сравнению с более управляемым сервисом

Это может стать сюрпризом, но контейнеры Kubernetes с «голым железом» довольно дешевы на большинстве облачных платформ, особенно если ваши узлы могут быть упреждающими. Поскольку все наши данные хранились в постоянных хранилищах или в очередях сообщений между этапами конвейера, наши рабочие нагрузки можно было завершить в любое время, и мы по-прежнему сохраняли бы наше согласованное состояние. Объедините стоимость Kubernetes с очень низкой стоимостью Pub/Sub в качестве шины сообщений, и мы получим победителя.


Построение вокруг простоты

И Kubernetes, и Pub/Sub — довольно простые, без множества наворотов, расширяющих возможности разработчиков. Таким образом, нам нужна была простая структура для создания новых конвейеров. быстро. Мы посвятили некоторые инженерные усилия построению этой конвейерной инфраструктуры на правильном уровне абстракции, где у конвейера есть вход, процессор и выход. С помощью этой простой структуры мы смогли построить всю платформу OTA Insight в быстром масштабе, не ограничивая себя рамками определенных сервисов или платформ.

Во-вторых, поскольку большинство наших агрегаций на уровне продукта выполняется в наших API Go, которые оптимизированы для скорости и параллелизма, мы можем заменить Spark нашей собственной бизнес-логикой, которая вычисляется на лету. Это помогает нам быстро двигаться в рамках этой бизнес-логики и упрощает прием данных. Сочетание фреймворка и агрегатов в наших API создает среду, в которой Spark становится ненужным, а сложность бизнес-логики равномерно распределяется между командами.


Резюме

В ходе нашего пути роста, от нашей начальной среды Spark (DataProc) до наших собственных настраиваемых конвейеров, мы многое узнали о затратах, инженерных усилиях, инженерном опыте и ограничениях роста и масштабирования.
Spark — отличный инструмент для многих приложений с большими данными, который заслуживает того, чтобы его называли самым распространенным в области обработки данных, но мы обнаружили, что он ограничивает нашу повседневную разработку, а также финансы. Во-вторых, он не полностью вписывался в архитектуру, которую мы представляли для нашего бизнеса.
В настоящее время мы знаем и владеем нашими пайплайнами так, как не может обеспечить ни один фреймворк. Это привело к быстрому росту новых конвейеров, новых интеграций и большему объему данных, чем когда-либо прежде, без необходимости не спать по ночам, размышляя, не будет ли эта новая интеграция слишком большой.

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

Хотите узнать больше? Приходите поговорить с нами!