zoukankan      html  css  js  c++  java
  • Redis Cluster 3.0搭建与使用

    Redis Cluster终于出了Stable,这让人很是激动,等Stable很久了,所以还是先玩玩。

    一. 集群简单概念。

    Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。

    Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。

    Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。

    Redis 集群提供了以下两个好处:

    • 将数据自动切分(split)到多个节点的能力。
    • 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。

    Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。

    集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:

    • 节点 A 负责处理 0 号至 5500 号哈希槽。
    • 节点 B 负责处理 5501 号至 11000 号哈希槽。
    • 节点 C 负责处理 11001 号至 16384 号哈希槽。

    这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。 比如说:

    • 如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。
    • 与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。

    因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。

    为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。

    在之前列举的节点 A 、B 、C 的例子中, 如果节点 B 下线了, 那么集群将无法正常运行, 因为集群找不到节点来处理 5501 号至 11000号的哈希槽。

    另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。

    不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作。

    Redis-cluster 架构图如下:

     

    架构细节:

    (1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.

    (2)节点的fail是通过集群中超过半数的节点检测失效时才生效.

    (3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

    (4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

     

    二. Redis Cluster搭建使用

    要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点,对应的redis节点的ip和端口对应关系如下(为了简单演示都在同一台机器上面)

    127.0.0.1:7000
    127.0.0.1:7001

    127.0.0.1:7002

    127.0.0.1:7003

    127.0.0.1:7004

    127.0.0.1:7005

    1. 下载最新版redis。

    wget http://download.redis.io/releases/redis-3.0.0.tar.gz

    2. 解压,安装

    tar xf redis-3.0.0.tar.gz                       
    cd redis-3.0.0
    make && make install

    3.创建存放多个实例的目录

    mkdir /data/cluster -p
    cd /data/cluster
    mkdir 7000 7001 7002 7003 7004 7005

    4.修改配置文件

    cp redis-3.0.0/redis.conf /data/cluster/7000/

    修改配置文件中下面选项

    port 7000

    daemonize yes

    cluster-enabled yes

    cluster-config-file nodes.conf

    cluster-node-timeout 5000

    appendonly yes

    文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为nodes.conf 。其他参数相信童鞋们都知道。节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。

    修改完成后,把修改完成的redis.conf复制到7001-7005目录下,并且端口修改成和文件夹对应。

    5.分别启动6个redis实例。

    复制代码
    cd /data/cluster/7000
    redis-server redis.conf
    cd /data/cluster/7001
    redis-server redis.conf
    cd /data/cluster/7002
    redis-server redis.conf
    cd /data/cluster/7003
    redis-server redis.conf
    cd /data/cluster/7004
    redis-server redis.conf
    cd /data/cluster/7005
    redis-server redis.conf
    复制代码

    查看进程否存在。

    复制代码
    [root@redis-server 7005]# ps -ef | grep redis
    root      4168     1  0 11:49 ?        00:00:00 redis-server *:7000 [cluster]
    root      4176     1  0 11:49 ?        00:00:00 redis-server *:7001 [cluster]
    root      4186     1  0 11:50 ?        00:00:00 redis-server *:7002 [cluster]
    root      4194     1  0 11:50 ?        00:00:00 redis-server *:7003 [cluster]
    root      4202     1  0 11:50 ?        00:00:00 redis-server *:7004 [cluster]
    root      4210     1  0 11:50 ?        00:00:00 redis-server *:7005 [cluster]
    root      4219  4075  0 11:50 pts/2    00:00:00 grep redis
    复制代码

    6.执行命令创建集群,首先安装依赖,否则创建集群失败。

    yum install ruby rubygems -y

    安装gem-redis

    下载地址:https://rubygems.org/gems/redis/versions/3.0.0

    gem install -l redis-3.0.0.gem  

    复制集群管理程序到/usr/local/bin

    cp redis-3.0.0/src/redis-trib.rb /usr/local/bin/redis-trib 

    创建集群:

    redis-trib create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

    命令的意义如下:

    • 给定 redis-trib.rb 程序的命令是 create , 这表示我们希望创建一个新的集群。
    • 选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
    • 之后跟着的其他参数则是实例的地址列表, 我们希望程序使用这些地址所指示的实例来创建新集群。

    简单来说, 以上命令的意思就是让 redis-trib 程序创建一个包含三个主节点和三个从节点的集群。

    接着, redis-trib 会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中:

    复制代码
    >>> Creating cluster
    Connecting to node 127.0.0.1:7000: OK
    Connecting to node 127.0.0.1:7001: OK
    Connecting to node 127.0.0.1:7002: OK
    Connecting to node 127.0.0.1:7003: OK
    Connecting to node 127.0.0.1:7004: OK
    Connecting to node 127.0.0.1:7005: OK
    >>> Performing hash slots allocation on 6 nodes...
    Using 3 masters:
    127.0.0.1:7000
    127.0.0.1:7001
    127.0.0.1:7002
    Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
    Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
    Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
    M: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
       slots:0-5460 (5461 slots) master
    M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
       slots:5461-10922 (5462 slots) master
    M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
       slots:10923-16383 (5461 slots) master
    S: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
       replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
    S: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
       replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
    S: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
       replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
    Can I set the above configuration? (type 'yes' to accept): 
    复制代码

    输入 yes 并按下回车确认之后, 集群就会将配置应用到各个节点, 并连接起(join)各个节点 —— 也即是, 让各个节点开始互相通讯:

    复制代码
    Can I set the above configuration? (type 'yes' to accept): yes
    >>> Nodes configuration updated
    >>> Assign a different config epoch to each node
    >>> Sending CLUSTER MEET messages to join the cluster
    Waiting for the cluster to join......
    >>> Performing Cluster Check (using node 127.0.0.1:7000)
    M: 2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000
       slots:0-5460 (5461 slots) master
    M: 2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001
       slots:5461-10922 (5462 slots) master
    M: 0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002
       slots:10923-16383 (5461 slots) master
    M: 37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003
       slots: (0 slots) master
       replicates 2774f156af482b4f76a5c0bda8ec561a8a1719c2
    M: e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004
       slots: (0 slots) master
       replicates 2d03b862083ee1b1785dba5db2987739cf3a80eb
    M: 9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005
       slots: (0 slots) master
       replicates 0456869a2c2359c3e06e065a09de86df2e3135ac
    [OK] All nodes agree about slots configuration.
    >>> Check for open slots...
    >>> Check slots coverage...
    [OK] All 16384 slots covered.
    复制代码

    一切正常输出以下信息:

    [OK] All nodes agree about slots configuration.
    >>> Check for open slots...
    >>> Check slots coverage...
    [OK] All 16384 slots covered.

    集群的客户端

    测试 Redis 集群比较简单的办法就是使用 redis-rb-cluster 或者 redis-cli , 接下来我们将使用 redis-cli 为例来进行演示:

    [root@redis-server ~]# redis-cli -c -p 7001
    127.0.0.1:7001> set name yayun
    OK
    127.0.0.1:7001> get name
    "yayun"
    127.0.0.1:7001> 

    我们可以看看还有哪些命令可以用:

    复制代码
    [root@redis-server ~]# redis-trib help
    Usage: redis-trib <command> <options> <arguments ...>
    
      set-timeout     host:port milliseconds
      add-node        new_host:new_port existing_host:existing_port
                      --master-id <arg>
                      --slave
      fix             host:port
      help            (show this help)
      del-node        host:port node_id
      import          host:port
                      --from <arg>
      check           host:port
      call            host:port command arg arg .. arg
      create          host1:port1 ... hostN:portN
                      --replicas <arg>
      reshard         host:port
                      --yes
                      --to <arg>
                      --from <arg>
                      --slots <arg>
    
    For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.
    [root@redis-server ~]# 
    复制代码

    可以看见有add-node,不用想了,肯定是添加节点。那么del-node就是删除节点。还有check肯定就是检查状态了。

    复制代码
    [root@redis-server ~]#  redis-cli -p 7000 cluster nodes 
    2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 master - 0 1428293673322 2 connected 5461-10922
    37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 slave 2774f156af482b4f76a5c0bda8ec561a8a1719c2 0 1428293672305 4 connected
    e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428293674340 5 connected
    0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428293670262 3 connected 10923-16383
    2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 myself,master - 0 0 1 connected 0-5460
    9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428293675362 6 connected
    [root@redis-server ~]# 
    复制代码

    可以看到7000-7002是master,7003-7005是slave。

    故障转移测试:

    127.0.0.1:7001> KEYS *
    1) "name"
    127.0.0.1:7001> get name
    "yayun"
    127.0.0.1:7001> 

    可以看见7001是正常的,并且获取到了key,value,现在kill掉7000实例,再进行查询。

    复制代码
    [root@redis-server ~]# ps -ef | grep 7000
    root      4168     1  0 11:49 ?        00:00:03 redis-server *:7000 [cluster]
    root      4385  4361  0 12:39 pts/3    00:00:00 grep 7000
    [root@redis-server ~]# kill 4168
    [root@redis-server ~]# ps -ef | grep 7000
    root      4387  4361  0 12:39 pts/3    00:00:00 grep 7000
    [root@redis-server ~]# redis-cli -c -p 7001
    127.0.0.1:7001> get name
    "yayun"
    127.0.0.1:7001> 
    复制代码

    可以正常获取到value,现在看看状态。

    复制代码
    [root@redis-server ~]# redis-cli -c -p 7001 cluster nodes
    2d03b862083ee1b1785dba5db2987739cf3a80eb 127.0.0.1:7001 myself,master - 0 0 2 connected 5461-10922
    0456869a2c2359c3e06e065a09de86df2e3135ac 127.0.0.1:7002 master - 0 1428295271619 3 connected 10923-16383
    37b251500385929d5c54a005809377681b95ca90 127.0.0.1:7003 master - 0 1428295270603 7 connected 0-5460
    e2e2e692c40fc34f700762d1fe3a8df94816a062 127.0.0.1:7004 slave 2d03b862083ee1b1785dba5db2987739cf3a80eb 0 1428295272642 5 connected
    2774f156af482b4f76a5c0bda8ec561a8a1719c2 127.0.0.1:7000 master,fail - 1428295159553 1428295157205 1 disconnected
    9923235f8f2b2587407350b1d8b887a7a59de8db 127.0.0.1:7005 slave 0456869a2c2359c3e06e065a09de86df2e3135ac 0 1428295269587 6 connected
    [root@redis-server ~]# 
    复制代码

    原来的7000端口实例已经显示fail,原来的7003是slave,现在自动提升为master。

    关于更多的在线添加节点,删除节点,以及对集群进行重新分片请参考官方文档。

    总结:

    redis-cluster是个好东西,只是stable才出来不久,肯定坑略多,而且现在使用的人比较少,前期了解学习一下是可以的,生产环境肯定要慎重考虑。且需要进行严格的测试。生产环境中redis的集群可以考虑使用Twitter开源的twemproxy,以及豌豆荚开源的codis,这两个项目都比较成熟,现在使用的公司很多。已经向业界朋友得到证实。后面也会写博客介绍twemproxy和codis。

    参考资料:

    http://redis.readthedocs.org/en/latest/topic/cluster-tutorial.html

    http://hot66hot.iteye.com/blog/2050676





  • 相关阅读:
    async
    subing用法
    vue中子组件调用父组件的方法
    Python—创建目录
    Python—访问限制
    Python—实例方法,实例数据(类属性,实例属性)
    Python—对象,类
    tail命令
    head命令
    pwd命令
  • 原文地址:https://www.cnblogs.com/caoxiaojian/p/5633435.html
Copyright © 2011-2022 走看看