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进行迁移。

测试结果如下:

从测试结果来看,迁移速度非常慢,每迁移一个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。

从上面代码可以看出:

下边再分析processSlotAction的实现:

可以看出:

04

瓶颈分析

从上面的分析可以得出:

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

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

Codis代码优化

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

1、Slot迁移并行化

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

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

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

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

2、Multikey迁移

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

Codis迁移优化测试结果

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

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

Redis实践系列丨Codis数据迁移原理与优化的更多相关文章

  1. Bash实践:抽样检测数据迁移至Redis集群后的数据一致性

    熟悉了一段时间的Bash编程,因此借此任务操作一把bash编程,主要涉及到Redis单节点与Redis集群的操作 1. 任务背景 近日有个任务需要将历史的Redis(主从节点)中的数据迁移至Redis ...

  2. ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定

    本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...

  3. redis集群升级,数据迁移及校验

    本次由于安全漏洞原因,需要降redis3升级为redis6,涉及到数据迁移及校验等,用阿里redis-shake迁移工具迁移,并用阿里RedisFullCheck工具进行数据比对 一.新redis安装 ...

  4. infobright系列二:数据迁移

    安装之后把之前infobright的数据迁移到新安装的infobright上. 1:挺掉相关的服务 2:scp 把旧数据拷到新安装的infobright上 3:修改/etc/my-ib.cnf的数据目 ...

  5. 一种HBase表数据迁移方法的优化

    1.背景调研: 目前存在的hbase数据迁移主要分如下几类: 根据上图,可以看出: 其实主要分为两种方式:(1)hadoop层:因为hbase底层是基于hdfs存储的,所以可以通过把hdfs上的数据拷 ...

  6. sqoop关系型数据迁移原理以及map端内存为何不会爆掉窥探

    序:map客户端使用jdbc向数据库发送查询语句,将会拿到所有数据到map的客户端,安装jdbc的原理,数据全部缓存在内存中,但是内存没有出现爆掉情况,这是因为1.3以后,对jdbc进行了优化,改进j ...

  7. 一步一步学EF系列三【数据迁移】

    我们每篇的内容都不多,所以希望在学习的过程中最后能亲自敲一下代码 这样更有利于掌握. 我们现在接着上篇的例子,我们现在给随便的表增加一个字段 CreateTime 创建日期 运行一下 看看会怎么样 修 ...

  8. redis 练习 a的数据库数据迁移到b数据库

    思路 1.从a redis中获取所有的key 2.判断key的类型 3.根据key的类型,判断使用的是set/hset类型 4.set到b redis中(写入到b redis中)

  9. EF Code First 数据迁移配置

    这里我想讲清楚code first 数据迁移的两种模式,还有开发环境和生产环境数据迁移的最佳实践. 1.1 数据迁移综述 EF Code first 虽然已经有了几种不同的数据库初始化策略,但是大部分 ...

随机推荐

  1. 洛谷 P1708 天然气井 题解

    https://www.luogu.org/problemnew/show/P1708 这道题还是比较好的. 读完题目我们先想想如何计算某个天然气井($x_1,y_1$)和中转站($a_1,b_1$) ...

  2. 远程桌面mstsc关闭连接栏

    在进行mstsc远程桌面连接电脑或者虚拟机的时候,总是会出现一个连接栏.虽然点左边的图钉可以自动隐藏,但是每次鼠标滑到上面的时候,还是会冒出来,这个就有点烦心了. 查了下资料,解决了这个问题. 关闭步 ...

  3. bash实现自动补全

    yum install -y bash-completion source /usr/share/bash-completion/bash_completion 执行后yum拥有选项自动补全功能 对于 ...

  4. Go:文件操作

    一.打开文件和关闭文件 os包File结构体的两个方法: func Open(name string) (file *File, err error) Open打开一个文件用于读取.如果操作成功,返回 ...

  5. Django:调用css、image、js

    1.在项目的manage.py同级目录创建static.templates 2.编辑settings.py,在最后加入 STATIC_URL = '/static/' HERE = os.path.d ...

  6. 【HDU 6153】A Secret (KMP)

    Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,whi ...

  7. 【转】关于大型网站技术演进的思考(二十)--网站静态化处理—web前端优化—中(12)

    Web前端很多优化原则都是从如何提升网络通讯效率的角度提出的,但是这些原则使用的时候还是有很多陷阱在里面,如果我们不能深入理解这些优化原则背后所隐藏的技术原理,很有可能掉进这些陷阱里,最终没有达到最佳 ...

  8. LA 3890 半平面交

    二分查询答案,判断每一个新形成的向量合在一块能否形成半平面交 #include <iostream> #include <cstdio> #include <cstrin ...

  9. usort 使用(转载)

    private function arrCmp($a,$b){ if($a['day_time'] == $b['day_time']){  return 0; } return($a['day_ti ...

  10. RabbitMQ最佳实践

    在使用消息机制时,我们通常需要考虑以下几个问题: 消息不能丢失 保证消息一定能投递到目的地 保证业务处理和消息发送/消费的一致性 本文以RabbitMQ为例,讨论如何解决以上问题. 消息持久化 如果希 ...