前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis同步迁移数据

Redis同步迁移数据

原创
作者头像
juviliu
修改2020-04-01 18:09:59
1.4K1
修改2020-04-01 18:09:59
举报
文章被收录于专栏:redis集群

概述

        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迁移流程

迁移一个slot大体可简化为3步,流程如下图所示:

Redis迁移流程
Redis迁移流程

Redis迁移流程

  1. 标记迁移状态

标记迁移目标分片的待迁移slot为IMPORTING状态,然后再标记源分片待迁移slot为MIGRATING状态。这里标记状态一定不能置换,否则会导致在该slot上的源分片及目标分片都无法写入新数据。

  1. 迁移slot中的所有数据

依次获取slot中的key,然后将这些key迁移到目标分片,直到所有的key迁移完成。

  1. 标记slot归属权

标记迁移完的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。

  1. 连接目标分片,标记迁移目标分片的待迁移slot为IMPORTING状态。(cluster setslot 4470 importing 32fe95bc56611ced95553ba90bc7add1e3bef3ad),在标志后,目标分片信息为:c6e02ef185bd9d641b8a50fd82781f0aeb5eb618 9.134.240.85:1637@11637 myself,master - 0 1581228243000 5 connected 10923-16383 [4470-<-32fe95bc56611ced95553ba90bc7add1e3bef3ad]
  2. 连接源分片,标记源分片待迁移slot为MIGRATING状态。(cluster setslot 4470 migrating c6e02ef185bd9d641b8a50fd82781f0aeb5eb618)标志后目标分片信息为:32fe95bc56611ced95553ba90bc7add1e3bef3ad 9.134.240.17:2777@12777 myself,master - 0 1581228385000 4 connected 0-5460 [4470->-c6e02ef185bd9d641b8a50fd82781f0aeb5eb618]
  3. 模拟数据写入(操作流程可跳过这个步骤,这步用于解释方案存在的问题)
    1. 写入或者修改未迁移的数据testmigrate,此时返回成功,并无影响。
    2. 写入已经迁移完的key或者新的key,此时会返回(error) ASK 4470 9.134.240.85:1637错误,这个时候我们需要连接到迁移的目标分片,然后先执行asking,再写入已经迁移完的key或者新的key,这个也是同步扩容的关键点,它能保证数据一定可以迁移成功,与业务的写入速度无直接关系,这个属于同步方案的最大优点。但这点上缺陷也比较明显,如果用户通过mset或者mget这类命令写入或者查询多个key的时候,如果这些key在源分片不能完全找到,它会返回ASK错误,此时需要转向目标分片执行写入和查询,但执行时并不能保证所有的key已经迁移到目标分片,这个时候会返回(error) TRYAGAIN Multiple keys request during rehashing of slot错误,这样就导致key无法正常写入。这种情况可以通过client或者proxy将mset/mget在写入redis之前进行拆分,这样相当于set/get命令,此时便不会出现无法写入的情况,但性能会有影响。
  4. 批量从源分片获取KEY ,(CLUSTER GETKEYSINSLOT 4470 10),命令一次读取10个key,但由于迁移前只写入了一个key,这里只会返回一个key。testmigrate
  5. 迁移上步获取这些KEY (migrate 9.134.240.85 1637 "" 0 10000 auth password keys testmigrate),这个命令会迁移上步获取 key。
  6. 重复前面两步至到迁移完后
  7. 连接目标分片,标记迁移完的slot归属权为迁移的目标分片(cluster setslot 4470 node c6e02ef185bd9d641b8a50fd82781f0aeb5eb618)。
  8. 连接源分片,然后再标记源分片迁移完的slot为目标分片。(cluster setslot 4470 node c6e02ef185bd9d641b8a50fd82781f0aeb5eb618)

同步迁移存在问题及解决办法

  1. 迁移时长限制

Redis请求处理为单线程,所有命令都只能串形执行,如果在我们迁移过程中有一个大key,那么在迁移过程用户及集群gossip请求处理都会阻塞,在我们的迁移测试中,迁移600MB的list,4千万个整形key,整个迁移时间为7.42s。那在这个7.42s的过程中,用户是无法有请求响应。由于我们分片cluster-node-timeout为默认的15s,所以在整个迁移过程中如果超过15s分片会被判死,从而导致主从切换。为了减少对业务的影响,同时避免主从切换,那就需要控制迁移时间。为了控制每次Key的搬迁时长,我们引入了迁移评估流程,就是在迁移前,检查是否满足迁移条件,总共需要检查的有两个点,一是每个key的搬移时长不能超过指定时长,我们目前定的是3s,那转换为key的大小,大体为200MB,所以我们在迁移过程中是限制单Key不能超过200MB,

  1. 迁移容量评估

除迁移时长外,还一个就是迁移容量,迁移过程中一定要保证目标分片一定有足够的容量容下带迁移的key。Redis获取key的容量使用的是MEMORY USAGE key samples count方法,但这个方法需要借助管控去查询所有待迁移的key,并且分slot统计需要迁移的容量,这种方式最主要的问题就是速度太慢。为了减少评估时间,我们在Redis中新增了评估命令,该命令返回slot的容量及其中最大Key的容量来解决迁移评估。如果在一个缩容流程中,它的数据迁移流程如下:

扩缩容流程
扩缩容流程

扩缩容流程

  1. 在两个分片中同一个slot都存在部分key时的访问问题。

在上节3b步骤中提过其存在的问题,这里不在重复。除了一些批量执行命令外,在lua执行中也可能出现执行报错。

  1. 迁移一个slot到全新分片时lua无法迁移的问题。

由于在新分片无lua相关脚本 ,如果通过EVALSHA执行则会报错。 但在实际中,一般比较少的情况下只使用evalsha命令,因为lua脚本一旦变了,那么脚本的sha也会改变。

  1. 迁移过程中主从切换导致集群无法写入及多份数据的问题

源分片发生主从切换,此时集群在目标分片不认可源分片对迁移分片的归属权,从而导致该分片认为集群fail,此时该分片则无法写入数据。但由于源分片可以写入,此时可能存在两个不同分片上面存在二份不同版本的数据,同时读取的时候由于部分数据已经迁移,也会导致部分数据无法读取。

  1. 对业务存在很小的性能影响

在迁移过程中会在源分片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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • slot迁移流程
  • 模拟搬迁过程
  • 同步迁移存在问题及解决办法
  • 总结
相关产品与服务
云数据库 Redis®
腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档