Redpanda簡介

banq發表於2024-03-17

在本教程中,我們將討論一個名為Redpanda的強大事件流平臺。這是對事實上的行業流媒體平臺Kafka 的競爭,有趣的是,它還與 Kafka API 相容。

我們將瞭解 Redpanda 的關鍵元件、功能和用例,建立用於將訊息釋出到 Redpanda 主題的 Java 程式,然後從中讀取訊息。

由於 Redpanda 的製作者聲稱自己是 Kafka 的競爭對手:

Redpanda 特點

  • 包括一個易於安裝的二進位制包
  • 不依賴JVM和第三方工具
  • 由於其每核執行緒程式設計模型,比 Kafka 快 10 倍
  • 用 C++ 編寫
  • 每個核心可以處理 1 GB/秒的寫入
  • 支援自動核心調整
  • p99999 延遲為 16ms
  • Redpanda Cloud 提供了一些開箱即用的託管聯結器

Redpanda架構
Redpanda 的架構不僅簡單而且非常容易掌握。有趣的是,它有一個易於安裝的二進位制安裝包。這使開發人員能夠快速領先,這也是其受歡迎的原因。此外,它還提供了一個具有極高吞吐量的高效能流媒體平臺。

關鍵部件和特性
讓我們深入瞭解 Redpanda 的關鍵元件和功能,這些元件和功能使其極其強大和高效能:

控制平面支援 Kafka API,用於管理代理、建立訊息主題、釋出和消費訊息等等。因此,依賴 Kafka 的遺留系統可以輕鬆遷移到 Redpanda。但是,有一組不同的管理 API 用於管理和配置 Redpanda 叢集。

Redpanda 支援分層儲存。這意味著我們可以將其配置為將其資料日誌從本地快取解除安裝或存檔到雲中更便宜的物件儲存。此外,根據消費者的需求,資料會實時從遠端物件儲存移回到本地快取。

Redpanda 有一個Raft 共識演算法實現層,可以跨節點複製主題分割槽資料。此功能可防止發生故障時資料丟失。自然也就保證了較高的資料安全性和容錯性。

Redpanda 擁有強大的身份驗證和授權支援。它可以使用 SASL、OAuth、OpenID Connect (OIDC)、基本身份驗證、Kerberos 等方法對外部使用者和應用程式進行身份驗證。此外,它還可以透過基於角色的訪問控制 (RBAC) 機制對其資源進行細粒度的訪問控制。

模式對於定義 Redpanda 經紀人、消費者和生產者之間交換的資料至關重要。因此,叢集有一個架構登錄檔。架構登錄檔 API 幫助註冊和修改架構。

HTTP代理 (pandaproxy) API提供了一種與 Redpanda 互動的便捷方式,以進行基本資料操作,例如列出主題和代理、獲取事件、生成事件等等。

最後,Redpanda為其監控提供了指標端點。這些可以在 Prometheus(監控工具)上進行配置,以提取重要指標並將其顯示在Grafana 儀表板上。


單個二進位制安裝包
Redpanda 的安裝包包含一個二進位制檔案,因此它的安裝比 Kafka 簡單得多。與 Kafka 不同,它不依賴於 JVM 或 Zookeeper 等叢集管理器。由於這些因素,操作 Redpanda 非常容易。

它是用 C++ 開發的,具有引人注目的每核執行緒程式設計模型,有助於最佳地利用 CPU 核心、記憶體和網路。因此,其部署的硬體成本顯著降低。該模型還可以實現低延遲和高吞吐量。

Redpanda 的叢集由多個節點組成。每個節點可以是資料平面或控制平面。所有這些節點都需要安裝一個具有適當配置的二進位制包。如果節點具有高階計算能力,則它們可以同時扮演這兩種角色,而不會出現效能瓶頸。

