NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

Redis 实践系列丨 Codis 数据迁移原理与优化

  • 2019-10-23
  • 本文字数:3657 字

    阅读完需:约 12 分钟

Redis实践系列丨Codis数据迁移原理与优化

Codis 介绍

Codis 是一种 Redis 集群的实现方案,与 Redis 社区的 Redis cluster 类似,基于 slot 的分片机制构建一个更大的 Redis 节点集群,对于连接到 codis 的 Redis 客户端来说, 除了部分不支持的命令外,与连接开源的 Redis Server 没有明显的区别, 客户端代码基本需要进行修改,Codis-proxy 会根据访问的 key 进行 slot 的计算,然后转发请求到对应的 Redis-server,对于客户端来说,中间的 codis-proxy 是不可见的,因此根据客户业务的需要,可以使用 codis 构建大规模的 Redis 服务,或者仅仅是用于把请求分担多个 Redis-server 提高系统的吞吐量。


与业界著名的 twproxy 相比,除了支持 Redis 的转发,coids 还支持不停机的数据迁移,使用户可以在容量或者吞吐量要求有变化时,轻松进行节点的增减,本文主要对 codis 的迁移原理进行分析,并提出一个可行的优化点。


本文是基于 codis3.0 版本。


Codis 迁移实现原理

Codis-dashboard 在启动时,运行了 4 个后台线程(goroutine),包括后台 redis 状态同步、proxy 状态同步、slot 事件处理、sync 事件处理,并提供了 slot 相关的 RestFUL API 进行 slot 与 Redis-group 归属关系的定义、迁移的定义和触发。


如下结构定义一个 slot 与 Redis-group 的归属关系和迁移关系,GroupId 表示索引为 Id 的 slot 所属的 redis-group,而 Action 用于表示一次迁移,Action.TargetId 表示该 slot 要迁移的目标 redis-group 的 Id,Action.State 表示迁移的状态,主要有 Pending、Preparing、Prepared、Migrating、Finished 几种状态。


type SlotMapping struct {                Id      int `json:"id"`                GroupId int `json:"group_id"`                                Action struct {                                Index    int    `json:"index,omitempty"`                                State    string `json:"state,omitempty"`                                TargetId int    `json:"target_id,omitempty"`        UpdatedAt int64 `json:"updated_at,omitempty"`                } `json:"action"`}
复制代码


手动进行一次迁移过程,可以用如下命令来触发:


codis-admin --dashboard=ADDR -slot-action --create --sid=ID --gid=ID,比如把 slot 10 迁移到 group 5,则可以执行” codis-admin --dashboard=ADDR -slot-action --create --sid=10 --gid=5”


如果是把多个 slot 迁移到同一个 server,则可以使用如下命令,一次性来定义若干个迁移操作,codis-admin --slot-action --create-range --beg=ID --end=ID --gid=ID,比如把 slot 10~15 迁移到 group 5,则可以执行” codis-admin --dashboard=ADDR -slot-action –create–range --beg=10 –end=15 --gid=5”。


一次迁移的执行过程中,slot 的 Action 的状态会发生变化,过程为:



也可以触发 codis 进行 rebalance,命令为:codis-admin --dashboard=ADDR –rebalance --confirm,codis 会自动把 slot 往一些新加入的节点进行迁移,使各个节点负责的 slot 均衡。

Codis 迁移的测试

经测试,对于一个 64G 规模的集群(由 8 个节点组成,每个节点 8G),使用 redis-benchmark 写满数据,每个 key 的 value 长度为 32 字节,总共写入 341446298(3.4 亿)条数据,扩容到 128G,即对其中的 512 个 slot 进行迁移。


测试结果如下:


1 第一个 slot,从 06:49:31 开始到 07:47:23 结束,从总耗时 3472 seconds,也即 57 分 52 秒


2 后续的 7 个 slot,分别花费时间为 3463、3468、3472、3468、3472、3474、3470 seconds, 基本在 57~58 分之间,由于耗时非常长,没有记录后续的时间数据


从测试结果来看,迁移速度非常慢,每迁移一个 slot 需要花费基本 1 个小时,因此使用 codis 时,需要监控数据量,当数据不够时,需要进行及时的扩容,否则当空间不够时的故障处理和恢复时间可能影响线上业务。

Codis 迁移代码分析及瓶颈分析

从测试结果来看,迁移速度确实非常慢,极端情况下可能会影响线上业务,因此对迁移过程进行分析和优化就很有必要,下边对关键的实现代码 handleSlotRebalance 、StartDaemonRoutines、ProcessSlotAction 进行解读,并分析优化改进的地方。

