Skip to content

pika集群迁移slot命令

chejinge edited this page Jul 23, 2023 · 3 revisions

pika支持codis sync slot迁移设计实现 为兼容pika官方版本,所以pika支持codis slot迁移实现是修改pika实现的,而不是修改pika的存储库nemo实现。 实现方法是,增加slot key(共1024个),set类型,用户发过来的每个key在进行修改操作(set, del, incr, hset, sadd , lpush, zadd......)时,根据slot = crc32(key)%1024计算出该key对应的的slot,然后将该key sadd或者srem到该slot对应的set key;迁移时,指定slot,从该slot spop(由于pika的spop会触发compact,所以是通过sscan和srem实现spop)出一个key然后迁移到目的的pika server。该实现的优点是和官方版本数据兼容,可以直接进行替换升级,不需要洗数据等,回退也方便。不足之处是每次修改操作均要有额外的set操作,降低了性能(大概降低10%~20%),增加了存储(增加30%左右),为了解决性能降低,存储增加的问题,所以增加了pika支持slot迁移的开关,开关关闭时,性能及存储使用和官方版本一致,打开开关时支持slot迁移。

##slot迁移开关## 开关可以通过配置文件配置conf/pika.conf:

slotmigrate [yes | no]

slotmigrate : yes ​ 也可以通过命令行config set进行配置:

$ redis-cli -h 127.0.0.1 -p 9221 config set slotmigrate yes ​ pika迁移codis添加命令说明: #####slotsinfo [start] [count]#####

命令说明:获取 redis 中 slot 的个数以及每个 slot 的大小 命令参数:缺省查询 [0, MAX_SLOT_NUM) start - 起始的 slot 序号 缺省 = 0 count - 查询的区间的大小,即查询范围为 [start, start + count) 缺省 = MAX_SLOT_NUM 返回结果:返回结果是 slotinfo 的 array;slotinfo 本身也是一个 array。 response := []slotinfo{slot1, slot2, slot3, ...}
slotinfo := []int{slotnum, slotsize}

其中: INT slotnum : slot 序号 INT slotsize : slot 内数据个数 ​ 例如: localhost:6379> slotinfo 0 128 1) 1) (integer) 23
2) (integer) 2 2) 1) (integer) 29 2) (integer) 1
​ #####slotsdel slot1 [slot2 …]#####

命令说明:删除 redis 中若干 slot 下的全部 key-value 命令参数:接受至少 1 个 slotnum 作为参数 返回结果:格式参见 slotsinfo,不同的是:slotsize 表示删除后剩余大小,通常为 0。 例如: localhost:6379> slotsdel 1013 990 1) 1) (integer) 1013 2) (integer) 0 2) 1) (integer) 990 2) (integer) 0 ​ ####数据迁移#### 以下4个命令是一族命令:

slotsmgrtslot - O(1) 随机在某个 slot 下迁移一个 key-value 到目标机器 slotsmgrtone - O(1) 将指定的 key-value 迁移到目标机 slotsmgrttagslot - O(n) 随机在某个 slot 下选择一个 key,并将与之有相同 tag 的 key-value 对全部迁移到目标机 slotsmgrttagone - O(n) 将与指定 key 具有相同 tag 的所有 key-value 对迁移到目标机 #####slotsmgrtslot host port timeout slot#####

命令说明:随机选择 slot 下的 1 个 key-value 到迁移到目标机(同步 IO 操作) 如果当前 slot 已经空了或者选择的 key 刚好过期,返回 0 如果当前 slot 下面还有 key 则选择一个进行迁移 同时返回当前 slot 剩余 key 的个数 迁移过程在目标机器调用 slotsrestore 命令,迁移会 覆盖旧值 命令参数: host:port - 目标机 redis 内部缓存到 host:port 的连接 30s,超时或错误则关闭

timeout - 操作超时,单位 ms 过程需要 3 个同步操作:

建立连接(可被缓存优化) 发送 key-value 数据 接受目标机返回 指令保证每个操作不超过 timeout

slot - 指定迁移的 slot 序号

返回结果: 操作返回 int response := []int{succ,size}

其中: INT succ : 表示迁移是否成功。 0 表示当前 slot 已经空了(迁移成功个数=0) 1 表示迁移一个 key 成功,并从本地删除(迁移成功个数=1) INT size : 表示 slot 下剩余 key 的个数 ​ 例如: localhost:6379> set a 100 # set <a, 100> OK localhost:6379> slotsinfo # slot 大小为 1 1) 1) (integer) 579 2) (integer) 1 localhost:6379> slotsmgrt 127.0.0.1 6380 100 579 (integer) 1 # 成功迁移 value localhost:6379> slotsinfo (empty list or set) localhost:6379> slotsmgrt 127.0.0.1 6380 100 579 1 (integer) 0 # 成功成功个数为 0;当前 slot 已经空了 #####slotsmgrtone host port timeout key#####

命令说明:迁移 key 到目标机,与 slotsmgrtslot 相同 命令参数:参见 slotsmgrtslot 返回结果: 操作返回 整数 (int) response := int(succ)

