Подключение к Apache Kafka

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

Дополнительные сведения о Kafka см. в документации по Apache Kafka.

Чтение данных из Kafka

kafka Используйте формат для настройки подключений к Kafka. Ниже приведен пример потокового чтения:

Python

df = (spark.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("subscribe", "<topic>")
  .option("startingOffsets", "latest")
  .load()
)

Scala

val df = spark.readStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("subscribe", "<topic>")
  .option("startingOffsets", "latest")
  .load()

SQL

CREATE OR REFRESH STREAMING TABLE <table_name> AS
SELECT * FROM STREAM read_kafka(
  bootstrapServers => '<server:ip>',
  subscribe => '<topic>'
);

Azure Databricks также поддерживает пакетные операции чтения из Kafka, как показано в следующем примере:

Python

df = (spark.read
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("subscribe", "<topic>")
  .option("startingOffsets", "earliest")
  .option("endingOffsets", "latest")
  .load()
)

Scala

val df = spark.read
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("subscribe", "<topic>")
  .option("startingOffsets", "earliest")
  .option("endingOffsets", "latest")
  .load()

SQL

SELECT * FROM read_kafka(
  bootstrapServers => '<server:ip>',
  subscribe => '<topic>',
  startingOffsets => 'earliest',
  endingOffsets => 'latest'
);

Для добавочной пакетной загрузки Databricks рекомендует использовать Kafka с Trigger.AvailableNow. См.: AvailableNow инкрементную пакетную обработку.

В Databricks Runtime 13.3 LTS и более поздних версиях Azure Databricks также предоставляет функцию SQL для чтения данных Kafka. Потоковая передача с помощью SQL поддерживается только в конвейерах Lakeflow или с таблицами потоковой передачи в Databricks SQL. См. табличную функцию read_kafka.

Настройка средства чтения структурированной потоковой передачи Kafka

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

Key Ценность Описание
kafka.bootstrap.servers Разделенный запятыми список host:port Серверы начальной загрузки кластера Kafka

Чтобы задать разделы подписки, необходимо указать один из следующих параметров:

Опция Ценность Описание
subscribe Разделенный запятыми список разделов. Список разделов, на который нужно подписаться.
subscribePattern Java строке regex. Шаблон, используемый для подписки на разделы.
assign Строка в формате JSON {"topicA":[0,1],"topic":[2,4]}. Зависит от topicPartitions использования.

Полный список доступных параметров см. в Kafka .

Схема строк Kafka

Средство чтения структурированной потоковой передачи Kafka возвращает строки со следующей схемой:

колонна Тип
key binary
value binary
topic string
partition int
offset long
timestamp timestamp
timestampType int

key и value всегда десериализуются как массивы байтов с ByteArrayDeserializer. Используйте операции DataFrame (например cast("string") , или from_avro) для явной десериализации ключей и значений.

Запись данных в Kafka

Ниже приведен пример потоковой записи в Kafka:

Python

(df.writeStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("topic", "<topic>")
  .start()
)

Scala

df.writeStream
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("topic", "<topic>")
  .start()

Azure Databricks также поддерживает семантику пакетной записи в приемники данных Kafka, как показано в следующем примере:

Python

(df.write
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("topic", "<topic>")
  .save()
)

Scala

df.write
  .format("kafka")
  .option("kafka.bootstrap.servers", "<server:ip>")
  .option("topic", "<topic>")
  .save()

Настройка модуля записи структурированной потоковой передачи Kafka

Это важно

Databricks Runtime 13.3 LTS и выше содержит более новую версию библиотеки kafka-clients, которая обеспечивает возможность идемпотентной записи по умолчанию. Если приемник Kafka использует версию 2.8.0 или ниже с настроенными ACL, но без включенного IDEMPOTENT_WRITE, запись завершается ошибкой org.apache.kafka.common.KafkaException:Cannot execute transactional method because we are in an error state.

Чтобы устранить эту ошибку, обновите до версии Kafka 2.8.0 или более поздней, или установите параметр .option(“kafka.enable.idempotence”, “false”) при настройке писателя структурированной потоковой передачи.

Ниже приведены распространенные варианты записи в Kafka:

Key Ценность Значение по умолчанию Описание
kafka.boostrap.servers Список <host:port>, разделенный запятыми нет Required. Конфигурация Kafka bootstrap.servers.
topic STRING не задано Optional. Задает топик для всех записываемых строк. Этот параметр переопределяет любой столбец темы, имеющийся в данных.
includeHeaders BOOLEAN false Optional. Следует ли включать заголовки Kafka в строку.

Полный список доступных параметров см. в разделе Kafka sink.

Схема модуля записи Kafka

При записи данных в Kafka указанный кадр данных может содержать следующие поля:

Имя столбца Обязательно или необязательно Тип
key optional STRING или BINARY
value required STRING или BINARY
headers optional ARRAY
topic необязательный (игнорируется, если topic задан в качестве опции записи) STRING
partition optional INT

Проверка подлинности

Azure Databricks поддерживает несколько методов проверки подлинности для Kafka, включая учетные данные службы каталога Unity, SASL/SSL и облачные варианты для AWS MSK, Центры событий Azure и Google Cloud Managed Kafka. См. раздел Аутентификация.