管理工具
Redpanda 提供了兩種管理工具,一個Web 控制檯和一個稱為Redpanda Keeper (RPK)的 CLI 。控制檯是一個使用者友好的 Web 應用程式,叢集管理員可以使用。
RPK 主要用於低階叢集管理和調優。但是,控制檯提供了資料流的可見性以及故障排除和管理叢集的功能。


部署
Redpanda支援自託管和Redpanda雲部署。

在自託管部署中,客戶可以將 Redpanda 叢集部署在其私有資料中心內或公有云的 VPC 中。它可以部署在物理機或虛擬機器以及 Kubernetes 上。根據經驗,每個代理都應該有其專用節點。目前支援RHEL/CentOS和Ubuntu作業系統。

此外,AWS Simple Storage Service (S3)、Azure Blob Storage (ABS) 和 Google Cloud Storage (GCS) 可用於支援分層儲存。

有趣的是,客戶還可以選擇Redpanda Cloud來提供託管服務。他們可以將整個叢集完全放在 Redpanda Cloud 上,也可以選擇擁有在其私有資料中心或公共雲帳戶中執行的資料平面。控制平面保留在 Redpanda Cloud 上,監控、配置和升級都在其中完成。

關鍵用例
與 Kafka 不同,Redpanda 對於開發人員來說是一個極其強大的流媒體平臺,因為它的架構簡單且易於安裝。讓我們沿著同樣的思路快速瀏覽一下用例:
一般來說,流媒體平臺的參與者是:

  • 源系統生成提要
  • 源可以監視事件、指標、通知等
  • 叢集中的代理管理主題
  • 生產者從源系統讀取提要並將其釋出到主題
  • 消費者不斷對訂閱的主題進行民意調查
  • 目標系統接收來自消費者的轉換後的訊息

Redpanda 保證將來自監控工具、合規性和安全平臺、物聯網裝置等各種來源的實時資訊傳送到目標系統,平均延遲降低 10 倍。

它支援消費者和生產者模型來處理來自各種來源的實時提要或事件。生產者是從源系統讀取資料並將其釋出到 Redpanda 叢集中的主題的應用程式。叢集中的broker高度可靠、容錯,保證訊息的傳遞。

消費者應用程式訂閱叢集中的主題。最終,他們從主題中讀取資料,並在進一步轉換資料後,將其傳送到各種目標系統,如分析平臺、NoSQL 資料庫、關聯式資料庫或其他流平臺。

在微服務架構中,Redpanda 透過促進微服務之間的非同步通訊來幫助解耦微服務。

因此,它可以在各行業的發展中發揮重要作用:

  • 用於事件和日誌處理、報告、故障排除和自動修復的可觀察性平臺
  • 實時合規和欺詐檢測系統
  • 實時分析儀表板和應用程式

使用 Kafka API 實現 Redpanda 客戶端
值得注意的是,Redpanda 支援 Kafka API。因此,我們將使用 Kafka 客戶端編寫可以與 Redpanda Stream 互動的程式。

對於我們的示例,我們使用Java Testcontainers在 Windows 桌面上部署單節點 Redpanda。

此外,我們將探索涵蓋主題建立、訊息釋出和訊息消費的基本程式。這僅用於演示目的,因此,我們不會深入研究 Kafka API 概念。

先決條件
在開始之前,讓我們匯入Kafka 客戶端庫所需的Maven 依賴項:

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>3.6.1</version>
</dependency>

建立主題
為了在 Redpanda 上建立主題,我們首先例項化Kafka 客戶端庫中的AdminClient類:

AdminClient createAdminClient() {
    Properties adminProps = new Properties();
    adminProps.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, getBrokerUrl());
    return KafkaAdminClient.create(adminProps);
}

為了設定AdminClient,我們獲取了代理 URL 並將其傳遞給其靜態create()方法。

現在,讓我們看看如何建立主題:

