Перейти к основному содержимому
Нормативная версия документации - английская

Эта страница переведена с английского языковой моделью. При любом расхождении верен английский оригинал.

Начало работы

Это руководство устанавливает ruststream-rdkafka, запускает локальную Kafka и первый сервис на ней.

Установка​

Cargo.toml
[dependencies]
ruststream = { version = "0.7", features = ["macros", "json", "logging"] }
ruststream-rdkafka = "0.7"
serde = { version = "1", features = ["derive"] }
tracing = "0.1"

[dev-dependencies]
ruststream-rdkafka = { version = "0.7", features = ["testing"] }
tokio = { version = "1", features = ["macros", "rt"] }

ruststream - это сам фреймворк. Фича macros даёт атрибуты, json - кодек по умолчанию, а logging выводит журнал сервиса в терминал. ruststream-rdkafka - брокер Kafka. Его фича testing добавляет Kafka внутри процесса, на которой работают тесты.

У крейта брокера такие фичи:

ФичаЧто она даёт
json (по умолчанию), msgpack, cborодноимённый кодек
schema-registryклиент Confluent Schema Registry и его формат данных
avroAvro поверх Schema Registry
protobufсообщения Protobuf в конверте Confluent
asyncapiпривязки Kafka в генерируемом документе AsyncAPI
testingKafka внутри процесса, на которой работает TestApp
sslTLS через системный OpenSSL
ssl-vendoredTLS через OpenSSL, собранный из исходников
zstdкодек сжатия zstd

Системные требования​

Крейт собирает из исходников librdkafka, клиент Kafka на C. Для сборки нужны компилятор C и make. Конфигурацию librdkafka выполняет собственный скрипт. В Debian и Ubuntu оба инструмента ставит пакет build-essential. Фиче ssl нужны ещё заголовки OpenSSL (libssl-dev), а ssl-vendored нужен perl, чтобы собрать OpenSSL. Сборку через CMake и системную librdkafka даёт rust-rdkafka. Добавьте rdkafka в свои зависимости с нужной фичей, и сборка её подхватит.

Локальная Kafka​

Для разработки достаточно одного узла Kafka в режиме KRaft:

compose.yaml
services:
kafka:
image: apache/kafka:4.0.0
ports:
- "9092:9092"

Запустите его и создайте тему, которую читает сервис:

docker compose up -d
docker compose exec kafka /opt/kafka/bin/kafka-topics.sh \
--bootstrap-server localhost:9092 --create --topic orders

Брокер слушает localhost:9092.

Первый сервис​

src/main.rs
#[derive(Debug, PartialEq, Deserialize)]
struct Order {
id: u64,
amount_cents: u64,
}

#[subscriber("orders")]
async fn take_order(order: &Order) -> HandlerOutcome {
if order.amount_cents == 0 {
tracing::warn!(order.id, "order without an amount dropped");
return HandlerOutcome::drop();
}
tracing::info!(order.id, order.amount_cents, "order taken");
HandlerOutcome::ack()
}

#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("orders", "0.1.0")).with_broker(
KafkaBroker::new(["localhost:9092"]).default_group("orders-svc"),
|b| {
b.include(take_order);
},
)
}

take_order читает заказы в JSON из темы orders. Заказ с суммой он подтверждает, а заказ без суммы отбрасывает. KafkaBroker::new принимает начальные адреса кластера и только запоминает их. Соединение открывается при запуске сервиса. Kafka читает тему только в составе группы консьюмеров. default_group - группа каждой подписки, которая не называет свою. #[ruststream::app] превращает app в main. В ручной форме то же делает run_main.

Запустите сервис:

cargo run -- run

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

echo '{"id":1,"amount_cents":1250}' | docker compose exec -T kafka \
/opt/kafka/bin/kafka-console-producer.sh --bootstrap-server localhost:9092 --topic orders

Сервис пишет в журнал order taken с номером заказа. Ctrl+C останавливает его.

cargo generate создаёт такой же сервис с роутером и ответом:

cargo generate --git https://github.com/powersemmi/ruststream-rdkafka templates/kafka-topic --name my-service

Первый тест​

В файле примера есть и два теста. Каждый запускает то же app через TestApp::start, публикует заказ и проверяет, как take_order завершил его доставку. Там KafkaBroker подключается к Kafka внутри процесса, поэтому тестам не нужен кластер:

cargo test

Руководство Тестирование сервиса на Kafka разбирает эти тесты и то, что моделирует Kafka внутри процесса.

Переход с rust-rdkafka​

Сервис на rust-rdkafka сам пишет цикл консьюмера и продюсер. Вот куда переходит каждая часть в RustStream:

rust-rdkafkaRustStream
ClientConfig::new().set("group.id", ..)default_group или KafkaTopic::group для отдельной подписки
ClientConfig::set для любого другого свойстваKafkaBroker::config, producer_config, KafkaTopic::config
StreamConsumer::subscribe и цикл recvобработчик #[subscriber]
десериализация message.payload()тип параметра обработчика, который декодирует кодек
store_offset или commit_message после работыCommit::Tracked и исход обработчика (Фиксация и гарантии доставки)
FutureProducer::sendответ или параметр Out, отправленный через политику публикации
seek и assignstart_at в точке монтирования или ручка перемотки в обработчике (Повторное чтение и перемотка)
send_offsets_to_transactionEosPublish (Транзакции и exactly-once)