01 handleSlotRebalance 实现分析

这个函数的主要逻辑分为三部分:


1)找到需要迁移的 slot;


2)为每个新节点分配 slot;


3)生成迁移操作;



上面的代码的逻辑是:


1)根据节点个数和 slot 槽数(固定的 1024),计算每个节点上应该负责的 slot 槽数,表示为 bound;


2)对每个 redis-group,找到需要迁移出去的 slot,表示为 pending;



生成迁移计划:


1)遍历所有的 redis-group,对于已有的 slot 小于应该负责的 slot 槽数的,就要迁移一些槽进来;


2)所有的 redis-group,决定需要迁移进来的 slot 列表,表示为 plans;



遍历迁移计划,使用 create actionRange 生成一系列的 slot action,并保存到 etcd,下一步就需要由后台线程去 etcd 中取出 slot 操作进行分别处理。

02 StartDaemonRoutines


这个代码是在 dashboard 启动时就启动的后台任务,每隔 5 秒钟触发一次 slot 操作,且只会运行一个 slot 操作任务。

03 ProcessSlotAction 实现分析

分为两步 Topom.SlotActionPrepare 和 Topom.processSlotAction。




从上面代码可以看出:


1 从 0 开始从所有的 slot 中,选择一个 Action.State 不为 ActionNothing 的 slot 进行处理,比如,如果为迁移某个 slot,那么该 slot 的 Action.State 就为 ActionPending,就可以被处理到


2 如果是多个 slot 需要处理,那么是从最小的 slot 开始,一个一个接一个的顺序处理,直到没有需要处理的 slot,然后继续每过 10 秒就处理一遍


下边再分析 processSlotAction 的实现:






可以看出:


1 循环调用底层的 redisp.MigrateSlot 函数,从源 slot 向目的 slot 做一次迁移操作


2 每次调用 redis 的 slotsmgrttagslot 命令进行一次迁移,只迁移一个 key;迁移完成后暂停一个时间,再继续进行后续迁移操作;应该是为了避免大量的迁移操作,影响了业务对 redis 的读写


3 直到迁移返回个位为 0,即表明迁移完成

04 瓶颈分析

从上面的分析可以得出:


1 多个 slot 的迁移,是一个一个 slot 串行处理的


2 对一个 slot 的迁移,是逐个 key 进行串行处理的,每迁移一次需要从 codis-dashboard 向 redis-server 发一次迁移命令,每发出一个迁移命令只迁移一个 key


这个设计的好处是,迁移过程对客户业务的影响很小,但是也有一些明显的缺点:


1 迁移效率较低,如果数据量很大,那么迁移时间会很长


2 如果扩容较晚,有些节点已经较为满了,那么很可能因为迁移较慢而还没有处理到这些 slot,从而导致对这些节点的写入失败


由于扩容一般会有一定的提前量,且会选在业务低峰期进行,因此可以对该迁移方案进行优化,可以在不对业务访问造成太大的影响的前提下提高迁移效率。

Codis 代码优化

根据上面对迁移实现的分析,优化的思路为:


1 对多个 slot 进行迁移,尽量进行并行化处理


2 调用 redis-server 进行迁移时,可以一次迁移多个 key

01 Slot 迁移并行化

从代码实现的分析,有 2 个点可以选择:


1 Topom.ProcessSlotAction 中,封装 SlotActionPrepare 和 processSlotAction,然后启动多个线程(goroutine),实现多个 slot 并行操作


2 Topom.StartDaemonRoutines 中,修改 ProcessSlotAction 的调用,启动多个线程(goroutine)


最终处理代码简单化的考虑,选择了方案 2,同时考虑到如下几点:


1 节点资源的限制,为避免耗费太多资源,限制最多 10 个线程并发


2 由于一般多个 slot 会映射到同一个 redis-server,而这样的多个 slot 进行并行化处理不会有提升效果,反而会影响到客户业务的访问,因此在并行时选择 slot 时,要选择不在同一个 redis-server 的 slot,使迁移真正的并行化


如下优化代码,启动至多 10 个线程进行 slot 事件的处理。



同时修改 SlotActionPrepare,选择一个状态为 Pending 且没有归属于同一个 redis-server 的 slot,进行处理。



02 Multikey 迁移

修改 redis-server 的迁移指令,支持一次迁移多个 key,为了灵活性,把迁移的个数从外部传入,代码比较显而易见,参考如下:



