redis cluster是去中心化,去中间件的,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。
Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,具体算法就是:CRC16(key) % 16384。
redis cluster 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。
首先去官方下载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"
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();
}
}
版本匹配:
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 对象时失败了。
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的日志就输出不了了
#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
说明:这里边的引用值不是redis-conf.properties文件中的,若想使用直接在里边修改即可。
自定义一个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
实现:
controller层:原来怎么写不动;
在service层:进行业务处理时,比如查询商品信息时先从redis中查找,若没有就从数据库中查找,查找后把数据对象放到redis缓存中,方便下次快速查找。