Skip to content

Ask the HotKV docs

Answers come only from these docs and can be wrong; check the linked pages before you rely on them.

CLUSTER MIGRATION

Last updated
CLUSTER MIGRATION IMPORT start-slot end-slot [start-slot end-slot ...]
CLUSTER MIGRATION STATUS ID task-id | ALL
CLUSTER MIGRATION CANCEL ID task-id | ALL
Group
Cluster
Complexity
O(N) where N is the number of keys in the slots (IMPORT), or the number of tasks (STATUS, CANCEL)
Arity
-4 (at least 4 words, counting the command name)
HotKV Cloud
Not available
On-Premise
no license needed

CLUSTER MIGRATION is the Redis 8 way to move slots atomically. You send IMPORT to the primary that is to receive the slots. It finds the node that owns them, copies the keys and the AI feature data of those slots, follows the writes made meanwhile, and takes the slots over in one step. Clients never see a half-moved slot, so there are no ASK redirects and no per-key MIGRATE. The command replies with a task ID at once and the move runs in the background. STATUS shows a task and CANCEL ends one.

redis-cli --cluster reshard and rebalance of Redis 8.4 and later use this command by themselves when every node of the cluster reports redis_version 8.4.0 or later (see compat-redis-version, default 8.4.0). Scaling compares it with the other ways of moving slots. The same move can be started from the source with CLUSTER MIGRATESLOTS.

Form Effect
IMPORT start-slot end-slot ... Take the slots in the inclusive ranges from their current owner. Ranges can come in any order, and a slot can be named only once. Every slot must have an owner, the same owner for all of them, and not this node.
STATUS ID task-id Show one task, whether it is running or finished.
STATUS ALL Show every task this node has: those in progress, or failed and waiting for their next try, first, then the finished ones, newest first, up to cluster-slot-migration-max-archived-tasks (default 32).
CANCEL ID task-id Cancel one task that is in progress or failed.
CANCEL ALL Cancel every such task.

A node runs one IMPORT at a time.

To hand the slots over, the source holds client writes to them once the target is within cluster-slot-migration-handoff-max-lag-bytes (default 1mb) of the writes the source has sent, for at most cluster-slot-migration-write-pause-timeout (default 10000 milliseconds). write_pause_ms reports how long that took.

A task that fails is not over: the target tries the import again every second until it succeeds or you cancel it. retries counts the tries.

IMPORT replies with the task ID, a bulk string of 40 hexadecimal characters, in RESP2 and RESP3.

STATUS replies with an array of tasks. Each task is a map in RESP3 and a flat array of field and value pairs in RESP2. STATUS ID of an ID that does not exist replies with an empty array.

Field Type Meaning
id Bulk string The task ID
slots Bulk string The slots, as ranges separated by spaces
source Bulk string The node ID of the node that owns the slots
dest Bulk string The node ID of the node that receives them
operation Bulk string import on the target, migrate on the source
state Bulk string Where the task is (below)
last_error Bulk string The reason the task last failed or was cancelled, empty otherwise
retries Integer How many times the task has been tried again
create_time Integer When the task was created, Unix time in milliseconds
start_time Integer When the current try started, Unix time in milliseconds
end_time Integer When the task ended, Unix time in milliseconds, and -1 while it has not
write_pause_ms Integer How long the source held writes to hand the slots over

The states on the target are none, connecting, auth-reply, handshake-reply, syncslots-reply, init-rdbchannel, accumulate-buffer (the copy arrives), streaming-buffer and wait-stream-eof (the writes made since the copy), and takeover. On the source they are wait-rdbchannel, wait-bgsave-start, send-bulk-and-stream (the copy), send-stream, handoff and stream-eof. A task ends as completed, canceled or failed. CLUSTER GETSLOTMIGRATIONS shows the same tasks with different field and state names.

CANCEL replies with an integer, the number of tasks it cancelled, which is 0 when no task matched. A cancelled task has the state canceled, and last_error says Cancelled due to user request. A task also ends as cancelled when this node becomes a replica, when the slots change owner by another command, when CLUSTER FORGET removes the other node, when CLIENT PAUSE is used, and when the server shuts down. Cancelling a task on the source with CLUSTER CANCELSLOTMIGRATIONS does not end it: the target tries again.

Errors:

Case Error
No subcommand, a missing argument, an odd number of slots, or a task ID missing after ID ERR wrong number of arguments for 'cluster|migration' command
STATUS or CANCEL followed by something other than ID or ALL ERR unknown argument
IMPORT on a replica ERR slot migration not allowed on replica.
A slot is open by hand (IMPORTING or MIGRATING) on this node ERR all slot states must be STABLE to start a slot migration task.
A slot outside 0 to 16383, or not a number ERR Invalid or out of range slot
A range that starts after it ends ERR start slot number <start> is greater than end slot number <end>
A slot named more than once ERR Slot <slot> specified multiple times
A slot has no owner ERR slot has no owner: <slot>
The slots have more than one owner ERR slots belong to different source nodes
This node owns the slots ERR this node is already the owner of the slot range
Another task is running on this node ERR an atomic slot migration task is still running here
Cluster mode is off ERR This instance has cluster support disabled

