Redis|集群


1. Redis集群

1.1 概述

Redis3.0以后推出Redis cluster集群方案。

1.2 Reids cluster 架构图


架构细节

  1. 所有reids节点彼此互联(PING-PONG机制),内部使用二进制协议传输和带宽。
  2. 节点的fail是通过集群中超过半数的节点检测失效时才生效。
  3. 客户端与redis节点直连,不需要中间件proxy,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
  4. reids-cluster把所有的物理节点映射到[0-16383]slot上,cluster负责维护node<->slot<->value
  • 集群的整个数据库被分为了16384个槽(slot),数据库的每个键都属于这16384槽中的一个,集群中的每个节点可以处理0到16384个槽。
  • 当数据库的16384个槽都有节点处理时,集群处于上线状态(ok);相反的,如果数据库中有任何一个槽没得到处理,那么集群处于下线状态(fail) 。
  • 当在redis集群放置一个key-value时,redis先对key使用crcy16算法计算出一个结果,然后把这个结果对16384求余数,这样每一个key都会对应一个编号在0-16383之间的槽,redis会根据节点量大致均等的将槽映射到不同的节点中。

1.3 Redis cluster选举:容错

  1. 节点失效判断:选举过程是集群中所有master都参与,如果半数以上的master节点与master节点之间的通信超过(cluster-node-timeout),就认为当前master节点挂掉。
  2. 集群失效判断:什么时候整个集群不可用(cluster_state:fail)?
    • 如果集群任意master挂掉,且当前master没有slave,则集群进入fail状态。也可以理解为集群的[0-16383]slot映射不完全时进入fail状态。
    • 如果集群超过半数的master挂掉,无论是否有slave,集群进入fail状态。

2. redis cluster 安装

2.1 安装Ruby环境

reids cluster需要使用集群管理redis-trib.rb,它的执行相应依赖Ruby环境。

  • 第一步:安装ruby
yum   install ruby   
yum   install rubygems 
  • 第二步:安装ruby和redis的接口程序redis
gem install redis 

安装到这里就出现问题了,CentOS 7库中的ruby的版本支持到2.0.0,可gem 安装redis需要最低是2.2.2,下面采用rvm来更新ruby:

# 具体RVM安装命令地址:http://rvm.io/
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB   # 安装GPG秘钥
curl -sSL https://get.rvm.io | bash -s stable    # 安装RVM
find / -name rvm -print   # 查询支持rvm的所有版本
rvm list known
rvm install 2.4.5         # 安装2.4.5版本
rvm use 2.4.5             # 使用rvm 2.4.5
rvm use 2.4.5 --default   # 设置2.4.5 为默认版本
rvm remove 2.3.5          # 删除2.3.5这个版本
ruby --version            # 查看ruby当前版本
  • 第三步:复制redis-3.2.9/src/redis-trib.rb文件到/usr/local/redis-cluster目录
    前面我安装的redis单机版是redis-3.2.9
cd /usr/local/
mkdir redis_cluster  # 创建集群目录
cp   redis-3.2.9/src/redis-trib.rb /usr/local/redis_cluster/ -r  

2.2 安装RedisCluster

Redis集群最少需要三台主服务器,三台从服务器。
端口号分别为:7000~7001

  • 第一步:在local目录下创建 7000 7001 7002 7003 7004 7005,并且拷贝单机版安装时,生成的bin目录里面的所有文件,到7000 7001...文件中。