Codis 迁移优化测试结果

经过验证,对于一个 64G 规模的集群,使用 redis-benchmark 写满数据,每个 key 的 value 长度为 32 字节,总共写入 341446298(3.4 亿)条数据,扩容到 128G,即对其中的 512 个 slot 进行迁移。最终测试结果为:


1 从 10:05:41 开始,到 10:34:50 结束,最终花费时间为 29 分钟


2 每个 slot 的迁移时间平均为 25 秒。比如 slot-64,从 10:05:41,到 10:06:07,花费 26 秒;slot-195,从 10:05:42,到 10:06:08,花费 26 秒,slot-576,从 10:05:48,到 10:06:13,花费 25 秒


因此,经过优化后迁移性能有极大的提升。当然当前的配置也是考虑到了尽量不影响客户的业务访问,一次迁移的数据量并不是最大化的,在某些情况下,可以修改配置,一次迁移更多的 key,可以更加快速的完成迁移。


本文转载自公众号中间件小哥(ID:huawei_kevin)。


原文链接:


https://mp.weixin.qq.com/s/kfHx8GKN0ZHYXO456boCnQ


2019-10-23 10:272022

评论

发布
暂无评论
发现更多内容

中国移动NZONE 50 Pro 5G手机正式开售

Geek_2d6073

2022世界人工智能大会•腾讯“智变未来”论坛:聚焦产业升级,数字赋能未来

科技热闻

C#/VB.NET 设置Word文档段落缩进

在下毛毛雨

C# .net word文档 段落缩进

使用FeatureAbility模块启动其他Ability

白晓明

OpenHarmony应用开发 FeatureAbility

AOSWAP去中心化交易所系统开发功能介绍

开发微hkkf5566

在数字时代,如何选择企业的知识管理软件

Baklib

盘点适合中小企业的文档管理工具

Baklib

主流定时任务解决方案全横评

Serverless Devs

spring Linux

iptables与firewalld防火墙是怎么样工作的呢?

阿柠xn

防火墙 Linux Kenel 运维‘ 9月月更

「龙蜥开发者说」征稿啦!

OpenAnolis小助手

开源 征文 获奖 龙蜥开发者说 龙蜥技术

万物皆可集成系列:低代码如何不成为数据孤岛

葡萄城技术团队

低代码 数据孤岛 集成

Apache Kyuubi 在小米大数据平台的应用实践

网易数帆

Java hive Apache Spark Thrift kerberos

数据可视化系列教程|六大组件基础知识

云智慧AIOps社区

大前端 低代码 开源项目 数据可视化 可视化大屏

优秀的产品手册有助于留住你的客户

Baklib

干货|为什么说开源基金会的选择很关键?(下)

Orillusion

开源 WebGL 元宇宙 webgpu web3d

UI自动化助力业务效率提升

转转技术团队

UI自动化测试

SpringCloud 注册中心(Nacos)快速入门

nacos SpringCould 9月月更

转:工业软件上云很难吗?可以微创呀!

小江

工业软件云化

基于函数计算自定义运行时快速部署一个 springboot 项目

Serverless Devs

为什么我要迁移SpringBoot到函数计算

Serverless Devs

笔记 | DevOps推动科技管理敏捷转型(文末附PPT)

嘉为蓝鲸

DevOps 运维 敏捷 IT 精益

高性能对象池实现

C++后台开发

后端开发 高性能服务器 内存池 对象池 C++开发

中移链DDC-SDK技术对接全流程(一)

BSN研习社

20个既简单又实用的JavaScript小技巧

千锋IT教育

购买小间距LED显示屏前需要了解什么?

Dylan

LED显示屏 led显示屏厂家

MASA Framework 获取配置信息的方法

MASA技术团队

.net MASA Framewrok MASA

聆心智能入选OPPO“微笑提案”TOP10,让有温度的AI技术守护数亿人心理健康

硬科技星球

传统单节点网站的Serverless上云

Serverless Devs

堡垒机有录像吗?好用吗?有什么作用?

行云管家

网络安全 企业 数据安全 堡垒机 录像

搭建自己的以图搜图系统 (一):10 行代码搞定以图搜图

Zilliz

Python 机器学习 深度学习 相似度分析 以图搜图

浅谈 SAP ABAP 系统里的 ALV 输出方式实现

Jerry Wang

前端开发 SAP abap 9月月更 ALV

Redis实践系列丨Codis数据迁移原理与优化_文化 & 方法_夏光_InfoQ精选文章