ssm+redis cluster集群

1、简介

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

Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384

redis cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。


2、搭建集群

首先去官方下载Redis,我这里下载的是3.0.5版本 
1.解压

[root@spg redis-claster]# tar -zxvf redis-3.0.5.tar.gz

2.安装

[root@spg redis-claster]#cd redis-3.0.5

[root@spg redis-3.0.5]#make && make install

3.将redis-trib.rb 复制到/usr/local/bin

[root@spg redis-3.0.5]#cp src/redis-trib.rb /usr/local/bin

4.开始集群搭建,首先修改配置文件。

[root@spg redis-3.0.5]#vi redis.conf

修改如下几处:

port 7000

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

5、新建6个节点(注意:Redis Cluster要求至少6个节点,3主3备,否则构建集群会报错):

#这里文件名就按端口号命名,方便区分。

 [root@spg redis-claster]# mkdir 7000 

[root@spg redis-claster]# mkdir 7001 

[root@spg redis-claster]# mkdir 7002 

[root@spg redis-claster]# mkdir 7003

 [root@spg redis-claster]# mkdir 7004 

[root@spg redis-claster]# mkdir 7005

 

6、redis.conf 分别拷贝到这6个文件夹中,并修改其中对应的端口号。 
分别启动6个Redis。

[root@spg redis-claster]# cd 7000 

[root@spg 7000]# redis-server redis.conf & 

#其他几个启动略...

 

7、查看进程查看各redis是否已经正常启动

[root@spg redis-claster]# ps -ef | grep redis

 

8、6个Redis加入集群

需要用到的命令就是redis-trib.rb,这是官方的一个用ruby写的一个操作redis cluster的命令,所以,你的机器上需要安装ruby。我们先试一下这个命令:

#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

 

因为我们要新建集群, 所以这里使用create命令. –replicas 1 参数表示为每个主节点创建一个从节点. 其他参数是实例的地址集合。

由于我机子上没安装ruby,所以,会报错:

/usr/bin/env: ruby: 没有那个文件或目录

命令安装ruby:

[root@spg 7003]# yum install ruby ruby-devel rubygems rpm-build

完成后继续执行,结果还是报错:

[root@spg 7003]# 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

/usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- redis (LoadError)    from /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require'    from /usr/local/bin/redis-trib.rb:25:in `

'

这是因为ruby和redis的连接没安装好:

[root@spg 7003]# gem install redis 

Fetching: redis-3.2.2.gem (100%)

Successfully installed redis-3.2.2 

Parsing documentation for redis-3.2.2 

Installing ri documentation for redis-3.2.2 1 gem installed

安装完后再创建集群

[root@spg redis-claster]# 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 

>>> 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

 

9、检查集群各节点状态:

[root@spg redis-3.0.5]# redis-trib.rb check 127.0.0.1:7000

Connecting to node 127.0.0.1:7000: OK 

Connecting to node 127.0.0.1:7002: OK 

Connecting to node 127.0.0.1:7004: OK 

Connecting to node 127.0.0.1:7005: OK 

Connecting to node 127.0.0.1:7001: OK 

Connecting to node 127.0.0.1:7003: OK 

>>> Performing Cluster Check (using node 127.0.0.1:7000)

,,,,,,,,

 

10、测试集群链接状况

redis-cli是redis默认的客户端工具,启动时加上`-c`参数,就可以连接到集群。 连接任意一个节点端口:

[root@spg 7006]# redis-cli -c -p 7003 

127.0.0.1:7003>set my_name wind

-> Redirected to slot [12803] located at 127.0.0.1:7002 OK

127.0.0.1:7002>get my_name

"wind"

2、java连接测试

import java.util.HashSet; 
import java.util.Set; 
import redis.clients.jedis.HostAndPort; 
import redis.clients.jedis.JedisCluster; 
/** * Jedis集群测试 * *
 @author Switch 
* @data 2017年2月11日 
* @version V1.0 
*/ 
public class JedisClusterTest { 
public static void main(String[] args) { 
// 创建并填充节点信息 
Set nodes = new HashSet<>(); 
nodes.add(new HostAndPort("192.168.37.131", 7001)); 
nodes.add(new HostAndPort("192.168.37.131", 7002)); 
nodes.add(new HostAndPort("192.168.37.131", 7003)); 
nodes.add(new HostAndPort("192.168.37.131", 7004)); 
nodes.add(new HostAndPort("192.168.37.131", 7005)); 
nodes.add(new HostAndPort("192.168.37.131", 7006)); 
// 创建JedisCluster对象 
JedisCluster jedisCluster = new JedisCluster(nodes); 
// 使用jedisCluster操作redis 
String key = "jedisCluster"; 
String setResult = jedisCluster.set(key, "hello redis!"); System.out.println(setResult); 
String getResult = jedisCluster.get(key); System.out.println(getResult); 
// 关闭jedisCluster(程序执行完后才能关闭,内部封装了连接池) jedisCluster.close(); 
} 
}

2、SSM + redis cluster项目实战

1)加入jar

版本匹配:

redis.client  2.9.0 ---- spring-data-redis  1.7.1.RELEASE 

   redis.client 2.9.0 -----spring-data-redis   1.7.2.RELEASE

由于版本不匹配,遇到的错误如下:

1. ClassNotFoundException  : redis/client/util/geoUtils   

说这个类找不到。

  2. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisTemplate' defined in class path resource [applicationContext.xml]

   说创建 redisTemplate bean 对象时失败了。

 

