Redis集群之:Codis介绍,可用集群部署与代码开发实战

1. 概述

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有显著区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务。

Codis的主要特性如下:

  1. 通过分片机制,使Redis集群可容纳几乎无限的数据
  2. 在无需重启集群的情况下,对节点进行扩容与自动均衡
  3. Group至少要包含一个Master与多个Slave,然后通过主从与哨兵机制实现集群的高可用
  4. 可视化的集群管理能力。

1.1 分片机制

Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。

每一个 slot 都会有一个且必须有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。数据的迁移也是以slot为单位的。

1.2 部署架构

Redis集群之:Codis介绍,可用集群部署与代码开发实战_第1张图片

Codis 3.x 由以下组件组成:

  • Codis Server:基于 redis-3.2.8 分支开发。增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。具体的修改可以参考文档 redis 的修改。

  • Codis Proxy:客户端连接的 Redis 代理服务, 实现了 Redis 协议。 除部分命令不支持以外(不支持的命令列表),表现的和原生的 Redis 没有区别(就像 Twemproxy)。

    • 对于同一个业务集群而言,可以同时部署多个 codis-proxy 实例;
    • 不同 codis-proxy 之间由 codis-dashboard 保证状态同步。
  • Codis Dashboard:集群管理工具,支持 codis-proxy、codis-server 的添加、删除,以及据迁移等操作。在集群状态发生改变时,codis-dashboard 维护集群下所有 codis-proxy 的状态的一致性。

    • 对于同一个业务集群而言,同一个时刻 codis-dashboard 只能有 0个或者1个;
    • 所有对集群的修改都必须通过 codis-dashboard 完成。
  • Codis Admin:集群管理的命令行工具。

    • 可用于控制 codis-proxy、codis-dashboard 状态以及访问外部存储。
  • Codis FE:集群管理界面。

    • 多个集群实例共享可以共享同一个前端展示页面;
    • 通过配置文件管理后端 codis-dashboard 列表,配置文件可自动更新。
  • Storage:为集群状态提供外部存储。

    • 提供 Namespace 概念,不同集群的会按照不同 product name 进行组织;
    • 目前仅提供了 Zookeeper、Etcd、Fs 三种实现,但是提供了抽象的 interface 可自行扩展

2. 部署实战

基于二进制的代码进行演示

  • codis 3.2.2:https://github.com/CodisLabs/codis/releases/download/3.2.2/codis3.2.2-go1.9.2-linux.tar.gz

2.1 单机部署

在一台机器上部署所有的服务,部署机器为:testcluster1v.zzt.ddddd.cn

所有操作都在codis3.2.2-go1.9.2-linux目录下执行

2.1.1 Zookeeper

在本机配置好zookeeper,本文不对该流程进行描述

2.1.2 Proxy

将一下配置保存proxy.toml:

jodis_name = "zookeeper"                          
jodis_addr = "testcluster1v.zzt.ddddd.cn:2181" 
jodis_timeout= "20s"                              
jodis_compatible = true                           

启动Proxy:$./codis-proxy --zookeeper=testcluster1v.zzt.ddddd.cn:2181 --config=proxy.toml

2.1.3 Dashboard

启动dashboard:$././codis-dashboard --zookeeper=testcluster1v.zzt.ddddd.cn:2181

2.1.4 Server

首先将创建redis配置文件,redis.conf,内容如下:

bind 0.0.0.0
protected-mode no

启动server:./codis-server redis.conf

为了演示master-slave效果,可以在启动个实例:./codis-server --port 6380

2.1.5 codis-fe

启动fe:$ ./codis-fe --ncpu=4 --log=fe.log --log-level=
WARN --zookeeper=testcluster1v.zzt.ddddd.cn:2181 --listen=:8080

2.1.6 web操作

服务都启动完之后,打开http://testcluster1v.zzt.ddddd.cn:8080/#codis-demo

此时,按照下面的顺序进行操作

  1. 创建group:在NEW Group按钮后的框里,输入1,然后回车
  2. 在group 1里添加两个redis实例
  3. 点击“Reblance all slots”

最后group的效果如下:
Redis集群之:Codis介绍,可用集群部署与代码开发实战_第2张图片

2.2 集群部署

通过4台机器模拟集群的搭建

机器 角色
testcluster1v.zzt.ddddd.cn Zookeeper(只用单节点),fe,dashboard,server,proxy,sentinel
testcluster2v.zzt.ddddd.cn server,proxy,sentinel
testcluster3v.zzt.ddddd.cn server,proxy,sentinel
testcluster4v.zzt.ddddd.cn server,proxy,sentinel

2.2.1 codis-fe,codis-dashboard,codis-fe

codis-fe,codis-dashboard,codis-fe的配置与单机相同,且只需要在一个机器上运行

2.2.2 codis-server,codis-proxy

codis-server,codis-proxy的配置也与单机配置相同,只是运行在多台机器上

最终分组配置以及代理的配置信息如下:

Redis集群之:Codis介绍,可用集群部署与代码开发实战_第3张图片

2.2.3 哨兵(sentinel)

只要是进行高可用的架构部署,那么就必须保证多节点,在Redis里面使用了主从模式可以实现多节点配置,但是传统的主从模式的设计有一个缺陷:一旦Master主机出现了问题之后,两台Slave主机将无法提供正常的工作支持,例如:slave主机为只读主机,而且如果要想继续提供支持,那么你至少应该通过剩余的几台slave里面去推选出一个新的master,并且最为重要的是,这个新的master还必须能够被用户的程序找到,哨兵机制就可以达到该目的。

基于Codis配置哨兵非常简单,只需简单的配置,就可以完成哨兵的配置。
配置步骤如下:

  1. 在4台机器上分别创建sentinel.conf文件,内容如下:
port 26379       
bind 0.0.0.0     
protected-mode no
  1. 在4台机器上,分别启动哨兵服务:$./redis-sentinel sentinel.conf
  2. 在管理页面添加4个哨兵
    Redis集群之:Codis介绍,可用集群部署与代码开发实战_第4张图片
  3. 点击SYNC按钮,自动生成哨兵配置,此时查看sentinel.conf会发现,已经根据之前分组以及主从的信息,生成了完整的配置文件
  4. 配置完哨兵后,随便关掉一个分组的MASTER节点,会发现SLAVE节点,很快就会切换为MASTER,稍后之前的MASTER启动后将会成为SLAVE

3. Jodis代码操作

对 Java 用户来说,可以使用基于 Jedis 的实现 Jodis ,来实现 proxy 层的 HA:

它会通过监控 zookeeper 上的注册信息来实时获得当前可用的 proxy 列表,既可以保证高可用性;
也可以通过轮流请求所有的proxy实现负载均衡。

Maven配置:

 
            io.codis.jodis
            jodis
            0.5.1

Java代码:

package com.eric.redis;

import redis.clients.jedis.Jedis;
import io.codis.jodis.RoundRobinJedisPool;
import io.codis.jodis.JedisResourcePool;

public class JodisSample {
    public static void main(String[] args) {
        JedisResourcePool jedisPool = RoundRobinJedisPool.create().
                curatorClient("testcluster1v.zzt.ddddd.cn:2181", 30000).zkProxyDir("/zk/codis/db_codis-demo/proxy").build();
        try (Jedis jedis = jedisPool.getResource()) {
            for (int i = 0; i < 100; i++) {
                jedis.set("ikey"+i,"value"+i);
            }
            jedis.set("foo", "bar");
            String value = jedis.get("foo");
            System.out.println(value);
        }
    }
}

你可能感兴趣的:(NoSQL)