Что такого уникального в Flink и что отличает его от Storm и Spark?

Эта статья является частью серии статей о Flink от Alibaba.

Инженеры приложения Alibaba для доставки еды Ele.me (饿 了 吗) все больше полагаются на Apache Flink, платформу обработки потокового видео с открытым исходным кодом, выпущенную в 2018 году.

Что такого уникального в Flink и что отличает его от Storm и Spark? В этой статье исследуется, как работает платформа больших данных Ele.me с точки зрения вычислений в реальном времени, и оцениваются различные сильные и слабые стороны Flink.

Платформа Ele.me сегодня

На следующем изображении показана текущая архитектура платформы Ele.me.

На текущей платформе Ele.me данные из нескольких источников сначала записываются в Apache Kafka. Основными вычислительными средами, используемыми для этого, являются Storm, Spark и Flink. Результаты данных этих структур затем депонируются в различные типы хранилищ.

В настоящее время существует более 100 задач в Storm, примерно 50 в Spark и меньшее количество во Flink.

Текущий масштаб кластера составляет 60 ТБ данных в день, один миллиард вычислений и 400 узлов. Здесь следует отметить, что и Spark, и Flink работают на YARN. В то время как Flink on YARN используется в основном как изоляция JobManager между задачами, Storm on YARN находится в автономном режиме.

В этой статье основное внимание будет уделено пяти областям: согласованная семантика, Apache Storm, Apache Spark Streaming и структурированная потоковая передача, а также Apache Flink.

Последовательная семантика

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

· Не более одного раза (или запустил и забыл): обычно при написании приложений Java используется простая семантика «не более одного раза», игнорируя управление смещением источника и идемпотентность ниже по течению. Когда данные поступают, для них нет механизма ACK - независимо от промежуточного состояния и состояния записи данных.

· Не менее одного раза: механизм повторной передачи, который повторно передает данные, чтобы гарантировать, что каждая часть обрабатывается хотя бы один раз.

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

· Идемпотентность + хотя бы один раз = ровно один раз: если можно гарантировать, что в нисходящем потоке есть идемпотентные операции, такие как «ON DUPLICATE KEY UPDATE» на основе MySQL, или если вы используете ES / Cassandra и т. д., вы можете использовать первичный ключ для достижения «расстроенной» семантики. Если вы добавите идемпотентность в микс при обеспечении хотя бы одного раза, результат будет ровно один раз.

Apache Storm

Хотя потоковая передача Spark и структурированная потоковая передача не были полностью реализованы на практике до 2017 года, Ele.me использует Apache Storm еще до 2016 года. Storm может похвастаться следующими функциями.

· Данные основаны на кортежах

· Задержка на уровне миллисекунд

· С самого начала поддерживалась Java, но теперь, когда используется Apache Beam, также поддерживаются Python и Go.

· Функция SQL не завершена. Typhon инкапсулирован внутри, и пользователям нужно только расширить некоторые из наших интерфейсов, чтобы использовать многочисленные основные функции. Flux также является хорошим инструментом для Storm. С его помощью, чтобы описать задачу Storm, вам нужно всего лишь написать файл YAML. Это до некоторой степени удовлетворяет требованиям, но пользователям по-прежнему необходимо писать Java на уровне инженера, а это означает, что аналитики данных часто не могут его использовать.

Резюме

Таким образом, у Storm есть три основных преимущества.

· Простота использования: из-за высокого порога его продвижение ограничено.

· State Backend: требуется больше для внешнего хранилища, в том числе для баз данных хранения ключей и значений, таких как Redis.

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

Apache Spark: потоковая передача Spark

В какой-то момент команду Ele.me спросили, может ли она написать SQL, который мог бы опубликовать вычислительную задачу в реальном времени за считанные минуты. Для этого команда начала работать с Apache Spark Streaming, основные концепции которого заключаются в следующем.

· Микропакетирование: вы должны предварительно настроить окно и обработать данные в этом окне.

· Задержка на втором уровне, обычно около 500 мс.

· Языки разработки включают Java и Scala.

· Потоковый SQL: техническая группа Ele.me надеется в ближайшем будущем предоставить платформу для потоковой передачи SQL.

Ключевая особенность