mkdir 7000 7001 7002  # 创建文件夹7000 70001 7002 ....
cp  /redis/bin/* /usr/local/7000/  -r
cp  /redis/bin/* /usr/local/7001/  -r
.......
  • 第二步:修改7000、7001....目录下的redis.conf配置文件,修改端口:和目录相对应7000、7001,打开Cluster-enable yes
  • 第三步:启动所有的实例
./redis-server redis.conf -p 7000
....
  • 第四步:创建redis集群
./redis-trib.rb create --replicas 1 172.19.165.143:7000 172.19.165.143:7001 172.19.165.143:7002 172.19.165.143:7003 172.19.165.143:7004 172.19.165.143:7005
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
172.19.165.143:7000
172.19.165.143:7001
172.19.165.143:7002
Adding replica 172.19.165.143:7003 to 172.19.165.143:7000
Adding replica 172.19.165.143:7004 to 172.19.165.143:7001
Adding replica 172.19.165.143:7005 to 172.19.165.143:7002
M: f649719d25e833a2cfa28877686334e4bee592b4 172.19.165.143:7000
   slots:0-5460 (5461 slots) master
M: 87cbfb735fc468193e3e8fd06b028f7079478f16 172.19.165.143:7001
   slots:5461-10922 (5462 slots) master
M: 5988d3d9be04d3b01b0b1028add0ee5b3ac793b8 172.19.165.143:7002
   slots:10923-16383 (5461 slots) master
S: a9bc31025e9188826a4fde74f1379d10ac8f96de 172.19.165.143:7003
   replicates f649719d25e833a2cfa28877686334e4bee592b4
S: 13bee88df50bf50a763d42135201c10e61762957 172.19.165.143:7004
   replicates 87cbfb735fc468193e3e8fd06b028f7079478f16
S: 5fe655116e404a989c9bce4a4aa206b30eb65905 172.19.165.143:7005
   replicates 5988d3d9be04d3b01b0b1028add0ee5b3ac793b8
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 172.19.165.143:7000)
M: f649719d25e833a2cfa28877686334e4bee592b4 172.19.165.143:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: a9bc31025e9188826a4fde74f1379d10ac8f96de 172.19.165.143:7003
   slots: (0 slots) slave
   replicates f649719d25e833a2cfa28877686334e4bee592b4
S: 13bee88df50bf50a763d42135201c10e61762957 172.19.165.143:7004
   slots: (0 slots) slave
   replicates 87cbfb735fc468193e3e8fd06b028f7079478f16
M: 5988d3d9be04d3b01b0b1028add0ee5b3ac793b8 172.19.165.143:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: 87cbfb735fc468193e3e8fd06b028f7079478f16 172.19.165.143:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 5fe655116e404a989c9bce4a4aa206b30eb65905 172.19.165.143:7005
   slots: (0 slots) slave
   replicates 5988d3d9be04d3b01b0b1028add0ee5b3ac793b8
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

创建过程中遇到问题参考这篇文章

3. 命令客户端连接集群

命令:

./redis-cli –h 127.0.0.1 –p 7000 –c
set key1 123

注意:-c 表示是以redis集群方式进行连接

./redis-cli -p 7001 -c
127.0.0.1:7001>get key1
-> Redirected to slot [9189] located at 127.0.0.1:7000
OK
127.0.0.1:7000>

4. 查看集群命令

查看集群状态

127.0.0.1:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_sent:926
cluster_stats_messages_received:926

查看集群中的节点:

127.0.0.1:7000> cluster nodes

5. 维护节点

集群创建成功后可以继续向集群中添加节点

5.1 添加主节点

  • 还是向前面一样先创建7007节点
  • 添加7007节点作为新节点
./redis-trib.rb add-node 127.0.0.1:7007 127.0.0.1:7000
  • 查看集群节点会发现7007已添加在集群中

5.2 槽分配(数据迁移)

添加完主节点需要对主节点进行hash槽分配,这样该主节才可以存储数据。
给刚添加的7007结点分配槽:

  • 第一步:连接上集群(连接集群中任意一个可用节点都可以)
./redis-trib.rb reshard 172.19.165.143 :7000
  • 第二步:输入要分配槽的数量
    出现提示:How many slots do you want to move (from 1 to 16384)?这个提示时,直接输入要分配的数量,如:3000。
  • 第三步:输入接收槽的结点id
    这里准备给7007分配槽,通过cluster nodes 查看7007节点id:15b809eadae88955e36bcdbb8144f61bbbaf38fb
    出现what is the receiving node ID?提示时输入上面的id。
  • 第四步:输入源节点id:all
    注意:输入源节点id,槽将从源节点中拿,分配后的槽在源节点中就不存在了,输入all从所有源节点中获取槽,输入done取消分配。
  • 第五部:输入yes开始移动槽到目标结点id

5.3 添加从节点

添加7008从结点,将7008作为7007主节点的从结点
命令:

./redis-trib.rb add-node --slave --master-id  主节点id   新节点的ip和端口   旧节点ip和端口(集群中任一节点都可以)

注意:如果原来该结点在集群中的配置信息已经生成到cluster-config-file指定的配置文件中(如果cluster-config-file没有指定则默认为nodes.conf),这时可能会报错:

[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解决方法是删除生成的配置文件nodes.conf,删除后再执行./redis-trib.rb add-node指令

5.4删除节点

./redis-trib.rb del-node 127.0.0.1:7005 节点id

删除已经占有hash槽的结点会失败,报错:

[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.

解决办法,把已经占用的槽分配出去

6. jedis连接集群

代码实现

@Test
public void testJedisCluster() throws Exception {
    //创建一连接,JedisCluster对象,在系统中是单例存在
    Set<HostAndPort> nodes = new HashSet<>();
    nodes.add(new HostAndPort("172.19.165.143", 7000));
    nodes.add(new HostAndPort("172.19.165.143", 7001));
    nodes.add(new HostAndPort("172.19.165.143", 7002));
    nodes.add(new HostAndPort("172.19.165.143", 7003));
    nodes.add(new HostAndPort("172.19.165.143", 7004));
    nodes.add(new HostAndPort("172.19.165.143", 7005));
    JedisCluster cluster = new JedisCluster(nodes);
    //执行JedisCluster对象中的方法,方法和redis一一对应。
    cluster.set("cluster-test", "my jedis cluster test");
    String result = cluster.get("cluster-test");
    System.out.println(result);
    //程序结束时需要关闭JedisCluster对象
    cluster.close();
}


Spring
配置applicationContext.xml

<!-- 连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 最大连接数 -->
    <property name="maxTotal" value="30" />
    <!-- 最大空闲连接数 -->
    <property name="maxIdle" value="10" />
    <!-- 每次释放连接的最大数目 -->
    <property name="numTestsPerEvictionRun" value="1024" />
    <!-- 释放连接的扫描间隔(毫秒) -->
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <!-- 连接最小空闲时间 -->
    <property name="minEvictableIdleTimeMillis" value="1800000" />
    <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
    <property name="softMinEvictableIdleTimeMillis" value="10000" />
    <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
    <property name="maxWaitMillis" value="1500" />
    <!-- 在获取连接的时候检查有效性, 默认false -->
    <property name="testOnBorrow" value="true" />
    <!-- 在空闲时检查有效性, 默认false -->
    <property name="testWhileIdle" value="true" />
    <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
    <property name="blockWhenExhausted" value="false" />
</bean>
<!-- redis集群 -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
    <constructor-arg index="0">
        <set>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7000"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7001"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7002"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7003"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7004"></constructor-arg>
            </bean>
            <bean class="redis.clients.jedis.HostAndPort">
                <constructor-arg index="0" value="172.19.165.143"></constructor-arg>
                <constructor-arg index="1" value="7005"></constructor-arg>
            </bean>
        </set>
    </constructor-arg>
    <constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>
</bean>

学习
Redis3.2.1集群搭建

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容