您的位置:首页 > 数据库 > Redis

redis 集群介绍就,安装详细步骤,和spring 整合

2017-01-02 11:54 756 查看


redis相关网站:

官网: http://redis.io     中文网:http://www.redis.cn/  
 文档:http://redisdoc.com/

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  集群安装

参考  http://blog.csdn.net/xu470438000/article/details/42971091
参考  http://www.cnblogs.com/wuxl360/p/5920330.html

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

 

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

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

2:上传服务器,解压,编译
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
3:创建集群需要的目录
mkdir -p /usr.local/cluster

cd /usr.local/cluster

mkdir 7000

mkdir 7001

mkdir 7002

mkdir 7003

mkdir 7004

mkdir 7005

 
4:修改配置文件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参数,分别改为对应的文件夹的名称

 
5:分别启动这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

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

 
6:执行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
6.1执行上面的命令的时候会报错,因为是执行的ruby的脚本,需要ruby的环境

错误内容:/usr/bin/env: ruby: No such file or directory

所以需要安装ruby的环境,这里推荐使用yum install ruby安装
yum install ruby
 

6.2然后再执行第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.3再次执行第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.4 再次执行第6步的命令,正常执行

 


输入yes,然后配置完成。

 


至此redis集群即搭建成功!

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

redis-cli -c -p 7000

简单说一下原理

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

Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做
哈希槽 (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集群

参考 http://blog.csdn.net/u013322876/article/details/50595833

下面是具体的代码实现

 

1.maven依赖

 

 

Java代码  


<dependency>  

    <groupId>redis.clients</groupId>  

    <artifactId>jedis</artifactId>  

    <version>2.7.2</version>  

</dependency>  

 

 

2.applicationContext.xml中的配置

 

 

Java代码  


   <!-- jedis cluster config -->  

   <bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" >  

        <property name="maxWaitMillis" value="-1" />  

        <property name="maxTotal" value="1000" />  

        <property name="minIdle" value="8" />  

        <property name="maxIdle" value="100" />  

</bean>  

  

<bean id="jedisCluster" class="com.besttone.subscribe.util.JedisClusterFactory">  

    <property name="addressConfig">  

        <value>classpath:redis-config.properties</value>  

    </property>  

    <property name="addressKeyPrefix" value="address" />    

      

    <property name="timeout" value="300000" />  

    <property name="maxRedirections" value="6" />  

    <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" />  

</bean>  

 

 

3.JedisClusterFactory实现类

 

Java代码  


public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {  

  

    private Resource addressConfig;  

    private String addressKeyPrefix ;  

  

    private JedisCluster jedisCluster;  

    private Integer timeout;  

    private Integer maxRedirections;  

    private GenericObjectPoolConfig genericObjectPoolConfig;  

      

    private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");  

  

    @Override  

    public JedisCluster getObject() throws Exception {  

        return jedisCluster;  

    }  

  

    @Override  

    public Class<? extends JedisCluster> getObjectType() {  

        return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);  

    }  

  

    @Override  

    public boolean isSingleton() {  

        return true;  

    }  

  

  

  

    private Set<HostAndPort> parseHostAndPort() throws Exception {  

        try {  

            Properties prop = new Properties();  

            prop.load(this.addressConfig.getInputStream());  

  

            Set<HostAndPort> haps = new HashSet<HostAndPort>();  

            for (Object key : prop.keySet()) {  

  

                if (!((String) key).startsWith(addressKeyPrefix)) {  

                    continue;  

                }  

  

                String val = (String) prop.get(key);  

  

                boolean isIpPort = p.matcher(val).matches();  

  

                if (!isIpPort) {  

                    throw new IllegalArgumentException("ip 或 port 不合法");  

                }  

                String[] ipAndPort = val.split(":");  

  

                HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));  

                haps.add(hap);  

            }  

  

            return haps;  

        } catch (IllegalArgumentException ex) {  

            throw ex;  

        } catch (Exception ex) {  

            throw new Exception("解析 jedis 配置文件失败", ex);  

        }  

    }  

      

    @Override  

    public void afterPropertiesSet() throws Exception {  

        Set<HostAndPort> haps = this.parseHostAndPort();  

          

        jedisCluster = new JedisCluster(haps, timeout, maxRedirections,genericObjectPoolConfig);  

          

    }  

    public void setAddressConfig(Resource addressConfig) {  

        this.addressConfig = addressConfig;  

    }  

  

    public void setTimeout(int timeout) {  

        this.timeout = timeout;  

    }  

  

    public void setMaxRedirections(int maxRedirections) {  

        this.maxRedirections = maxRedirections;  

    }  

  

    public void setAddressKeyPrefix(String addressKeyPrefix) {  

        this.addressKeyPrefix = addressKeyPrefix;  

    }  

  

    public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {  

        this.genericObjectPoolConfig = genericObjectPoolConfig;  

    }  

  

}  

 

4.redis-config.properties文件

 

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

 

Java代码  


address1=192.168.30.139:7000  

address2=192.168.30.139:7001  

address3=192.168.30.139:7002  

address4=192.168.30.139:7003  

address5=192.168.30.139:7004  

address6=192.168.30.139:7005  

 

5.项目目录图

 

 



 

 

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

 

 



 

 

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

 

 

7.三个master节点中的数据

 



 

 8.三个slave节点中的数据

 



 

 

 

实践过程中碰到的问题:

 

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

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

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

Java代码  


./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时,报错:

 

Java代码  


(error) MOVED 6257 192.168.30.141:7001  

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

Java代码  


redis-cli -c -h 192.168.30.141 -p 7000  

 

 ok,以上满足使用,结束!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: