写点什么

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:272609

评论

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

eosio.token 智能合约介绍

BSN研习社

区块链 智能合约 EOS

由亚马逊云科技 Graviton4 驱动的全新内存优化型实例 Amazon EC2 实例(R8g),现已开放预览

亚马逊云科技 (Amazon Web Services)

Java’ Amazon EC2

从3天到3小时,“文思助手”让行业专业写作“文思泉涌”

飞桨PaddlePaddle

百度 paddle 百度飞桨 文心大模型‘ 飞桨星河社区

DevOps是什么?只看这篇文章就够了!

DevOps 华为云

面试官:Sentinel是如何实现限流的?

王磊

Java 面试

如何给极狐GitLab 配置 webhook,自动触发 Pipeline?

极狐GitLab

本地缓存Ehcache的应用实践 | 京东云技术团队

京东科技开发者

属于你的Chat GPT来了

派大星

ChatGPT Open AI

什么是企业级应用软件?对企业有什么应用意义?常见的企业级应用软件有哪些?

天津汇柏科技有限公司

创业 企业级应用 企业级应用程序开发 企业级应用软件

云小课|Runc容器逃逸漏洞(CVE-2024-21626)安全风险通告

华为云开发者联盟

云计算 后端 华为云 华为云开发者联盟 华为云云小课

软件架构一致性 —— 被忽视的研发成本

阿里技术

软件架构 研发 研发成本

【大数据技术攻关专题】「Apache-Flink零基础入门」手把手+零基础带你玩转大数据流式处理引擎Flink(基础加强+运行原理)

码界西柚

大数据 flink flink 实战 技术指南 2024年第三十一篇文章

一文搞懂设计模式—单例模式

Java随想录

Java 设计模式

一文详解应用安全防护ESAPI

华为云开发者联盟

安全 开发 华为云 华为云开发者联盟 应用安全防护

探索大模型的端应用与形态

百度开发者中心

人工智能 深度学习 大模型

大促削峰实战:评价QPS降低85%的背后逻辑

京东科技开发者

预训练对话大模型深度解读

百度开发者中心

自然语言处理 深度学习 大模型训练 大模型

年度大模型榜单揭晓,智谱AI GLM-4在上海人工智能实验室司南榜单中位居国内榜首

极客天地

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