Persistent Kafka transacton-id across restarts on Kubernetes

11/18/2019

I am trying to achieve the exactly-once delivery on Kafka using Spring-Kafka on Kubernetes. As far as I understood, the transactional-ID must be set on the producer and it should be the same across restarts, as stated here https://stackoverflow.com/a/52304789/3467733.

The problem arises using this semantic on Kubernetes. How can you get a consistent ID?

To solve this problem I implementend a Spring boot application, let's call it "Replicas counter" that checks, through the Kubernetes API, how many pods there are with the same name as the caller, so I have a counter for every pod replica.

For example, suppose I want to deploy a Pod, let's call it APP-1.

This app does the following:

  1. It perfoms a GET to the Replicas-Counter passing the pod-name as parameter.
  2. The replicas-counter calls the Kubernetes API in order to check how many pods there are with that pod name. So it does a a +1 and returns it to the caller. I also need to count not-ready pods (think about a first deploy, they couldn't get the ID if I wasn't checking for not-ready pods).
  3. The APP-1 gets the id and will use it as the transactional-id

But, as you can see a problem could arise when performing rolling updates, for example:

Suppose we have 3 pods:

At the beginning we have:

  • app-1: transactional-id-1
  • app-2: transactional-id-2
  • app-3: transactional-id-3

So, during a rolling update we would have:

  • old-app-1: transactional-id-1
  • old-app-2: transactional-id-2
  • old-app-3: transactional-id-3
  • new-app-3: transactional-id-4 (Not ready, waiting to be ready)

    New-app-3 goes ready, so Kubernetes brings down the Old-app-3. So time to continue the rolling update.

  • old-app-1: transactional-id-1

  • old-app-2: transactional-id-2

  • new-app-3: transactional-id-4
  • new-app-2: transactional-id-4 (Not ready, waiting to be ready)

As you can see now I have 2 pods with the same transactional-id.

As far as I understood, these IDs have to be the same across restarts and unique.

How can I implement something that gives me consistent IDs? Is there someone that have dealt with this problem?

The problem with these IDs are only for the Kubernetes Deployments, not for the Stateful-Sets, as they have a stable identifier as name. I don't want to convert all deployment to stateful sets to solve this problem as I think it is not the correct way to handle this scenario.

-- Justin
apache-kafka
kubernetes
spring-kafka

1 Answer

11/27/2019

The only way to guarantee the uniqueness of Pods is to use StatefulSet. StatefulSets will allow you to keep the number of replicas alive but everytime pod dies it will be replaced with the same host and configuration. That will prevent data loss that is required.

Service in Statefulset must be headless because since each pod is going to be unique, so you are going to need certain traffic to reach certain pods.

Every pod require a PVC (in order to store data and recreate whenever pod is deleted from that data).

Here is a great article describing why StatefulSet should be used in similar case.

-- acid_fuji
Source: StackOverflow