使用KEDA和Kafka在 Kubernetes 上自動擴充套件 - Piotr

banq 發表於 2022-01-25
IoT Kafka Kubernetes

在本文中,您將學習如何使用KEDA自動擴充套件使用來自 Kafka 主題的訊息的應用程式。KEDA縮寫是Kubernetes Event Driven簡寫。

為了解釋它背後的想法,我將建立兩個簡單的服務。第一個是向 Kafka 主題傳送事件,第二個是接收它們。我們將在 Kubernetes 上執行這兩個應用程式。為了簡化練習,我們可以使用 Spring Cloud Stream,它提供了與 Kafka 的智慧整合。

 

架構

在我們開始之前,讓我們花點時間來了解我們今天的場景。我們有一個單一的Kafka主題,被我們兩個應用程式用來交換事件。這個主題由10個分割槽組成。還有一個單一的生產者例項,定期傳送事件。我們將縮減和增加消費者服務的pod數量。消費者服務的所有例項都被分配到同一個Kafka消費者組。這意味著該組中只有一個例項可以接收特定的事件。

每個消費者例項只有一個接收執行緒。因此,我們可以很容易地模擬一個事件的處理時間。我們將讓主執行緒休眠1秒。另一方面,生產者將以一個可變的速度傳送事件。同時,它將在所有可用的分割槽中分割訊息。這樣的行為可能會導致分割槽上的消費者滯後,因為Spring Cloud Stream只有在處理完一個訊息後才會提交偏移。在我們的案例中,滯後的數值取決於生產者的速度和執行中的消費者例項的數量。為了澄清這一點,讓我們看看下面的圖表。

使用KEDA和Kafka在 Kubernetes 上自動擴充套件 - Piotr

我們的目標非常簡單。我們需要根據生產者服務產生的流量來調整消費者例項的數量。偏移滯後的值不能超過期望的閾值。如果我們增加生產者一方的流量率,KEDA應該增加消費者例項的數量。因此,如果我們降低生產者的流量率,它應該減少消費者例項的數量。下面是我們的場景圖。

使用KEDA和Kafka在 Kubernetes 上自動擴充套件 - Piotr

 

 

在Spring Cloud Stream中使用Kafka

為了將Spring Cloud Stream用於Kafka,我們只需在Maven pom.xml中加入一個依賴項。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>

之後,我們可以使用一個標準的Spring Cloud Stream模型。然而,在後臺,它通過一個特殊的繫結器實現與Kafka整合。

我們的兩個應用程式都非常簡單。生產者只是生成和傳送事件(預設為JSON格式)。我們在程式碼中需要做的唯一事情是宣告Supplier Bean。在後臺,有一個單執行緒,每秒鐘生成和傳送CallmeEvent。每一次它只增加訊息中的id欄位。

@SpringBootApplication
public class ProducerApp {

   private static int id = 0;

   public static void main(String[] args) {
      SpringApplication.run(ProducerApp.class, args);
   }

   @Bean
   public Supplier<CallmeEvent> eventSupplier() {
      return () -> new CallmeEvent(++id, "Hello" + id, "PING");
   }

}

我們可以用下面的屬性改變Supplier 每次傳送之間的預設固定延遲。比方說,我們想每隔100毫秒傳送一個事件。

spring.cloud.stream.poller.fixedDelay = 100

我們還應該提供基本的配置,如Kafka地址、主題名稱(如果與Supplier函式的名稱不同)、分割槽的數量和分割槽的金鑰。Spring Cloud Stream會在應用啟動時自動建立主題、話題。

spring.cloud.stream.bindings.eventSupplier-out-0.destination = test-topic
spring.cloud.stream.bindings.eventSupplier-out-0.producer.partitionKeyExpression = payload.id
spring.cloud.stream.bindings.eventSupplier-out-0.producer.partitionCount = 10
spring.kafka.bootstrap-servers = one-node-cluster.redpanda:9092

現在,消費者的應用。它也不是很複雜。正如我之前提到的,為了模擬處理時間,我們將在接收方法裡面休眠主執行緒。

public class ConsumerApp {

   private static final Logger LOG = LoggerFactory.getLogger(ConsumerAApp.class);

   public static void main(String[] args) {
      SpringApplication.run(ConsumerApp.class, args);
   }

   @Bean
   public Consumer<Message<CallmeEvent>> eventConsumer() {
      return event -> {
         LOG.info("Received: {}", event.getPayload());
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) { }
      };
   }

}

最後,在消費者方面的配置。設定消費者組並啟用分割槽是很重要的。

spring.cloud.stream.bindings.eventConsumer-in-0.destination = test-topic
spring.cloud.stream.bindings.eventConsumer-in-0.group = a
spring.cloud.stream.bindings.eventConsumer-in-0.consumer.partitioned = true
spring.kafka.bootstrap-servers = one-node-cluster.redpanda:9092

現在,我們應該把這兩個應用程式部署在Kubernetes上。

但在這之前,我們先在Kubernetes上安裝Kafka和KEDA。

更多點選標題見原文