Получение метрик Kafka

Чтобы отслеживать отставание по Kafka для потокового запроса, используйте метрики avgOffsetsBehindLatest, maxOffsetsBehindLatest и minOffsetsBehindLatest. Эти метрики сообщают о средней, максимальной и минимальной задержке смещения по всем секциям разделов, подписанных по сравнению с последними смещениями в Kafka. См. статью Чтение метрик в интерактивном режиме.

Замечание

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

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

Чтобы оценить оставшиеся данные для чтения запроса, используйте метрику estimatedTotalBytesBehindLatest . Эта метрика оценивает общее количество байтов, оставшихся во всех подписанных секциях на основе пакетов, обработанных за последние 300 секунд. Вы можете изменить период времени, используемый для этой оценки, задав bytesEstimateWindowLength параметр.

Например, чтобы задать длину окна в 10 минут:

Python

df = (spark.readStream
  .format("kafka")
  .option("bytesEstimateWindowLength", "10m") # m for minutes, you can also use "600s" for 600 seconds
)

Scala

val df = spark.readStream
  .format("kafka")
  .option("bytesEstimateWindowLength", "10m") // m for minutes, you can also use "600s" for 600 seconds

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

{
  "sources": [
    {
      "description": "KafkaV2[Subscribe[topic]]",
      "metrics": {
        "avgOffsetsBehindLatest": "4.0",
        "maxOffsetsBehindLatest": "4",
        "minOffsetsBehindLatest": "4",
        "estimatedTotalBytesBehindLatest": "80.0"
      }
    }
  ]
}

Дополнительные сведения см. в Мониторинг структурированных запросов потоковой передачи Azure Databricks.

Пример переноса данных из Kafka в Delta Lake

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

В этом примере используется фиксированная схема JSON. Для других форматов, таких как Avro или Protobuf, используйте from_avro или from_protobuf. Вы также можете интегрироваться с реестром схем. См . пример с реестром схем.

Python

from pyspark.sql.functions import from_json, col

# Define simple JSON schemas for key and value
key_schema = "user_id STRING"
value_schema = "event_type STRING, event_ts TIMESTAMP"

# Configure Kafka options with service credentials
kafka_options = {
  "kafka.bootstrap.servers": "<bootstrap-server>:9092",
  "subscribe": "<topic-name>",
  "databricks.serviceCredential": "<service-credential-name>",
}

# Read from Kafka and parse JSON
parsed_df = (spark.readStream
  .format("kafka")
  .options(**kafka_options)
  .load()
  .select(
    from_json(col("key").cast("string"), key_schema).alias("key"),
    from_json(col("value").cast("string"), value_schema).alias("value")
  )
  .select("key.*", "value.*")
)

# Write to Delta table
query = (parsed_df.writeStream
  .format("delta")
  .option("checkpointLocation", "/path/to/checkpoint")
  .trigger(availableNow=True)
  .toTable("catalog.schema.events_table")
)

query.awaitTermination()

Scala

import org.apache.spark.sql.functions.{from_json, col}
import org.apache.spark.sql.streaming.Trigger
import org.apache.spark.sql.types.StructType

// Define JSON schemas for key and value
val keySchema = "user_id STRING"
val valueSchema = "event_type STRING, event_ts TIMESTAMP"

// Configure Kafka options with service credentials
val kafkaOptions = Map(
  "kafka.bootstrap.servers" -> "<bootstrap-server>:9092",
  "subscribe" -> "<topic-name>",
  "databricks.serviceCredential" -> "<service-credential-name>"
)

// Read from Kafka and parse JSON
val parsedDF = spark.readStream
  .format("kafka")
  .options(kafkaOptions)
  .load()
  .select(
    from_json(col("key").cast("string"), StructType.fromDDL(keySchema)).alias("key"),
    from_json(col("value").cast("string"), StructType.fromDDL(valueSchema)).alias("value")
  )
  .select("key.*", "value.*")

// Write to Delta table
val query = parsedDF.writeStream
  .format("delta")
  .option("checkpointLocation", "/path/to/checkpoint")
  .trigger(Trigger.ProcessingTime("10 seconds"))
  .toTable("catalog.schema.events_table")

query.awaitTermination()

SQL

-- Create a streaming table from Kafka using read_kafka
CREATE OR REFRESH STREAMING TABLE catalog.schema.events_table AS
SELECT
  key::string:user_id AS user_id,
  value::string:event_type AS event_type,
  to_timestamp(value::string:event_ts) AS event_ts
FROM STREAM read_kafka(
  bootstrapServers => '<bootstrap-server>:9092',
  subscribe => '<topic-name>',
  serviceCredential => '<service-credential-name>'
);

Замечание

При использовании бессерверных вычислений Databricks для инкрементальной потоковой обработки рекомендуется триггер availableNow. Для непрерывной потоковой передачи с низкой задержкой используйте непрерывный режим конвейеров Lakeflow. Полный список поддерживаемых параметров см. в структурированных триггерах потоковой передачи .