Import slots 100 to 199 into the primary on port 7003, which does not own them. The task ends completed on the target, and the source reports the same task as migrate:

127.0.0.1:7003> CLUSTER MIGRATION IMPORT 100 199
"0fdd612b88e9a3e41e32718ae4111f9b81e98128"
127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 0fdd612b88e9a3e41e32718ae4111f9b81e98128
1) 1) "id"
2) "0fdd612b88e9a3e41e32718ae4111f9b81e98128"
3) "slots"
4) "100-199"
5) "source"
6) "7318275656a439e2520d240886b8ed2cddb464fc"
7) "dest"
8) "66cf057e48f56b104d6abf3169c982e3f02ec4cc"
9) "operation"
10) "import"
11) "state"
12) "completed"
13) "last_error"
14) ""
15) "retries"
16) (integer) 0
17) "create_time"
18) (integer) 1791064444227
19) "start_time"
20) (integer) 1791064444228
21) "end_time"
22) (integer) 1791064444247
23) "write_pause_ms"
24) (integer) 0
127.0.0.1:7000> CLUSTER MIGRATION STATUS ID 0fdd612b88e9a3e41e32718ae4111f9b81e98128
1) 1) "id"
2) "0fdd612b88e9a3e41e32718ae4111f9b81e98128"
...
10) "migrate"
...
24) (integer) 18

A task that was running when its export was cancelled on the source. It failed, was tried again (retries is 1), and then you cancel it on the target:

127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab
1) 1) "id"
2) "9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab"
...
11) "state"
12) "accumulate-buffer"
13) "last_error"
14) "Main channel - the link to the source dropped (state: accumulate-buffer, rdb_channel_state: rdbchannel-transfer)"
15) "retries"
16) (integer) 1
...
127.0.0.1:7003> CLUSTER MIGRATION CANCEL ID 9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab
(integer) 1
127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab
1) 1) "id"
2) "9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab"
...
11) "state"
12) "canceled"
13) "last_error"
14) "Cancelled due to user request (state: accumulate-buffer, rdb_channel_state: rdbchannel-transfer)"
...

The same status as RESP3 maps:

$ redis-cli -3 --no-raw -p 7003 CLUSTER MIGRATION STATUS ALL
1) 1# "id" => "8077cb03457a205de36e93e964e8245133687196"
2# "slots" => "150-199"
3# "source" => "ea0c1bd255fc04ab7dfc3aabf682cb8f64f84cba"
4# "dest" => "49a04a859cbe2f18b168fdff41f4f2346045f9e3"
5# "operation" => "import"
6# "state" => "completed"
7# "last_error" => ""
8# "retries" => (integer) 0
9# "create_time" => (integer) 1791064214167
10# "start_time" => (integer) 1791064214167
11# "end_time" => (integer) 1791064214179
12# "write_pause_ms" => (integer) 0

Refusals:

127.0.0.1:7003> CLUSTER MIGRATION IMPORT 100 199
(error) ERR this node is already the owner of the slot range
127.0.0.1:7002> CLUSTER MIGRATION IMPORT 5000 6000
(error) ERR slots belong to different source nodes
127.0.0.1:7004> CLUSTER MIGRATION IMPORT 500 599
(error) ERR slot migration not allowed on replica.
127.0.0.1:7003> CLUSTER MIGRATION IMPORT 500 500 500 500
(error) ERR Slot 500 specified multiple times
127.0.0.1:7005> CLUSTER MIGRATION IMPORT 0 10
(error) ERR slot has no owner: 0
127.0.0.1:7003> CLUSTER SETSLOT 700 IMPORTING 7318275656a439e2520d240886b8ed2cddb464fc
OK
127.0.0.1:7003> CLUSTER MIGRATION IMPORT 500 549
(error) ERR all slot states must be STABLE to start a slot migration task.
127.0.0.1:7003> CLUSTER MIGRATION IMPORT 600 649
(error) ERR an atomic slot migration task is still running here
127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 0000000000000000000000000000000000000000
(empty array)

The subcommands, replies, error texts, task states and the retries behaviour follow Redis 8.4. In last_error, the text in parentheses gives the state of the task’s main channel and of its RDB channel, as Redis does. HotKV’s own AI data moves with the slots. CLUSTER MIGRATION STATUS also lists migrations started with CLUSTER MIGRATESLOTS, and CLUSTER GETSLOTMIGRATIONS lists the tasks started with CLUSTER MIGRATION IMPORT, each in the other command’s field names.

CLUSTER MIGRATESLOTS, CLUSTER GETSLOTMIGRATIONS, CLUSTER CANCELSLOTMIGRATIONS, CLUSTER SETSLOT, Scaling a cluster