2maven pom.xml 文件

      redis.clients
      jedis
      2.9.0
  
    

        org.springframework.data
        spring-data-redis
        1.7.1.RELEASE
    


			
				org.slf4j
				slf4j-api
			
		 //这里为什么要排除slf日志?因为我的框架使用的是log4j,如果有slf,那么log4j的日志将不生效。所以要排除。因为spring-data-redis依赖slf。这 样的缺点spring-data-redis的日志就输出不了了
2)配置redis-conf.properties

#JedisPoolConfig的参数
#最大连接数
redis.pool.maxTotal=30
#最大空闲时间
redis.pool.maxIdle=10
#每次最大连接数
redis.pool.numTestsPerEvictionRun=1024
#释放扫描的扫描间隔
redis.pool.timeBetweenEvictionRunsMillis=30000
#连接的最小空闲时间
redis.pool.minEvictableIdleTimeMillis=1800000
#连接控歘按时间多久后释放,当空闲时间>该值且空闲连接>最大空闲连接数时直接释放
redis.pool.softMinEvictableIdleTimeMillis=10000
#获得链接时的最大等待毫秒数,小于0:阻塞不确定时间,默认-1
redis.pool.maxWaitMillis=1500
#在获得链接的时候检查有效性,默认false
redis.pool.testOnBorrow=true
#在空闲时检查有效性,默认false
redis.pool.testWhileIdle=true
#连接耗尽时是否阻塞,false报异常,true阻塞超时,默认true
redis.pool.blockWhenExhausted=false
#RedisClusterConfiguration配置
redis.maxRedirects=3
#主机和端口号
redis.host=192.168.48.131
redis.port=6379
redis.host2=192.168.48.131
redis.port2=6380
redis.host3=192.168.48.131
redis.port3=6381
redis.host4=192.168.48.131
redis.port4=6382
redis.host5=192.168.48.131
redis.port5=6383
redis.host6=192.168.48.131
redis.port6=6384

3) 配置redis 配置文件 我把它单独提取出来放在一个配置文件(spring-data-redis-cluster.xml)中,然后import spring ApplicationContext.xml 文件中

说明:这里边的引用值不是redis-conf.properties文件中的,若想使用直接在里边修改即可。















        
        
            
                
                    
                    
                

                
                    
                    
                
                
                    
                    
                
                
                    
                    
                
                 
                    
                    
                
                 
                    
                    
                
            
        
     
    
    
        
        
        
    
    
    

    
    
        
        
        
        
        
    
4ApplicationContent.xml 配置文件中 导入以上配置


5)redisTemplate  的应用

自定义一个redisClient类来管理操作 redis 的存取操作

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
public class RedisClusterClient {
        // 由于在Spring ApplicationContext.xml 配置文件中导入了 redis的配置文件,也就间接的将   这个Bean托管给了Spring bean容器来管理所以 只要我使用注解就可以把这个模板类对象引用过来。
       @Autowired
       private RedisTemplate clusterRedisTemplate;
     
       //添加数据
        public void put(Object key, Object value) {
            if(null == value) {
                return;
            }
     
            if(value instanceof String) {
                if(StringUtils.isEmpty(value.toString())) {
                    return;
                }
            }
     
            // TODO Auto-generated method stub
            final String keyf = key + "";
            final Object valuef = value;
            final long liveTime = 86400;
     
            clusterRedisTemplate.execute(new RedisCallback() {
                public Long doInRedis(RedisConnection connection)
                        throws DataAccessException {
                    byte[] keyb = keyf.getBytes();
                    byte[] valueb = toByteArray(valuef);
                    connection.set(keyb, valueb);
                    if (liveTime > 0) {
                        connection.expire(keyb, liveTime);
                    }
                    return 1L;
                }
            });
        }
     
         // 获取数据
        public Object get(Object key) {
            final String keyf = (String) key;
            Object object;
            object = clusterRedisTemplate.execute(new RedisCallback() {
                public Object doInRedis(RedisConnection connection)
                        throws DataAccessException {
     
                    byte[] key = keyf.getBytes();
                    byte[] value = connection.get(key);
                    if (value == null) {
                        return null;
                    }
                    return toObject(value);
     
                }
            });
     
            return object;
        }
     
        /**
         * 描述 : . 
         *

         * <使用方法说明>          *

         *          * @param bytes          * @return          */         private Object toObject(byte[] bytes) {             Object obj = null;             try {                 ByteArrayInputStream bis = new ByteArrayInputStream(bytes);                 ObjectInputStream ois = new ObjectInputStream(bis);                 obj = ois.readObject();                 ois.close();                 bis.close();             } catch (IOException ex) {                 ex.printStackTrace();             } catch (ClassNotFoundException ex) {                 ex.printStackTrace();             }             return obj;         }               private byte[] toByteArray(Object obj) {             byte[] bytes = null;             ByteArrayOutputStream bos = new ByteArrayOutputStream();             try {                 ObjectOutputStream oos = new ObjectOutputStream(bos);                 oos.writeObject(obj);                 oos.flush();                 bytes = bos.toByteArray();                 oos.close();                 bos.close();             } catch (IOException ex) {                 ex.printStackTrace();             }             return bytes;         }      }实现:

controller层:原来怎么写不动;

在service层:进行业务处理时,比如查询商品信息时先从redis中查找,若没有就从数据库中查找,查找后把数据对象放到redis缓存中,方便下次快速查找。



你可能感兴趣的:(Redis)