概述
Redis集群版采用hash slot的方式来决定key存在哪个slot中。它总共有16384个slot,通过CLUSTER SLOTS或者CLUSTER NODES可获取slot分布情况。每个key只能存储于一个slot里面,具体一个key存储于哪个slot是通过crc16( key)%16384计算得来。也可通过命令CLUSTER KEYSLOT获取某个key位于哪个slot,一般情况下,集群中每个分片平均分配slot。比如3个分片。那每个分片的slot分别为0-5460,5461-10922,10923-16383。但这些slot并不是固定的,可以动态调整。下面则主要介绍它的调整方式及存在的问题及风险。
迁移一个slot大体可简化为3步,流程如下图所示:
Redis迁移流程
标记迁移目标分片的待迁移slot为IMPORTING状态,然后再标记源分片待迁移slot为MIGRATING状态。这里标记状态一定不能置换,否则会导致在该slot上的源分片及目标分片都无法写入新数据。
依次获取slot中的key,然后将这些key迁移到目标分片,直到所有的key迁移完成。
标记迁移完的slot归属权为迁移的目标分片,然后再标记源分片迁移完的slot归属于目标分片。这里标记状态一定不能置换,否则同 样会导致在该slot上的源分片及目标分片都无法写入新数据。
首先创建一个3主3从的集群,其初始化的集群分片信息如下,其中红色标记了分片slot信息,其第一列为分片ID。
32fe95bc56611ced95553ba90bc7add1e3bef3ad 9.134.240.17:2777@12777 master - 0 1581226004825 4 connected 0-5460
ea63f5b7a787f2f12c74669814db487b1b18a887 9.134.240.102:3307@13307 slave c6e02ef185bd9d641b8a50fd82781f0aeb5eb618 0 1581226005827 5 connected
952c500a85976e818ce0da15e036f96f0076382c 9.134.240.214:3074@13074 myself,slave 32fe95bc56611ced95553ba90bc7add1e3bef3ad 0 1581225986000 3 connected
c6e02ef185bd9d641b8a50fd82781f0aeb5eb618 9.134.240.85:1637@11637 master - 0 1581226003824 5 connected 10923-16383
5a7c0f4a005ba70c8aa5097424d85dc07eb19c6e 9.134.241.18:3447@13447 master - 0 1581226002822 2 connected 5461-10922
a2574a5a2f54db80e4e401f8a1cc900b2da035aa 9.134.240.75:4219@14219 slave 5a7c0f4a005ba70c8aa5097424d85dc07eb19c6e 0 1581226006828 2 connected
首先写入一个testmigrate到集群中,通过cluster keyslot testmigrate可算出它位于4470号slot,那么待迁移的源分片为32fe95bc56611ced95553ba90bc7add1e3bef3ad,在迁移前,向源分片写入set testmigrate 1。我们将这个分片迁移到目标分片c6e02ef185bd9d641b8a50fd82781f0aeb5eb618。
Redis请求处理为单线程,所有命令都只能串形执行,如果在我们迁移过程中有一个大key,那么在迁移过程用户及集群gossip请求处理都会阻塞,在我们的迁移测试中,迁移600MB的list,4千万个整形key,整个迁移时间为7.42s。那在这个7.42s的过程中,用户是无法有请求响应。由于我们分片cluster-node-timeout为默认的15s,所以在整个迁移过程中如果超过15s分片会被判死,从而导致主从切换。为了减少对业务的影响,同时避免主从切换,那就需要控制迁移时间。为了控制每次Key的搬迁时长,我们引入了迁移评估流程,就是在迁移前,检查是否满足迁移条件,总共需要检查的有两个点,一是每个key的搬移时长不能超过指定时长,我们目前定的是3s,那转换为key的大小,大体为200MB,所以我们在迁移过程中是限制单Key不能超过200MB,
除迁移时长外,还一个就是迁移容量,迁移过程中一定要保证目标分片一定有足够的容量容下带迁移的key。Redis获取key的容量使用的是MEMORY USAGE key samples count方法,但这个方法需要借助管控去查询所有待迁移的key,并且分slot统计需要迁移的容量,这种方式最主要的问题就是速度太慢。为了减少评估时间,我们在Redis中新增了评估命令,该命令返回slot的容量及其中最大Key的容量来解决迁移评估。如果在一个缩容流程中,它的数据迁移流程如下:
扩缩容流程
在上节3b步骤中提过其存在的问题,这里不在重复。除了一些批量执行命令外,在lua执行中也可能出现执行报错。
由于在新分片无lua相关脚本 ,如果通过EVALSHA执行则会报错。 但在实际中,一般比较少的情况下只使用evalsha命令,因为lua脚本一旦变了,那么脚本的sha也会改变。
源分片发生主从切换,此时集群在目标分片不认可源分片对迁移分片的归属权,从而导致该分片认为集群fail,此时该分片则无法写入数据。但由于源分片可以写入,此时可能存在两个不同分片上面存在二份不同版本的数据,同时读取的时候由于部分数据已经迁移,也会导致部分数据无法读取。
在迁移过程中会在源分片dump数据,然后在目标分片restore数据,会一定程度增加一定的写入量,但这个可以根据并发迁移key个数及加入一定迁移间隔来减少对业务影响。
Redis同步迁移有着简单,迁移不受写入速度的限制,但也存在一些无法规避的问题,特别是迁移大key影响业务及集群、lua无法迁移到新分片的问题,同步迁移都无法很好的支持,并且迁移过程中存在状态,也增加了一定迁移风险。在redis5.0中redis-cli直接集成了cluster相关的工具,比如slot均衡,slot扩容状态修复等,也简化了常用运维操作,但本身并没有解决其存在的问题,我们在实际的生产环境中改动redis源码来加强迁移稳定性,但还是无法消除同步迁移方法的不足。而最终解决只能通过异步迁移来解决同步迁移的问题,目前公有云最新的迁移已经切换到异步方案。可参考https://cloud.tencent.com/developer/article/1598700。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。