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,可以更加快速的完成迁移。

最新文章

  1. c模拟c++ const 转换
  2. GridView的七种数据绑定列的类型
  3. Shiro权限验证代码记录,正确找到shiro框架在什么地方做了权限识别
  4. android 设置textview跑马灯效果
  5. 【OpenStack】OpenStack系列10之Horizon详解
  6. 关于LR中的EXTRARES
  7. 用Google Analytics跟踪JavaScript Errors (译)
  8. oracle中exp,imp的使用详解
  9. JSP写入MySQL数据库中出现乱码问题笔记
  10. Sublime Text3 Package Control和Emmet插件安装方法
  11. JDBC中PreparedStatement和Statement的区别
  12. 浅谈TCP优化(转)
  13. input text中不能显示空格后的内容
  14. Webstorm 提示 Can't use Subversion command line client
  15. Java四大名著下载大全(中文+英文)
  16. .Net Core应用框架Util介绍(二)
  17. PhoenixFD插件流体模拟——UI布局【Resimulation】详解
  18. hadoop的块
  19. 【转】从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler
  20. git简单运用

热门文章

  1. POJ-1200-Crazy Search(字符串Hash)
  2. 二手GTX650
  3. LeetCode728. 自除数
  4. linux中的vi命令
  5. PS学习笔记(02)
  6. 尼姆博弈扩展形式(一): 限定每次取物的上限。NYOJ-135,难度5~~~
  7. [Go]通道(channel)的基本操作
  8. Go变量定义学习
  9. 在oracle下我们如何正确的执行数据库恢复
  10. kafka直连方式消费多个topic