構建一個純Rust非同步的Apache Kafka客戶端 - influxdata

banq發表於2022-03-19

InfluxDB的未來核心是InfluxDB IOx, 使用的是Apache  Kafka 對資料進行排序:
到目前為止,我們一直依賴於 rust-rdkafka,它為librdkafka提供非同步繫結,而 librdkafka又是用 C 編寫的。
那麼我們為什麼要替換它呢?以下是一些原因:
  • 複雜性: librdkafka 是一個複雜的庫,其中包含大量我們不需要或不想要的功能,它支援廣泛的 Kafka 版本,而我們基本上執行的是“最新版本”。由於 rust-rdkafka 也只公開了 librdkafka 功能的一小部分,我們認為這也可能適用於其他使用者。
  • 繫結:  rust-rdkafka 試圖將 librdkafka 塞入 Rust 非同步生態系統。這在一定程度上可行,但會導致一些問題,例如當從不同執行緒執行回撥時,tokio 會感到困惑。繫結本身也有一些限制。
  • 緩衝/模組化: 我們對 librdkafka 中的緩衝和批處理工作方式的控制有限。這是跨語言庫的固有問題。
  • 專業知識和見解: 錯誤和意外行為很難除錯。我們對在生產中使用當前狀態感到不舒服。
  • 可行性: 我們只使用非常有限的 Kafka 功能子集(例如,沒有事務),為此 Kafka 協議相當簡單。對於這個子集,編寫一個新客戶端實際上是可行的。

這就是為什麼我們決定在 Rust 中啟動一個簡單、新鮮、完全非同步的 Kafka 客戶端:  RSKafka
 
這是一個快速使用示例。首先,我們設定一個客戶端:

let connection = "localhost:9093".to_owned();
let client = ClientBuilder::new(vec![connection]).build().await.unwrap(); 

讓我們建立一個主題:

let topic = "my_topic";
let controller_client = client.controller_client().await.unwrap();
controller_client.create_topic(
    topic,
    2,      // partitions
    1,      // replication factor
    5_000,  // timeout (ms)
).await.unwrap(); 

然後我們生產和消費一些資料:

// get a client for writing to a partition
let partition_client = client
    .partition_client(
        topic.to_owned(),
        0,  // partition
    )
    .await
    .unwrap();
 
// produce some data
let record = Record {
    key: b"".to_vec(),
    value: b"hello kafka".to_vec(),
    headers: BTreeMap::from([
        ("foo".to_owned(), b"bar".to_vec()),
    ]),
    timestamp: OffsetDateTime::now_utc(),
};
partition_client.produce(vec![record]).await.unwrap();
 
// consume data
let (records, high_watermark) = partition_client
    .fetch_records(
        0,             // offset
        1..1_000_000,  // min..max bytes
        1_000,         // max wait time
    )
    .await
    .unwrap(); 

您可能會直接跳到 原始碼,但我也邀請您繼續閱讀並瞭解我們是如何構建它的,以及哪些實踐通常適用於客戶端庫。
詳細點選標題
 

相關文章