其中: INT succ : 与 slotsmgrtslot 相似 例如: localhost:6379> set a 100 # set <a, 100> OK localhost:6379> slotsinfo 1) 1) (integer) 579 2) (integer) 1 localhost:6379> slotsmgrtone 127.0.0.1 6380 100 a (integer) 1 # 迁移成功 localhost:6379> slotsmgrtone 127.0.0.1 6380 100 a (integer) 0 # 放弃迁移,本地已经不存在了 #####slotsmgrttagone host port timeout key#####

命令说明:迁移与 key 有相同的 tag 的所有 key 到目标机 当 key 中不包含合法 tag 时,命令退化为 slotsmgrtone 当 key 中包含合法 tag 时,命令扫描对应 slot 下的所有 key,找到所有含有相同 tag 的 key-value,一次原子的迁移到目标机 操作需要遍历整个 slot,复杂度 O(n) ,如果对应 key 不包含 tag 则退化为 O(1) 命令参数:参见 slotsmgrtone 返回结果: 操作返回 整数 (int) response := int(succ)

其中: INT succ : 表示成功迁移的 key 的个数。 例如: localhost:6379> set a{tag} 100 # set <a{tag}, 100> OK localhost:6379> set b{tag} 100 # set <b{tag}, 100> OK localhost:6379> slotsmgrttag 127.0.0.1 6380 1000 {tag} (integer) 2 localhost:6379> scan 0 # 迁移成功,本地不存在了 1) "0" 2) (empty list or set) localhost:6380> scan 0 # 数据一次成功迁移到目标机 1) "0" 2) 1) "a{tag}" 2) "b{tag}" #####slotsmgrttagslot host port timeout slot#####

命令说明:与 slotsmgrtslot 对应的迁移指令 其他说明参考 slotsmgrtslot 以及 slotsmgrttagone 的解释即可 #####slotsrestore key1 ttl1 val1 [key2 ttl2 val2 …]#####

命令说明:该命令是对 redis-2.8 的 restore 命令的扩展 可以对 restore 多个 key-value 过程是原子的。 备注:与 restore 不同的是,slotsrestore 只支持 replace,即一定 覆盖旧值 。如果旧值已经存在,那么只可能是 redis-slots 或者 proxy 的实现 bug,程序会通过 redisLog 打印一条冲突记录。 ####调试相关#### #####slotshashkey key1 [key2 …]#####

命令说明:计算并返回给定 key 的 slot 序号 命令参数:输入为 1 个或多个 key 返回结果: 操作返回 array response := []int{slot1, slot2...}

其中: INT slot : 表示对应 key 的 slot 序号,即 hash32(key) % NUM_OF_SLOTS 例如: localhost:6379> slotshashkey a b c # 计算 <a,b,c> 的 slot 序号 1) (integer) 579 2) (integer) 1017 3) (integer) 879 pika支持semi-async的迁移命令 除了pika支持sync迁移的一些如slotsinfo,slotsdel等,又添加了四个迁移命令:分别是slotsmgrttagslot-async,slotsmgrt-exec-wrapper,slotsmgrt-async-status,slotsmgrt-async-cancel:

slotsmgrttagslot-async: semi-async模式批量迁移key,使用方法如下:

127.0.0.1:9221> SLOTSMGRTTAGSLOT-ASYNC pika1 9221 5000 200 33554432 518 500 slotsmgrt-exec-wrapper: semi-async模式处理请求的key属于正在迁移slot的请求,使用方法如下:

127.0.0.1:9221> slotsmgrt-exec-wrapper test1 set test1 100 slotsmgrt-async-status: semi-async模式,查看迁移的状态,使用方法如下:

127.0.0.1:9221> slotsmgrt-async-status pika支持后台清理slot数据命令 前面介绍了slotsreload命令,该命令会遍历数据库里面所有的key,并根据hash算法函数,将key分别添加到对应slot的set slotkey里面。而pika添加的后台清理slot数据命令slotscleanup,则是遍历数据库里面的key时,如果发现属于被删除slot的key,则删除该key。由于遍历数据库所有的key会对系统产生一些压力,所以在一些压力大的情况下需要将slotscleanup停止掉,则可以执行slotscleanupoff命令,具体如下: slotscleanup: 后台清理不需要的slot的key,该命令执行后会立即返回,具体清除操作会在后台执行,可以通过info命令查看。如要清除slot 10,11,12,13,14,15的key,则可按如下执行:

127.0.0.1:9221> slotscleanup 10 11 12 13 14 15 slotscleanupoff: 停止后台执行的slot清除操作,使用方法如下:

127.0.0.1:9221> slotscleanupoff 127.0.0.1:9221> slotsreload

该命令是一个在后台运行的命令,类似bgsave模式,可以通过info命令查看slotsreload是否运行结束,在运行结束后才可以进行迁移。

如果数据库使用的场景中,有大量过期数据,大量使用expire等设置key过期的命令,建议不要在配置文件中打开开关(那些过期的数据,在slot里面没有进行过期删除,会导致数据累积,后面会考虑改进这点),可以考虑在需要迁移前在命令行打开开关,然后运行slotsreload命令,在slotsreload命令运行结束后,进行迁移,迁移完成后在命令行运行slotsdel命令进行收尾工作(释放磁盘占用),命令后面跟需要清理掉slot,如下方式

Clone this wiki locally