项目地址:https://github.com/doyoubi/undermoon
目标:
- 简单
- 快速
迁移过程基于以下 Redis
命令:
- SCAN
- DUMP
- PTTL
- RESTORE
- DEL
SCAN
命令有一个很好的特性,它可以保证在第一个 SCAN
命令之前设置的所有 key
最终都会返回,但有时会返回多次。我们可以执行 3
阶段迁移来模拟复制。
- 等待
Redis
完成所有命令。 - 将所有读写操作重定向到目标
Redis
。如果key
不存在,则目标Redis
将需要在处理命令之前从源Redis
转储key
的数据。 - 开始扫描并将数据转发到
peer Redis
。
详细步骤
migrating proxy(迁移代理)
通过PreCheck
命令检查importing proxy(导入代理)
是否也收到迁移任务。migrating proxy
阻塞所有新添加的命令到Queue
,并等待现有命令完成。migrating proxy
向importing proxy
发送TmpSwitch
命令。收到此命令后,importing proxy
开始处理导入slot(槽)
范围内的key
。当命令返回时,migrating proxy
释放Queue
内的所有命令,并将它们重定向到importing proxy
。migrating proxy
使用SCAN
、PTTL
、DUMP
、RESTORE
、DEL
将迁移slot
范围内的所有数据转发到peer importing Redis
。RESTORE
不设置REPLACE
flag。importing proxy
在处理命令时,无论是读操作还是写操作,都会先- 将
EXISTS
和处理后的命令发送到local importing Redis
,如果EXISTS
返回true
,则将命令转发到local importing Redis
。 - 如果
EXISTS
返回false
,则发送DUMP
和PTTL
到迁移的Redis
获取数据,并RESTORE
数据并将命令转发到local Redis
。然后最后将命令转发到local importing Redis
。 - 如果该命令不会删除
key
,则获取key lock
, - 如果该命令可能删除
key
,则获取key lock
并将UMSYNC
发送到migrating proxy
,让migrating proxy
使用DUMP
、PTTL
、RESTORE
、DEL
将key
传输到importing proxy
。然后最后将命令转发到local importing Redis
。
- 将
- 当
migrating proxy
完成扫描后,它会向importing proxy
提出CommitSwitch
。然后importing proxy
只需要在local Redis
中处理命令。 - 通知
coordinator
并等待UMCTL SETCLUSTER
的最终提交。
为什么会这样设计
整个迁移过程基于以下命令 SCAN
、PTTL
、DUMP
、RESTORE
、DELETE
。仅向导入服务器代理发送 RESTORE
命令,因此为了获得更好的性能,应在迁移服务器代理中执行此扫描和传输。
由于扫描和传输在服务器代理和 Redis
上都占用了大量的 CPU
资源,因此最好在importing proxy
上处理其他工作负载。因此,一开始我们将所有插槽(slots
)直接转移到importing proxy
。
此时,importing proxy
仍然只有一小部分数据。当它需要处理新添加的 slots
上的命令时,需要在处理请求之前使用 PTTL
、DUMP
、RESTORE
从迁移的服务器代理中拉取数据。它还需要发送 DELETE
来删除 key
。
请注意,对于不会删除 key
的任何命令,由于它是幂等的,因此对同一 key
多次 RESTORE
仍然是正确的。所以仅仅让 importing proxy
来拉数据不会导致任何不一致。
但是对于那些可能删除 DEL
、EXPIRE
、KPOP
等 key
的命令,只让 importing proxy
拉取数据可能会导致以下情况:
key
被删除- 还有另一个
RESTORE
命令可以恢复key
。
因此,在提取数据时,需要将其与
importing proxy
中的其他RESTORE
命令。migrating proxy
中的SCAN
和RESTORE
。
因此,我们需要在 importing proxy
中锁定 key
,并且需要 migrating proxy
帮助我们发送数据而不是从importing proxy
中拉取数据,以便对该 key
的操作只能按顺序处理。
性能
因此,在迁移过程中,迁移和导入 proxy
的工作量非常平衡。migrating proxy
使用 130%
的 CPU
,importing proxy
使用 80%
的 CPU
。
而且迁移 1G
数据只用了不到一分钟。
在测试中,在迁移的同时进行基准测试,吞吐量从 50k
减少到 28k
并逐渐增加到 40k
。这是因为在迁移和importing proxy
中,SCAN
、DUMP
、RESTORE
会在 Redis
中消耗大量吞吐量。但是一旦 key
被迁移到导入服务器代理,它只需要在请求之前发送一个额外的 EXISTS
命令。
提交迁移后,吞吐量将翻倍。