CLUSTER MIGRATION
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.
Options
Section titled “Options”| 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.
Return value
Section titled “Return value”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 |
Examples
Section titled “Examples”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 0fdd612b88e9a3e41e32718ae4111f9b81e981281) 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) 0127.0.0.1:7000> CLUSTER MIGRATION STATUS ID 0fdd612b88e9a3e41e32718ae4111f9b81e981281) 1) "id" 2) "0fdd612b88e9a3e41e32718ae4111f9b81e98128" ... 10) "migrate" ... 24) (integer) 18A 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 9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab1) 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) 1127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 9ec1175e94f56fd3e5082beb8011f2d1e3a2c0ab1) 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 ALL1) 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) 0Refusals:
127.0.0.1:7003> CLUSTER MIGRATION IMPORT 100 199(error) ERR this node is already the owner of the slot range127.0.0.1:7002> CLUSTER MIGRATION IMPORT 5000 6000(error) ERR slots belong to different source nodes127.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 times127.0.0.1:7005> CLUSTER MIGRATION IMPORT 0 10(error) ERR slot has no owner: 0127.0.0.1:7003> CLUSTER SETSLOT 700 IMPORTING 7318275656a439e2520d240886b8ed2cddb464fcOK127.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 here127.0.0.1:7003> CLUSTER MIGRATION STATUS ID 0000000000000000000000000000000000000000(empty array)Compatibility
Section titled “Compatibility”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.
See also
Section titled “See also”CLUSTER MIGRATESLOTS, CLUSTER GETSLOTMIGRATIONS, CLUSTER CANCELSLOTMIGRATIONS, CLUSTER SETSLOT, Scaling a cluster
Was this page helpful?
Thanks for the feedback.