Механизм транзакций Kafka

Kafka — это хорошо масштабируемая распределенная система обмена сообщениями, которая играет важную роль в экосистеме обработки массивных данных.

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

В этой статье представлены концепция и процесс механизма транзакций в экосистеме Kafka.

Концепция механизма транзакций Kafka

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

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

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

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

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

Процесс механизма транзакций Kafka

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

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

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

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

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

Инициализировать контекст транзакции

Логически говоря, транзакции всегда инициируются производителем. Производитель инициализирует контекст транзакции, вызывая метод initTransactions. Первое, что нужно сделать, это найти координатора транзакций (Transaction Coordinator), которому кластер Kafka отвечает за управление текущей транзакцией, и подать заявку на получение ресурса ProducerID от него. Начальный идентификатор производителя и эпоха не инициализированы.

После получения соответствующего вызова метода диспетчер транзакций (TransactionManager) на стороне производителя отправляет информацию для поиска координатора транзакций и информацию для инициализации идентификатора производителя. Вся метаданная, связанная с транзакцией, будет заполнена клиентом, менеджером транзакций на стороне производителя и сервером, то есть координатором транзакций на брокере кластера Kafka.

Вначале производитель не знает, у какого Брокера есть координатор транзакции, связанный с его TransactionalID. Логически все данные, связанные с транзакциями, которые необходимо сохранить, в конечном итоге будут записаны в специальную тему __transaction_state. Эта и специальная тема __consumer_offsets для управления сайтами потребления в предыдущем ответе на статью об управлении сайтами потребления составляют единственные две специальные темы в текущей системе Kafka.

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

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

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

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

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

Среди них для получения нового ресурса ProducerID требуется, чтобы менеджер ProducerID подал заявку на получение сегмента номера ProducerID от ZooKeeper и выделил их один за другим. Средство подачи заявки на числовой сегмент состоит в изменении информации узла /latest_producer_id_block в ZooKeeper.Процесс заключается в чтении информации последнего примененного идентификатора производителя на узле, добавлении длины числового сегмента, на который будет подана заявка, и затем обновите последний примененный идентификатор производителя на узле. Поскольку ZooKeeper имеет контроль версий для обновлений узлов, одновременные запросы приведут к несовпадению нескольких целевых версий запросов, и будет инициирована повторная попытка. Длина ProducerID равна длине типа Long, поэтому использовать его в реальном использовании практически невозможно, Kafka выдает фатальную ошибку при исчерпании ресурсов числового сегмента и не пытается восстановить.

Если получена предыдущая информация метаданных того же TransactionalID, выполните другие действия в соответствии с предыдущим состоянием транзакции координатора транзакций.

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

  2. Если состояние — PrepareAbort или PrepareCommit, верните исключение CONCURRENT_TRANSACTIONS. Точно так же в это время состояние вот-вот перейдет в конечное состояние, и нет необходимости принудительно завершать предыдущую транзакцию, иначе будут генерироваться ненужные траты.

  3. Если состояние Dead или PrepareEpochFence или текущий ProducerID и эпоха не совпадают, сразу создается исключение без повторной попытки. Это связано с тем, что либо предыдущий источник был заменен новым источником, либо время ожидания транзакции истекло, и нет необходимости повторять попытку.

  4. Если в это время состояние Ongoing, координатор транзакций переведет транзакцию в состояние PrepareEpochFence, затем отменит текущую транзакцию и вернет исключение CONCURRENT_TRANSACTIONS.

  5. Если в это время состояние является одним из CompleteAbort, CompleteCommit или Empty, сначала переведите состояние в Empty, а затем обновите значение эпохи.

После такой серии операций Kafka инициализирует контекст выполнения транзакции.

начать транзакцию

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

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

Отправить сообщение в транзакции

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

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

Гарантии порядка сообщений в транзакции также проверяются при отправке транзакции.

Производитель подал заявку на ресурс ProducerID в это время.Когда он отправляет сообщение в раздел, внутренний диспетчер сообщений будет поддерживать порядковый номер ( SequenceNumber ) для каждого отдельного раздела. Соответственно, кластер Kafka также поддерживает порядковый номер для создания сообщений от каждого идентификатора производителя к каждому разделу.

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

совершить транзакцию

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

Независимо от отправки или отказа производитель отправляет запрос EndTxnRequest координатору транзакций, и запрос содержит поле для определения того, следует ли отправить или отменить. После получения этого запроса координатор транзакций сначала обновляет состояние транзакции до PrepareAbort или PrepareCommit, а затем обновляет состояние до __transaction_state.

Если координатор транзакций выходит из строя до того, как обновление статуса будет успешным, восстановленный координатор транзакций будет думать, что транзакция находится в состоянии «Выполняется». транзакцию в статус PrepareAbort или PrepareCommit.

Затем, в зависимости от того, зафиксирована она или отброшена, маркер транзакции (TransactionMarker) отправляется лидерам всех секций, участвующих в транзакции.

Флаг транзакции — это сообщение управления транзакцией, представленное механизмом транзакций Kafka, которое отличается от бизнес-сообщений. Его функция в основном состоит в том, чтобы определить, что транзакция была завершена.Это сообщение может быть использовано потребителями так же, как бизнес-сообщение, и оно может быть связано с бизнес-сообщением в транзакции через TransactionalID, так что потребители настроены с функцией чтения зафиксированных может игнорировать незавершенное сообщение о зафиксированной транзакции или сообщение об отброшенной транзакции.

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

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

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

Как правило, статус транзакции основан на постоянной информации метаданных в разделе __transaction_state.

транзакция с истекшим сроком ожидания

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

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

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

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

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

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

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

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

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

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

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

Supongo que te gusta

Origin blog.csdn.net/qq_35240226/article/details/108124318
Recomendado
Clasificación