1.Redis集群介绍


什么是Redis集群?

Redis集群是一个实现分布式并且允许单点故障的Redis高级版本。

Redis集群没有最重要或者说中心节点,这个版本最主要的一个目标是设计一个线性可伸缩(可随意增删节点?)的功能。

Redis集群为了数据的一致性可能牺牲部分允许单点故障的功能,所以当网络故障和节点发生故障时这个系统会尽力去保证数据的一致性和有效性。(这里我们认为节点故障是网络故障的一种特殊情况)

为了解决单点故障的问题,我们同时需要masters 和 slaves。 即使主节点(master)和从节点(slave)在功能上是一致的,甚至说他们部署在同一台服务器上,从节点也仅用以替代故障的主节点。 实际上应该说 如果对从节点没有read-after-write(写并立即读取数据 以免在数据同步过程中无法获取数据)的需求,那么从节点仅接受只读操作。

已实现子集

Redis集群会把所有的单一key存储在非分布式版本的Redis中。对于复合操作比如求并集求交集之类则未实现。

在将来,有可能会增加一种为“Computation Node”的新类型节点。这种节点主要用来处理在集群中multi-key的只读操作,但是对于multi-key的只读操作不会以集群传输到Computation Node节点再进行计算的方式实现。

Redis集群版本将不再像独立版本一样支持多数据库,在集群版本中只有database 0,并且SELECT命令是不可用的。

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。


参考  http://www.redis.cn/topics/cluster-tutorial.html


2.redis  集群安装

Redis集群部署文档(centos6系统)

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

 

:下载redis。官网下载3.0.0版本,之前2.几的版本不支持集群模式

下载地址:https://github.com/antirez/redis/archive/3.0.0-rc2.tar.gz

:上传服务器,解压,编译

tar -zxvf redis-3.0.0-rc2.tar.gz 

mv redis-3.0.0-rc2.tar.gz redis3.0

cd /usr/local/redis3.0

make

make install

:创建集群需要的目录

mkdir -p /usr.local/cluster

cd /usr.local/cluster

mkdir 7000

mkdir 7001

mkdir 7002

mkdir 7003

mkdir 7004

mkdir 7005

 

:修改配置文件redis.conf

cp /usr/local/redis3.0/redis.conf  /usr.local/cluster

vi redis.conf

修改配置文件中的下面选项

port  7000                                        //端口7000,7002,7003        
bind 本机ip                                       //默认ip为127.0.0.1 需要改为其他节点机器可访问的ip 否则创建集群时无法访问对应的端口,无法创建集群
daemonize    yes                               //redis后台运行
pidfile  /var/run/redis_7000.pid          //pidfile文件对应7000,7001,7002
cluster-enabled  yes                           //开启集群  把注释#去掉
cluster-config-file  nodes_7000.conf   //集群的配置  配置文件首次启动自动生成 7000,7001,7002
cluster-node-timeout  15000                //请求超时  默认15秒,可自行设置
appendonly  yes                           //aof日志开启  有需要就开启,它会每次写操作都记录一条日志



修改完redis.conf配置文件中的这些配置项之后把这个配置文件分别拷贝到7000/7001/7002/7003/7004/7005目录下面

cp /usr/local/cluster/redis.conf /usr/local/cluster/7000

cp /usr/local/cluster/redis.conf /usr/local/cluster/7001

cp /usr/local/cluster/redis.conf /usr/local/cluster/7002

cp /usr/local/cluster/redis.conf /usr/local/cluster/7003

cp /usr/local/cluster/redis.conf /usr/local/cluster/7004

cp /usr/local/cluster/redis.conf /usr/local/cluster/7005

 

注意:拷贝完成之后要修改7001/7002/7003/7004/7005目录下面redis.conf文件中的port参数,分别改为对应的文件夹的名称

 

:分别启动这6个redis实例

cd /usr/local/cluster/7000

redis-server redis.conf

cd /usr/local/cluster/7001

redis-server redis.conf

cd /usr/local/cluster/7002

redis-server redis.conf

cd /usr/local/cluster/7003

redis-server redis.conf

cd /usr/local/cluster/7004

redis-server redis.conf

cd /usr/local/cluster/7005

redis-server redis.conf

 

 

启动之后使用命令查看redis的启动情况ps -ef|grep redis

如下图显示则说明启动成功

 

:执行redis的创建集群命令创建集群

cd /usr/local/redis3.0/src

./redis-trib.rb  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

执行上面的命令的时候会报错,因为是执行的ruby的脚本,需要ruby的环境

/usr/bin/env: ruby: No such file or directory

的环境,这里推荐使用yum install ruby安装

yum install ruby

 

然后再执行第6步的创建集群命令,还会报错,提示缺少rubygems组件,使用yum安装

 

错误内容:

