Работа с Kafka в Rust: библиотеки и примеры для начинающих

Онлайн-тренажер Python для начинающих

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

Начать курс

Работа с Kafka в Rust: обзор библиотек и практические примеры

Apache Kafka — это распределённая платформа для потоковой обработки данных, широко используемая для построения надёжных и масштабируемых систем обмена сообщениями. Язык Rust, благодаря своей производительности и безопасности памяти, становится всё более популярным выбором для написания высоконагруженных приложений, работающих с Kafka. В этой статье мы рассмотрим основные библиотеки для работы с Kafka в Rust, их установку и приведём простые примеры кода.

Популярные библиотеки для Kafka в Rust

На данный момент существует два основных подхода к работе с Kafka в экосистеме Rust:

  • rdkafka — обёртка над популярной C-библиотекой librdkafka. Предоставляет максимальную производительность и функциональность, включая поддержку всех современных возможностей Kafka (транзакции, идемпотентность, точные гарантии доставки).
  • Kafka-Rust (kafka) — чистая реализация протокола Kafka на Rust, без внешних зависимостей. Легче в сборке, но может отставать по функциональности от rdkafka.

Для большинства production-проектов рекомендуется использовать rdkafka, так как он более зрелый, производительный и активно поддерживается сообществом.

Установка rdkafka

Для начала работы добавьте зависимость в ваш Cargo.toml:

[dependencies]
rdkafka = { version = "0.36", features = ["cmake-build"] }
tokio = { version = "1", features = ["full"] }  # для асинхронной работы
serde = { version = "1", features = ["derive"] }  # для сериализации данных
serde_json = "1"  # для работы с JSON

Библиотека rdkafka требует наличия librdkafka в системе. Вы можете установить её через системный пакетный менеджер или использовать feature cmake-build, как в примере выше — в этом случае библиотека скомпилируется автоматически.

Пример: базовый продюсер (Producer)

Продюсер отправляет сообщения в указанный топик Kafka. Вот простейший пример асинхронного продюсера на Tokio:

use rdkafka::config::ClientConfig;
use rdkafka::producer::{FutureProducer, FutureRecord};
use std::time::Duration;

#[tokio::main]
async fn main() {
    // Создаём конфигурацию продюсера
    let producer: FutureProducer = ClientConfig::new()
        .set("bootstrap.servers", "localhost:9092")
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Ошибка создания продюсера");

    // Отправляем сообщение в топик "my-topic"
    let delivery_status = producer
        .send(
            FutureRecord::to("my-topic")
                .payload("Привет, Kafka из Rust!")
                .key("ключ-сообщения"),
            Duration::from_secs(0),
        )
        .await;

    match delivery_status {
        Ok(partition_offset) => println!("Сообщение отправлено: {:?}", partition_offset),
        Err((e, _)) => eprintln!("Ошибка отправки: {}", e),
    }
}

Пример: базовый консьюмер (Consumer)

Консьюмер читает сообщения из топика. Ниже приведён пример синхронного консьюмера с ручным подтверждением (commit):

use rdkafka::config::ClientConfig;
use rdkafka::consumer::{Consumer, StreamConsumer};
use rdkafka::message::Message;
use rdkafka::util::get_rdkafka_version;

fn main() {
    let consumer: StreamConsumer = ClientConfig::new()
        .set("group.id", "my-consumer-group")
        .set("bootstrap.servers", "localhost:9092")
        .set("enable.auto.commit", "false")  // ручной commit
        .set("auto.offset.reset", "earliest")  // читать с начала
        .create()
        .expect("Ошибка создания консьюмера");

    consumer.subscribe(&["my-topic"]).expect("Ошибка подписки");

    loop {
        match consumer.recv() {
            Ok(msg) => {
                let payload = msg.payload().unwrap_or(b"");
                let key = msg.key().unwrap_or(b"");
                println!(
                    "Получено: key={:?}, payload={:?}, topic={}, partition={}, offset={}",
                    String::from_utf8_lossy(key),
                    String::from_utf8_lossy(payload),
                    msg.topic(),
                    msg.partition(),
                    msg.offset()
                );
                // Вручную подтверждаем обработку сообщения
                consumer.commit_message(&msg, rdkafka::consumer::CommitMode::Async).unwrap();
            }
            Err(e) => eprintln!("Ошибка получения: {}", e),
        }
    }
}

Работа с сериализацией данных

Часто требуется отправлять не просто строки, а структурированные данные (например, JSON). Для этого удобно использовать библиотеку serde:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct                    

Рекомендаций