· Экосистема Spark и SparkSQL
В этом заключается главное преимущество Spark. Стек технологий унифицирован, и пакеты SQL, графических вычислений и машинного обучения совместимы. В отличие от Flink, в Spark сначала выполняется пакетная обработка, а это означает, что ее API реального времени и офлайн унифицированы.

· Контрольные точки на HDFS

· Работа на YARN
Spark принадлежит к экосистеме Hadoop и тесно интегрирован с YARN.

· Высокая производительность
Поскольку это средство микродозирования, производительность относительно высока.

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

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

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

Многопоточное присоединение

Некоторым пользователям все еще может быть интересно, как выполнить многопоточное объединение. Для Spark 1.5 см. Spark Streaming SQL. В этом проекте с открытым исходным кодом DStream зарегистрирован как таблица, и операция соединения выполняется в таблице. Но эта операция поддерживается только в версиях до 1.5. После внедрения структурированной потоковой передачи в Spark 2.0 от проекта отказались. Метод хитрый:

Несмотря на то, что Spark Streaming позволяет делать покупки по нескольким темам, каждый пакет RDD в DStream покупок преобразуется в DataFrame, чтобы DataFrame можно было зарегистрировать как таблицу. Затем таблица делится на две части, чтобы можно было выполнить соединение. Это соединение полностью зависит от данных этой покупки, и условия соединения неконтролируемы. Вот почему этот метод сложен.

В качестве примера возьмем следующий случай. Куплены две темы. Таблица разделена на две части по условию фильтра. Затем эти две таблицы могут быть объединены. Однако по сути это поток.

Семантика ровно один раз

Для одного раза важно отметить, что данные должны быть переданы во внешнее хранилище до фиксации смещения. Независимо от того, попадают ли данные в ZK или MySQL, важно убедиться, что они находятся в транзакции. Также необходимо вывести его во внешнее хранилище до того, как исходный драйвер сгенерирует Kafka RDD, а исполнитель потребляет данные. Если эти условия соблюдены, может быть достигнута сквозная семантика «ровно один раз». Это главная предпосылка.

Резюме

· Обработка SQL с отслеживанием состояния (‹2.x mapWithState, updateStateByKey): если вы хотите реализовать кросс-пакетные вычисления с отслеживанием состояния с версией 1.X, сделайте это через эти два интерфейса. Вам все равно нужно сохранить это состояние в HDFS или внешнем хранилище. Поэтому реализация немного сложна.

· Настоящее многопотоковое объединение: истинная семантика многопотокового объединения недостижима.

· Сквозная семантика точно один раз: их сложно реализовать. Вы должны погрузить их во внешнее хранилище, а затем вручную отправить смещение в транзакции.

Apache Spark: структурированная потоковая передача

В версиях более поздних, чем Spark 2.X, используются инкрементные вычисления с отслеживанием состояния. Следующая картинка взята с официального сайта.

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

На следующем графике показана архитектура структурированной потоковой передачи.

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

Ключевая особенность

· Обработка SQL и DSL с отслеживанием состояния: это может удовлетворить FlowCompute с отслеживанием состояния.

· Реальное многопотоковое объединение. Многопотоковое объединение можно реализовать с помощью Spark 2.3. Метод реализации аналогичен таковому для Flink. Вы должны определить условия двух потоков (это в основном включает определение времени как условия). Например, в поток поступают две темы, и вы ограничиваете данные, для которых требуется буфер, через поле в определенной схеме (обычно время события). Таким образом вы присоединяетесь к двум потокам.

· Проще реализовать сквозную семантику «ровно один раз». Для поддержки идемпотентных операций вам нужно только расширить интерфейс приемника, что приведет к семантике ровно один раз.

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

Кроме того, его водяной знак не поддерживает SQL. В Ele.me техническая группа добавляет расширение для обеспечения полной записи SQL и преобразования слева направо (как показано на следующем графике). Мы надеемся, что это применимо не только к программистам, но и к аналитикам данных, которые не знают, как программировать.

Резюме

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

· Непрерывная обработка: в настоящее время поддерживаются только операции, подобные карте, а поддержка SQL также ограничена.