void createTopic(String topicName) {
    try (AdminClient adminClient = createAdminClient()) {
        NewTopic topic = new NewTopic(topicName, 1, (short) 1);
        adminClient.createTopics(Collections.singleton(topic));
    } catch (Exception e) {
        LOGGER.error(<font>"Error occurred during topic creation:", e);
    }
}

AdminClient類的createTopics ()方法採用NewTopic物件作為建立主題的引數。

最後,讓我們看一下createTopic()方法的實際操作:

@Test
void whenCreateTopic_thenSuccess() throws ExecutionException, InterruptedException {
    String topic = <font>"test-topic";
    createTopic(topic);
    try(AdminClient adminClient = createAdminClient()) {
        assertTrue(adminClient.listTopics()
          .names()
          .get()
          .contains(topic));
    }
}

程式在Redpanda上成功建立了主題test-topic。我們還使用AdminClient類的listTopics()方法驗證代理中主題是否存在。

向主題釋出訊息
可以理解的是,生產者應用程式最基本的要求是將訊息釋出到主題。為此,我們將使用KafkaProducer:

KafkaProducer<String, String> createProducer() {
    Properties producerProps = new Properties();
    producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, getBrokerUrl());
    producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
    producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
    return new KafkaProducer<String, String>(producerProps);
}

我們透過向KafkaProducer建構函式提供代理 URL 和StringSerializer類等基本屬性來例項化生產者。

現在,讓我們使用生產者將訊息釋出到主題:

void publishMessage(String msgKey, String msg, String topic, KafkaProducer<String, String> producer)
    throws ExecutionException, InterruptedException {
    ProducerRecord<String, String> record = new ProducerRecord<>(topic, msgKey, msg);
    producer.send(record).get();
}

建立ProducerRecord物件後,我們將其傳遞給KafkaProducer物件中的send()方法來發布訊息。send ()方法是非同步操作的,因此,我們呼叫get()方法來確保在訊息釋出之前處於阻塞狀態。

最後,現在讓我們釋出一條訊息:

@Test
void givenTopic_whenPublishMsg_thenSuccess() {
    try (final KafkaProducer<String, String> producer = createProducer()) {
        assertDoesNotThrow(() -> publishMessage(<font>"test_msg_key_2", "Hello Redpanda!", "baeldung-topic", producer));
    }
}

首先,我們透過呼叫方法createProducer() 建立KafkaProducer物件。然後我們釋出訊息“Hello Redpanda!” 透過呼叫我們之前介紹過的方法publishMessage()到主題baeldung-topic 。

使用主題中的訊息
下一步,我們首先建立一個KafkaConsumer,然後才能使用流中的訊息:

KafkaConsumer<String, String> createConsumer() {
    Properties consumerProps = new Properties();
    consumerProps.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, <font>"earliest");
    consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, getBrokerUrl());
    consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG,
"test-consumer-group");
    consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
    consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
    return new KafkaConsumer<String, String>(consumerProps);
}

我們透過向KafkaConsumer建構函式提供代理 URL、 StringDeSerializer類等基本屬性來例項化消費者。此外,我們確保消費者將從偏移量 0(“最早”)開始消費訊息。

繼續,讓我們使用一些訊息:

@Test
void givenTopic_whenConsumeMessage_thenSuccess() {
    try (KafkaConsumer<String, String> kafkaConsumer = createConsumer()) {
        kafkaConsumer.subscribe(Collections.singletonList(TOPIC_NAME));
        while(true) {
            ConsumerRecords<String, String> records = kafkaConsumer.poll(Duration.ofMillis(1000));
            if(records.count() == 0) {
                continue;
            }
            assertTrue(records.count() >= 1);
            break;
        }
    }
}

該方法在建立KafkaConsumer物件後訂閱一個主題。然後,它每 1000 毫秒輪詢一次以從中讀取訊息。在這裡,為了演示,我們將退出迴圈,但在現實世界中,應用程式會不斷輪詢訊息,然後進一步處理它們。