./redis-trib.rb:24:in `require': no such file to load -- rubygems (LoadError)

from ./redis-trib.rb:24

yum install rubygems

再次执行第6步的命令,还会报错,提示不能加载redis,是因为缺少redis和ruby的接口,使用gem 安装

错误内容:

/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- redis (LoadError)

from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'

from ./redis-trib.rb:25

 

gem install redis

 

再次执行第6步的命令,正常执行

 

spring redis 配置数据index spring 配置redis集群_Redis

,然后配置完成。

 

spring redis 配置数据index spring 配置redis集群_Redis_02

集群即搭建成功!

:使用redis-cli命令进入集群环境

redis-cli -c -p 7000






简单说一下原理

redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。

哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到set 和 get 的时候,直接跳转到了7000端口的节点。

Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。只有当一个master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。

3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。



3.spring 整合redis集群

下面是具体的代码实现

 

1.maven依赖

1. <dependency>  
2.     <groupId>redis.clients</groupId>  
3.     <artifactId>jedis</artifactId>  
4. 2.7.2</version>  
5. </dependency>

2.applicationContext.xml中的配置


1.    <!-- jedis cluster config -->  
2. "genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig"
3. "maxWaitMillis" value="-1"
4. "maxTotal" value="1000"
5. "minIdle" value="8"
6. "maxIdle" value="100"
7. </bean>  
8.   
9. <bean id="jedisCluster" class="com.besttone.subscribe.util.JedisClusterFactory">  
10. "addressConfig">  
11.         <value>classpath:redis-config.properties</value>  
12.     </property>  
13. "addressKeyPrefix" value="address"
14.       
15. "timeout" value="300000"
16. "maxRedirections" value="6"
17. "genericObjectPoolConfig" ref="genericObjectPoolConfig"
18. </bean>

 

3.JedisClusterFactory实现类

 

    1. public class JedisClusterFactory implements
    2.   
    3. private
    4. private
    5.   
    6. private
    7. private
    8. private
    9. private
    10.       
    11. private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");  
    12.   
    13. @Override
    14. public JedisCluster getObject() throws
    15. return
    16.     }  
    17.   
    18. @Override
    19. public Class<? extends
    20. return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);  
    21.     }  
    22.   
    23. @Override
    24. public boolean
    25. return true;  
    26.     }  
    27.   
    28.   
    29.   
    30. private Set<HostAndPort> parseHostAndPort() throws
    31. try
    32. new
    33. this.addressConfig.getInputStream());  
    34.   
    35. new
    36. for
    37.   
    38. if
    39. continue;  
    40.                 }  
    41.   
    42.                 String val = (String) prop.get(key);  
    43.   
    44. boolean
    45.   
    46. if
    47. throw new IllegalArgumentException("ip 或 port 不合法");  
    48.                 }  
    49. ":");  
    50.   
    51. new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));  
    52.                 haps.add(hap);  
    53.             }  
    54.   
    55. return
    56. catch
    57. throw
    58. catch
    59. throw new Exception("解析 jedis 配置文件失败", ex);  
    60.         }  
    61.     }  
    62.       
    63. @Override
    64. public void afterPropertiesSet() throws
    65. this.parseHostAndPort();  
    66.           
    67. new
    68.           
    69.     }  
    70. public void
    71. this.addressConfig = addressConfig;  
    72.     }  
    73.   
    74. public void setTimeout(int
    75. this.timeout = timeout;  
    76.     }  
    77.   
    78. public void setMaxRedirections(int
    79. this.maxRedirections = maxRedirections;  
    80.     }  
    81.   
    82. public void
    83. this.addressKeyPrefix = addressKeyPrefix;  
    84.     }  
    85.   
    86. public void
    87. this.genericObjectPoolConfig = genericObjectPoolConfig;  
    88.     }  
    89.   
    90. }

     

    4.redis-config.properties文件

     

       这是一个集群环境,六个节点(不同端口),三个master ,三个slaver

      1. address1=192.168.30.139:7000
      2. address2=192.168.30.139:7001
      3. address3=192.168.30.139:7002
      4. address4=192.168.30.139:7003
      5. address5=192.168.30.139:7004
      6. address6=192.168.30.139:7005



       

      5.项目目录图

       

       

      spring redis 配置数据index spring 配置redis集群_Redis_03


       

       

      6.代码中使用(此代码为从redis中获取相关信息)

       

       

      spring redis 配置数据index spring 配置redis集群_redis_04


       

       

      ok,运行之后,会发现redis会根据不同的key,把它们放入到不同的节点中,如下图

       

       

      7.三个master节点中的数据

       

      spring redis 配置数据index spring 配置redis集群_redis_05


       

       8.三个slave节点中的数据

       

      spring redis 配置数据index spring 配置redis集群_ruby_06


       

       

       

      实践过程中碰到的问题:

       

      1.在一切准备好了之后,在操作redis的时候,却报错误:Too many Cluster redirections

      由于,我是windows开发环境,在本机开了一个虚拟机,然后在虚拟机中搭建的linux集群环境,本机的ip和虚拟机中的ip不相同,所以报这个错误,

      解决方法:在redis集群搭建过程中,在为每个节点分hash槽的时候,执行如下代码(其中,xxx为集群环境中的ip):


      1. ./redis-trib.rb create --replicas 1 xxx.xxx.xxx.xxx:7000  xxx.xxx.xxx.xxx:7001 xxx.xxx.xxx.xxx:7002 xxx.xxx.xxx.xxx:7003 xxx.xxx.xxx.xxx:7004 xxx.xxx.xxx.xxx:7005./redis-trib.rb 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


      2.在一切搭建好后,我们使用redis-cli登陆,当命令:set msg XXX时,报错:

       


      1. (error) MOVED 6257 192.168.30.141:7001


       解决:在使用客户端登陆时:加上-c参数,即:


      1. redis-cli -c -h 192.168.30.141 -p 7000


       

       ok,以上满足使用,结束!!