Este conteúdo não está disponível no idioma selecionado.
Chapter 21. Migrating ZooKeeper-based Kafka clusters
If you are using ZooKeeper for metadata management of your Kafka cluster, you must migrate to using Kafka in KRaft mode. KRaft mode replaces ZooKeeper for distributed coordination, offering enhanced reliability, scalability, and throughput.
Kafka 4.0 and later runs exclusively in KRaft mode, with no ZooKeeper integration. As a result of this change, Streams for Apache Kafka removed support for ZooKeeper-based Kafka clusters starting with version 3.0.
To complete the migration, follow the procedures in the order presented in this section.
21.1. Migration overview Copiar o linkLink copiado para a área de transferência!
Migrating an existing Kafka cluster from ZooKeeper to KRaft mode happens in four main phases. The diagrams show the logical transition at each step.
21.1.1. Phase 1: ZooKeeper-based cluster Copiar o linkLink copiado para a área de transferência!
Brokers store metadata in ZooKeeper and operate in ZooKeeper mode.
21.1.2. Phase 2: Deploy the KRaft controller quorum Copiar o linkLink copiado para a área de transferência!
A new set of dedicated controller nodes is deployed. They run in migration mode, connect to ZooKeeper, and wait for brokers to register.
Key changes:
- Controllers added
- Controllers connect to ZooKeeper
- Migration flag enabled
21.1.3. Phase 3: Enable migration on brokers (metadata migration in progress) Copiar o linkLink copiado para a área de transferência!
Brokers are rolled one at a time with updated configuration. On restart, each broker registers with the KRaft controller quorum.
When all brokers have registered, the KRaft controller leader begins the metadata migration process: it reads the existing metadata stored in ZooKeeper and writes it into the KRaft metadata log.
During this phase, the controllers also perform dual-write by copying new metadata updates back to ZooKeeper to maintain rollback compatibility.
Key changes:
- Brokers register with the KRaft controller quorum
- The KRaft controller leader migrates existing metadata from ZooKeeper into KRaft
- Brokers send new metadata updates to the KRaft controllers (not to ZooKeeper)
- KRaft controllers dual-write updates back to ZooKeeper to support rollback
- KRaft becomes the source of truth for cluster metadata
- ZooKeeper receives replicated metadata only to support rollback
21.1.4. Phase 4: Restart brokers in full KRaft mode Copiar o linkLink copiado para a área de transferência!
Brokers are rolled again with ZooKeeper configuration removed.
Key changes:
- Brokers operate fully in KRaft mode
- The KRaft controllers continue dual-write to ZooKeeper to support rollback
- This is the last point where rollback is possible
21.1.5. Phase 5: Finalize migration (controllers exit migration mode) Copiar o linkLink copiado para a área de transferência!
Controllers are rolled with ZooKeeper settings removed.
Key changes:
- Controllers stop dual-write to ZooKeeper
- ZooKeeper is no longer used by the cluster
- Rollback to ZooKeeper is no longer possible
- The cluster’s metadata is managed by the KRaft controller quorum
When the controllers exit migration mode, ZooKeeper can be decommissioned if it is not needed for other services.
21.2. Verify the ZooKeeper-Based Kafka Cluster is running Copiar o linkLink copiado para a área de transferência!
This procedure verifies that your ZooKeeper-based Kafka cluster is running and functioning correctly before you begin the migration. You check that ZooKeeper is available, that the brokers are connected, and that basic messaging works. An operational cluster is required for a successful migration to KRaft mode.
Prerequisites
- You are logged in to Red Hat Enterprise Linux as the Kafka user.
- Streams for Apache Kafka is installed on each host, and the configuration files are available.
- You are using Streams for Apache Kafka 2.9 (Kafka 3.9.x), which includes important fixes for KRaft migration. Migration is supported only on Streams for Apache Kafka 2.9. If you are using an earlier version, upgrade to 2.9 before migrating to KRaft mode.
-
All brokers must be configured with an inter-broker protocol version supported by Kafka 3.9.x (for example,
inter.broker.protocol.version=3.9). Using an older inter-broker protocol can prevent migration from starting or cause unexpected failures.
Procedure
Verify that ZooKeeper is running.
jcmd | grep zookeeperReturns:
<process_id> org.apache.zookeeper.server.quorum.QuorumPeerMain ./config/zookeeper.propertiesCheck that the Kafka brokers are running:
jcmd | grep kafkaReturns:
<process_id> kafka.Kafka ./config/server.propertiesEach Kafka broker appears as a running process.
Verify that each broker is connected to ZooKeeper.
Use the ZooKeeper shell to list the registered brokers:
./bin/zookeeper-shell.sh <zk-host>:2181 ls /brokers/idsReturns a list of the IDs for the brokers currently registered with ZooKeeper. This command confirms the brokers are registered with ZooKeeper. Client connectivity is verified in the next step.
Check the cluster is running correctly by sending and consuming messages.
For more information, see Sending and receiving messages from a topic.
21.3. Migrating from ZooKeeper to KRaft mode Copiar o linkLink copiado para a área de transferência!
This is a single end-to-end procedure for migrating a ZooKeeper-based Kafka cluster to KRaft mode. The workflow applies to both single-node and multi-node deployments.
To migrate your Kafka cluster to KRaft mode, complete the following steps:
- Install a quorum of dedicated controller nodes to replace ZooKeeper for metadata management.
- Enable KRaft metadata migration on the controllers.
- Start the controllers and enable migration on the existing brokers.
- Perform a rolling restart of the brokers to apply the configuration changes.
- After migration completes, switch the brokers to KRaft mode and disable migration on the controllers.
During the migration, the cluster enters a dual-write phase. ZooKeeper and the KRaft controllers store metadata in parallel until the final transition is complete.
After you finalize KRaft mode, you cannot roll back to ZooKeeper. Review your environment and backup requirements before proceeding.
Before starting the migration, verify that your environment can support Kafka in KRaft mode:
- Migration requires dedicated controller nodes. Nodes that act as both brokers and controllers are not supported.
- ZooKeeper and the KRaft controller quorum run in parallel during migration, so ensure that the cluster has sufficient compute resources.
If you previously rolled back a KRaft migration, make sure that all cleanup steps were completed before attempting the migration again:
- Delete the dedicated controller nodes.
-
Remove the
/migrationznode from ZooKeeper usingzookeeper-shell.sh:delete /migration
Skipping this cleanup can lead to metadata loss and migration failure.
Prerequisites
- The Kafka cluster is running.
Logging is enabled to monitor the migration process.
Set the root logger to
DEBUGon the controllers and brokers. For migration-specific logging, setTRACEfor the migration logger.Controller logging configuration
log4j.rootLogger=DEBUG log4j.logger.org.apache.kafka.metadata.migration=TRACE
Procedure
Retrieve the Kafka cluster ID using the
zookeeper-shelltool:./bin/zookeeper-shell.sh localhost:2181 get /cluster/idThe command prints connection information before returning the cluster ID. The final JSON line in the output contains the cluster ID. For example:
Connecting to localhost:2181 WATCHER:: WatchedEvent state:SyncConnected type:None path:null {"version":"1","id":"SY9T31EKSS6XeNO_Jio6yQ"}In this example, the cluster ID is
SY9T31EKSS6XeNO_Jio6yQ.Install a KRaft controller quorum to the cluster.
A KRaft controller quorum is required to manage metadata during the migration. Each controller runs in a dedicated role and must be configured separately.
Create a
controller.propertiesfile for each controller node.Each controller requires:
-
A unique
node.id. Thenode.idmust be unique across the entire Kafka cluster, including the existing brokers (which still usebroker.id). Brokers and controllers share a single ID namespace, so do not reuse an ID already assigned to a broker or another controller. -
The migration flag set to
true. - ZooKeeper connection details.
- A listener for controller-quorum communication.
- A list of all controllers in the quorum.
- A listener name for inter-broker communication.
A dedicated controller listener port that does not conflict with broker listener ports on the same host.
NoteThe controller listener is used for communication within the KRaft quorum and for controller-related requests from brokers and administrative clients. It is not used for regular client traffic such as producing or consuming messages.
Example controller configuration
process.roles=controller node.id=1 # Enable KRaft metadata migration zookeeper.metadata.migration.enable=true zookeeper.connect=zoo1.example.com:2181,zoo2.example.com:2181,zoo3.example.com:2181 # Listener for quorum communication listeners=CONTROLLER://0.0.0.0:9090 controller.listener.names=CONTROLLER listener.security.protocol.map=CONTROLLER:PLAINTEXT # List all controllers in the quorum controller.quorum.bootstrap.servers=controller1:9090,controller2:9090,controller3:9090 # Required for migration inter.broker.listener.name=PLAINTEXTUse a dedicated port for the controller listener that does not conflict with broker listeners on each host. In most deployments, the same controller listener port is used on every controller node, and the host name distinguishes each controller. Only controllers configure the quorum voters.
-
A unique
Generate a directory ID for each controller node.
CONTROLLER_1_DIR_ID="$(./bin/kafka-storage.sh random-uuid)" CONTROLLER_2_DIR_ID="$(./bin/kafka-storage.sh random-uuid)" CONTROLLER_3_DIR_ID="$(./bin/kafka-storage.sh random-uuid)"Each controller requires a unique directory ID for metadata storage initialization.
Format the metadata directory on each controller node.
Use the cluster ID retrieved from ZooKeeper and specify the initial controller quorum:
./bin/kafka-storage.sh format \ --cluster-id <cluster-id> \ --initial-controllers "1@controller1:9090:${CONTROLLER_1_DIR_ID},2@controller2:9090:${CONTROLLER_2_DIR_ID},3@controller3:9090:${CONTROLLER_3_DIR_ID}" \ --config ./config/kraft/controller.propertiesUse the same cluster ID and
--initial-controllersconfiguration on all controllers. Each controller entry uses the format<node.id>@<host>:<port>:<directory.id>.By default,
log.dirsis/tmp/kraft-controller-logs, which is cleared on system reboot. Set a persistent directory in production environments.Start each controller node.
./bin/kafka-server-start.sh -daemon ./config/kraft/controller.propertiesVerify that the controllers are running.
jcmd | grep kafkaYou should see one process per controller.
Confirm that each controller has entered the
PRE_MIGRATIONstate.Run the following command on each controller host:
grep "NONE to PRE_MIGRATION" ./logs/controller.logA log entry similar to the following indicates that the controller has started successfully, formed a quorum, and is ready for brokers to register:
Replayed a ZkMigrationStateRecord changing the migration state from NONE to PRE_MIGRATIONThis state confirms that the controllers are prepared to begin metadata migration when all brokers have been restarted with migration enabled.
Enable migration on each broker.
In this step, update each broker so it can register with the KRaft controller quorum and enter the migration process. Metadata migration does not begin immediately. The controllers start migrating metadata from ZooKeeper to KRaft only after all brokers have been restarted with migration enabled and have successfully registered with the controller quorum. During this phase, any new metadata created through brokers is written to KRaft first and then copied back to ZooKeeper by the controllers (dual-write) to maintain rollback compatibility. Controllers must be running before you restart any brokers.
Stop the broker running on the host.
./bin/kafka-server-stop.sh jcmd | grep kafkaIf you are using a multi-node cluster, restart brokers one at a time. For guidance, see Section 3.8, “Performing a graceful rolling restart of Kafka brokers”.
Update the broker configuration.
Edit the
server.propertiesfile to enable metadata migration and to add a listener for communication with the KRaft controllers.Each broker requires:
-
inter.broker.protocol.versionset to a supported version -
The migration flag set to
true - ZooKeeper connection details (already present on existing brokers)
- A controller listener on a free port
Controller quorum connection details (must list all controllers)
Example broker configuration
broker.id=0 # Set the inter-broker protocol version for migration inter.broker.protocol.version=3.9 # Enable dual-write migration mode zookeeper.metadata.migration.enable=true zookeeper.connect=zoo1.my-domain.com:2181,zoo2.my-domain.com:2181,zoo3.my-domain.com:2181 # Add a controller listener for KRaft quorum communication listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 listener.security.protocol.map=PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT # Connect the broker to the controller quorum controller.listener.names=CONTROLLER controller.quorum.bootstrap.servers=controller1:9090,controller2:9090,controller3:9090Use a unique controller listener port for each broker if required by your environment.
-
Restart the broker with the updated configuration.
./bin/kafka-server-start.sh -daemon ./config/kraft/server.propertiesThe broker starts with the migration-enabled configuration. Metadata migration begins after all brokers have restarted with migration enabled and have registered with the controller quorum. The time required for migration depends on the number of topics and partitions in the cluster.
Verify that the broker is running.
jcmd | grep kafkaYou should see a running
kafka.Kafkaprocess using the updated configuration file.
Confirm that metadata migration is complete.
After all brokers have registered with the KRaft controller quorum, the active controller begins migrating metadata from ZooKeeper into the KRaft metadata log.
Verify that the controller has entered the
MIGRATIONstate.Run the following command on the active controller host:
grep "PRE_MIGRATION to MIGRATION" ./logs/controller.logA log entry similar to the following indicates that the migration phase has started:
Replayed a ZkMigrationStateRecord changing the migration state from PRE_MIGRATION to MIGRATIONCheck the controller logs for the completion message.
Run the following command on the active controller host:
grep "migration.*ZooKeeper.*KRaft" ./logs/controller.logA log entry similar to the following indicates that the metadata migration phase has finished:
-
Completed migration of metadata from ZooKeeper to KRaft.
-
(Optional) Check the ZooKeeper
/migrationznode.This znode contains information about the active KRaft controller during migration:
./bin/zookeeper-shell.sh localhost:2181 get /migrationThe output includes the controller ID currently coordinating migration. Once the migration is complete, this information should reflect the active controller and the final metadata state.
Switch each broker to KRaft mode.
After the metadata migration is complete, you must update each broker so it runs fully in KRaft mode. This step removes all ZooKeeper-specific settings and enables the broker role in KRaft.
Stop the broker running on the host.
./bin/kafka-server-stop.sh jcmd | grep kafkaIf the cluster has multiple brokers, restart them one at a time.
Update the broker configuration.
Edit the
server.propertiesfile and make the following changes:-
Replace
broker.idwithnode.idusing the same value -
Add the KRaft broker role:
process.roles=broker -
Remove
inter.broker.protocol.version -
Remove
zookeeper.metadata.migration.enable -
Remove all ZooKeeper configuration (
zookeeper.connect) Remove any control-plane listener configuration (for example,
control.plane.listener.nameand its associated listener entry), if present.Example broker configuration for KRaft mode
node.id=0 process.roles=broker # Listener for client traffic listeners=PLAINTEXT://0.0.0.0:9092 # Connect the broker to the controller quorum controller.listener.names=CONTROLLER controller.quorum.bootstrap.servers=controller1:9090,controller2:9090,controller3:9090This configuration removes all ZooKeeper dependencies and enables the standalone KRaft broker mode.
-
Replace
Update the authorizer if you use ACLs.
ZooKeeper-based brokers use:
authorizer.class.name=kafka.security.authorizer.AclAuthorizerFor KRaft-based brokers, replace it with:
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizerRestart the broker.
./bin/kafka-server-start.sh -daemon ./config/kraft/server.propertiesThe broker starts in KRaft mode and connects to the controller quorum.
Switch each controller out of migration mode.
After all brokers are running in KRaft mode, update the controllers so that they stop interacting with ZooKeeper. This completes the migration process and places the cluster fully under KRaft control.
Stop the controller.
Stop the controller in the same way as the broker:
./bin/kafka-server-stop.sh jcmd | grep kafkaUpdate the controller configuration.
Edit the
controller.propertiesfile and remove all ZooKeeper-related migration settings:- Remove the ZooKeeper connection details
-
Remove the
zookeeper.metadata.migration.enableproperty Remove
inter.broker.listener.nameExample controller configuration after migration
process.roles=controller node.id=1 listeners=CONTROLLER://0.0.0.0:9090 controller.listener.names=CONTROLLER listener.security.protocol.map=CONTROLLER:PLAINTEXT controller.quorum.bootstrap.servers=controller1:9090,controller2:9090,controller3:9090
Restart the controller.
./bin/kafka-server-start.sh -daemon ./config/kraft/controller.propertiesVerify that the controller has exited migration mode.
Check the controller log:
grep "MIGRATION to POST_MIGRATION" ./logs/controller.logA log entry similar to the following indicates the transition out of migration:
Replayed a ZkMigrationStateRecord changing the migration state from MIGRATION to POST_MIGRATION.This confirms that the controller no longer relies on ZooKeeper and that the migration process is complete.
NoteAfter all brokers and controllers are running in KRaft mode and the controllers have exited migration mode, the cluster no longer relies on ZooKeeper for metadata management. If ZooKeeper is not required for other applications, you can decommission it.
21.4. Performing a rollback on the migration Copiar o linkLink copiado para a área de transferência!
If you have finalized the migration, rollback is not possible.
Before finalizing the migration, while the cluster is still in dual-write mode, you can roll back to ZooKeeper mode. The steps depend on how far the migration has progressed.
- If you’ve only completed the preparation and controller quorum setup, stop and remove the dedicated KRaft controller nodes from the cluster. No other changes are required, and the cluster continues to operate in ZooKeeper mode.
If you’ve enabled metadata migration on the brokers, follow these steps:
- Stop and remove the dedicated KRaft controller nodes from the cluster.
Use
zookeeper-shell.shto do the following:-
Run
delete /controllerto allow a ZooKeeper-based broker to become the active controller. -
Run
get /migrationto confirm that the migration znode exists, then rundelete /migrationto remove it. Removing this znode resets ZooKeeper to a clean pre-migration state.
WarningRun
delete /controllerpromptly to minimize controller downtime. Temporary errors in broker logs are expected until rollback completes.-
Run
On each broker:
Remove the following KRaft-related configurations:
-
zookeeper.metadata.migration.enable -
controller.listener.names -
controller.quorum.bootstrap.servers
-
-
Replace
node.idwithbroker.id
- Perform a rolling restart of all brokers.
If brokers have already been restarted in KRaft mode, follow these steps:
On each broker:
-
Remove
process.roles. -
Replace
node.idwithbroker.id.
-
Remove
-
Restore
zookeeper.connectand any required ZooKeeper settings. Perform a first rolling restart of the brokers.
ImportantRetain
zookeeper.metadata.migration.enable=truefor the first restart.- Stop and remove the dedicated KRaft controller nodes from the cluster.
Use
zookeeper-shell.shto do the following:-
Run
delete /controllerto allow a ZooKeeper-based broker to become the active controller. -
Run
get /migration, thendelete /migrationto inspect and clear the migration metadata (stored in the znode). This restores a clean state in ZooKeeper for retrying the migration.
-
Run
On each broker, remove KRaft-related configuration:
-
zookeeper.metadata.migration.enable -
controller.listener.names -
controller.quorum.bootstrap.servers
-
- Perform a second rolling restart of the brokers.