· Низкая сквозная задержка с одноразовой гарантией: гарантия сквозной семантики точно один раз требует дополнительных расширений. Техническая команда Ele.me обнаружила, что Kafka версии 0.11 предоставляет транзакционные функции, на основе которых мы можем рассмотреть возможность достижения сквозной семантики «ровно один раз» от источника до движка и приемника.

· CEP (Drools): для пользователей, которым требуются такие функции, как CEP для обработки сложных событий, механизм правил Drools может быть запущен для каждого исполнителя.

Помня о вышеупомянутых недостатках Apache Spark в структурированной потоковой передаче, инженеры Ele.me решили начать использовать Flink.

Apache Flink

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

Фреймворк Flink

JobManager в Flink похож на драйвер в Spark, TaskManager похож на исполнителя, и задачи в обоих одинаковы. Однако Flink использует RPC - это Akka, а ядро ​​Flink настраивает структуру сериализации памяти. Более того, задачам во Flink не нужно ждать друг друга, как это делают задачи на каждом этапе Spark, вместо этого отправляя данные в нисходящий поток после обработки.

Оператор обработки двоичных данных Flink

Для сериализации в Spark пользователи обычно используют сериализацию Kryo или Java по умолчанию. Project Tungsten также оптимизировал слой JVM и генерацию кода для программ Spark. Flink, тем временем, реализует структуру сериализации на основе памяти, которая поддерживает концепции ключа и указателя. Его ключ - непрерывное хранилище, оптимизированное на уровне ЦП. Вероятность промаха кеша крайне мала. При сравнении и сортировке данных вы не сравниваете реальные данные - вы сначала сравниваете ключ. Только когда результат будет равен, данные будут десериализованы из памяти. На этом этапе вы можете сравнить конкретные данные. Это представляет собой надежную оптимизацию производительности.

Цепочка задач Flink

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

Концепция параллелизма

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

Spark обычно регулирует степень параллелизма с помощью Spark.default.parallelism. Во время операции перемешивания параллелизм обычно регулируется параметром Spark.sql.shuffle.partitions. При вычислениях в реальном времени этот параметр следует установить на меньшее значение. Например, в продакшене параметры Kafka и раздела устанавливаются почти одинаковыми, в то время как пакет настраивается на несколько большее значение. На левом графике инженеры Ele.me установили для параллелизма значение 2 (до 10). Затем они запустили две одновременные партии и создали группу (до 10) в соответствии с ключом. Таким образом, данные могут быть максимально разнесены.

Штаты и контрольно-пропускные пункты

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

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

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

Устойчивость к ошибкам

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

Ровно-однократная двухфазная фиксация

После Flink 1.4 был введен протокол двухфазной фиксации для поддержки только одного раза. После того, как данные потребляются от вышестоящего Kafka, на каждом шаге будет инициироваться голосование для записи состояния, а отметка будет обработана через барьер контрольной точки. Состояние записывается в Kafka только в конце (это относится только к Kafka 0.11 или новее). Только после окончательного завершения состояние каждого шага будет уведомлено координатором в JobManager и закреплено, таким образом достигнув ровно один раз.

Точки сохранения

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

Окончательный анализ: преимущества и недостатки Flink

Преимущества Flink можно суммировать следующим образом:

· Триггер: в отличие от Spark, Flink поддерживает более широкую семантику потоковой передачи, включая время обработки, время события и время приема.

· Непрерывная обработка и окна: Flink поддерживает непрерывную обработку и работает с окнами лучше, чем Spark.

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

· CEP

· Точки сохранения: пользователи могут управлять версиями в соответствии с потребностями своего бизнеса.

Однако есть и недостатки в следующих областях:

1. SQL: функция SQL не завершена. Большинство пользователей переходят с Hive, где покрытие Spark превышает 99%. В настоящее время функции SQL не поддерживаются, как и настройка параллелизма для одного оператора.

2. Машинное обучение, графические вычисления: производительность Flink здесь ниже, чем у Spark, но сообщество работает над улучшением в этих областях.

Эта статья является частью серии статей о Flink от Alibaba.

Alibaba Tech

Подробная информация о последних технологиях Alibaba из первых рук → Facebook: Alibaba Tech. Twitter: « AlibabaTech ».