Proxy-Style Redis集群设计

Proxy-Style Redis集群设计

概述:

为了实现Redis作为内存数据库时的横向扩展和高可用,大致有如下三种方案.

  1. 客户端分片

    在客户端维护路由规则进而,这种方式的性能最好,几乎没有额外开销,实现最简单.但是缩容和扩容需要手动调整分片规则,运维难度相当大.

  2. Redis-Cluster 去中心化的Redis集群方案

    这是官方的集群方案,集群将所有Key映射到一定数量的Slot(虚拟)中.集群成员节点通过P2P方式交换信息.理论的访问性能几乎和单机一致(需要测试),但是其实现复杂度非常高(通信协议,内部状态变换).由于其复杂性,通常也难以运维.虽然是官方方案,但没有大规模成功实施的案例.

  3. Proxy-Style

    以Twemproxy和Codis为代表的集群方案,通过独立的Proxy节点对Redis访问进行路由,管理分片,Proxy逻辑和存储逻辑隔离.由于Proxy额外的开销,单机性能通常低于第一种方案,但可通过增加Proxy节点改善.由于Proxy的独立性,状态简单,运维相对也比较容易.


综合对比:

方案 实现难度 性能 运维难度
客户端分片
Redis-Cluster
Proxy-Style

本文主要介绍Proxy-Style的问题及相应的设计方法,该设计来自于Codis

Proxy-Style Design

  1. 基本Proxy设计图,Proxy可以通过一致性哈希或普通的哈希算法对请求进行路由.

    基本Proxy设计

    Proxy与集群中所有Redis服务器建立连接,通过对key进行hash,将Redis访问路由到每台服务器上.
    这个结构Proxy是单点的,另外单机Proxy会成为性能瓶颈.

  2. 通过数据中心(zookeeper)维护Proxy状态,客户端通数据中心获取当前可用的Proxy节点列表.

    zk-center

    这种方案客户端可以通过Zookeeper获取Proxy的在线状态,对所有在线Proxy进行轮询.可以通过水平增加Proxy进行负载均衡,扩展Proxy的处理能力.当然也可以使用其他的HA负载均衡方案实现,例如在前面加上Haproxy做反向代理.
    此时Redis节点本身是无备份的,一旦崩溃,节点上的数据也就丢失了,这样无法作为可靠的内存数据库使用.

  3. 存储以主从结构组成一个服务器组

    这里写图片描述

    每个RedisGroup中可以由一个Mater和多个Slave组成,组内通过SYNC命令进行复制.

    到此为止集群还要解决另外一个问题,Redis缩容/扩容.节点数量的变更,需要对所有的key进行重哈希,分配到所有的节点上.操作需要对整个库加锁,这在线上环境是无法接受的.如果使用一致性哈希,虽然可以避免全局重哈希,但不可避免的会丢失一部分数据.如果集群作为缓存服务器,这不是问题,但如果作为内存数据库使用,数据丢失是不能接受的.

  4. Pre-Sharding 提前将Key分配到若干虚拟Slot中,以Slot为单位进行数据迁移.

    slot-support

    为了保持Proxy无状态,Slot和RedisGroup的对应关系状态信息保存在数据中心(Zookeeper)中.这样对key的哈希路由只跟Slot有关,在扩容/缩容时并不会改变Slot的数量,故无须进行重哈希.只需要对部分Slot进行迁移,更新Slot-RedisGroup的对应关系即可.迁移过程由于以Slot为单位,只需要对单个Slot加锁保证过程中的一致性.

    这里写图片描述

    根据这个上述设计,使用Zookeeper(zk)保存状态数据,具体实现并不一定需要依赖zk,也可以自行设计方案.这里的zk表示的是一个能保证高可用的数据中心,对所有的Proxy提供一致的视图.例如Codis3.0中,通过dashboard保存状态数据,通过rpc与Proxy通信.

    Pre-Sharding的方案写一个Key的时序图:

Created with Raphaël 2.1.0 Client Client Proxy Proxy zk zk RedisGroupN RedisGroupN set ( k , v ) 根据key的哈希 将其分配到某个slot中 slot=hash(k)%1024 slot在哪个RedisGroup ? RedisGroupId=n set( k,v )

Codis实现简介

设计是想法的说明书,最终还是需要具体实现的.下面以Codis实现简单分析一下上述设计在实现中的难题.

  1. 为了让Proxy对Client透明,Codis-Proxy实现Redis的通信协议,对客户端的视图与访问Redis基本无异(有部分指令不支持,例如一些多key操作)
  2. Codis在为了支持PreSharding,修改Redis源码(Codis-server),增加操作Slot相关的命令,以支持数据热迁移.
  3. Codis2.0依赖zk/etcd做数据中心保存状.(Slot-Group对应关系,Slot的迁移状态,等等.)
    Codis3.0进一步对Redis代码进行修改,在Redis上增加保存Slot信息的数据结构.并通过改进的Dashboard API与Proxy通信传递状态信息.
  4. Codis2中使用codis-config命令来操作集群,例如添加删除RedisGroup,执行Slot迁移,等等.配合Dashboard展示集群状态,手动操作主从切换.
    Codis3中废弃了codis-config命令,统一使用Dashboard管理集群.

参考资料

  1. Codis 的设计与实现 Part 1
  2. Codis 的设计与实现 Part 2
  3. Codis 的设计与实现 Part 3
  4. Codis2 使用文档
  5. Codis3 使用文档
  6. 高效运维最佳实践(03):Redis集群技术及Codis实践

猜你喜欢

转载自blog.csdn.net/u012631045/article/details/50586984