redis-cluster架构图
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽
(2)节点的fail是通过投票机制即集群中超过半数的节点检测失效时才生效
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
Redis集群的搭建
第一步:安装redis
- 下载:打开redis官方网站,推荐下载稳定版本(stable)
- 解压
tar zxvf redis-3.2.5.tar.gz
- 复制:推荐放到usr/local目录下
sudo mv -r redis-3.2.3/* /usr/local/redis/ 进入redis目录 cd /usr/local/redis/
- 生成
sudo make
- 测试
sudo make test 这段运行时间会较长,可以略过
- 安装:将redis的命令安装到/usr/bin/目录
sudo make install
第二步:搭建伪Redis集群的准备工作
- 使用命令生成可执行文件到指定目录下(因为需要6个可执行的redis-server)
sudo make install PREFIX=/usr/local/redis-cluster
- 将/usr/local/redis目录下的redis.conf文件copy一份到刚生成的目录中,并修改该配置文件
和
- 书写脚本运行所有6个redis
cd redis01
./redis-server redis.conf
cd ..
第三步:安装ruby和相关的包
- 安装
sudo apt-get install ruby
- 安装redis-3.0.0.gem
sudo gem install redis-3.0.0.gem
- 将/usr/local/redis/src目录下的redis-trib.rb文件copy到任意位置
- 执行命令运行起来redis集群
./redis-trib.rb create --replicas 1 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 127.0.0.1:7006
真正建立redis集群时,更改为运行redis主机们的ip地址(要关闭防火墙)
第四步:使用集群
redis-cli -p 7002 -c # -c表示操作的是集群
Java操作redis
1、导入Jedis包
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2、操作redis
1)直接操作版
@Test
public void JedisClient(){
// 1.创建一个Jedis对象。需要指定服务端的ip及端口
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 2.使用Jedis对象操作数据库
jedis.set("k1","v1");
String k1 = jedis.get("k1");
System.out.println(k1);
// 3.关闭Jedis对象
jedis.close();
}
2)连接池版
@Test
public void JedisPool(){
// 1.创建一个JedisPool对象。需要指定服务端的ip及端口
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
// 2.从JedisPool中获得Jedis对象
Jedis jedis = jedisPool.getResource();
// 3.使用Jedis操作redis服务器
jedis.set("k2","v2");
String k1 = jedis.get("k2");
System.out.println(k1);
// 4.操作完毕后关闭jedis对象,连接池回收资源
jedis.close();
// 5.关闭JedisPool对象
jedisPool.close();
}
3)连接集群版
@Test
// 集群默认使用的就是连接池,所以不用我们来配了
public void JedisCluster(){
// 1.使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));
nodes.add(new HostAndPort("127.0.0.1", 7003));
nodes.add(new HostAndPort("127.0.0.1", 7004));
nodes.add(new HostAndPort("127.0.0.1", 7005));
nodes.add(new HostAndPort("127.0.0.1", 7006));
// 2.直接使用JedisCluster对象操作redis。在系统中单例存在。
JedisCluster jedisCluster = new JedisCluster(nodes);
jedisCluster.set("k3", "v3");
String result = jedisCluster.get("k3");
System.out.println(result);
// 3.系统关闭前,关闭JedisCluster对象。
jedisCluster.close();
}
项目整合
缓存数据库查询数据,当进行增删改方法时,删除缓存;由于我们平时用单机版的就行了,项目发布时在使用集群版,所以我们可以采用面向接口编程;缓存是在service中配置的


1 public interface JedisClient { 2 3 String set(String key, String value); 4 String get(String key); 5 Boolean exists(String key); 6 Long expire(String key, int seconds); 7 Long ttl(String key); 8 Long incr(String key); 9 Long hset(String key, String field, String value); 10 String hget(String key, String field); 11 Long hdel(String key, String... field); 12 Boolean hexists(String key, String field); 13 List<String> hvals(String key); 14 Long del(String key); 15 }


1 package cn.e3mall.common.jedis; 2 3 import java.util.List; 4 5 import redis.clients.jedis.Jedis; 6 import redis.clients.jedis.JedisPool; 7 8 public class JedisClientPool implements JedisClient { 9 10 private JedisPool jedisPool; 11 12 public JedisPool getJedisPool() { 13 return jedisPool; 14 } 15 16 public void setJedisPool(JedisPool jedisPool) { 17 this.jedisPool = jedisPool; 18 } 19 20 @Override 21 public String set(String key, String value) { 22 Jedis jedis = jedisPool.getResource(); 23 String result = jedis.set(key, value); 24 jedis.close(); 25 return result; 26 } 27 28 @Override 29 public String get(String key) { 30 Jedis jedis = jedisPool.getResource(); 31 String result = jedis.get(key); 32 jedis.close(); 33 return result; 34 } 35 36 @Override 37 public Boolean exists(String key) { 38 Jedis jedis = jedisPool.getResource(); 39 Boolean result = jedis.exists(key); 40 jedis.close(); 41 return result; 42 } 43 44 @Override 45 public Long expire(String key, int seconds) { 46 Jedis jedis = jedisPool.getResource(); 47 Long result = jedis.expire(key, seconds); 48 jedis.close(); 49 return result; 50 } 51 52 @Override 53 public Long ttl(String key) { 54 Jedis jedis = jedisPool.getResource(); 55 Long result = jedis.ttl(key); 56 jedis.close(); 57 return result; 58 } 59 60 @Override 61 public Long incr(String key) { 62 Jedis jedis = jedisPool.getResource(); 63 Long result = jedis.incr(key); 64 jedis.close(); 65 return result; 66 } 67 68 @Override 69 public Long hset(String key, String field, String value) { 70 Jedis jedis = jedisPool.getResource(); 71 Long result = jedis.hset(key, field, value); 72 jedis.close(); 73 return result; 74 } 75 76 @Override 77 public String hget(String key, String field) { 78 Jedis jedis = jedisPool.getResource(); 79 String result = jedis.hget(key, field); 80 jedis.close(); 81 return result; 82 } 83 84 @Override 85 public Long hdel(String key, String... field) { 86 Jedis jedis = jedisPool.getResource(); 87 Long result = jedis.hdel(key, field); 88 jedis.close(); 89 return result; 90 } 91 92 @Override 93 public Boolean hexists(String key, String field) { 94 Jedis jedis = jedisPool.getResource(); 95 Boolean result = jedis.hexists(key, field); 96 jedis.close(); 97 return result; 98 } 99 100 @Override 101 public List<String> hvals(String key) { 102 Jedis jedis = jedisPool.getResource(); 103 List<String> result = jedis.hvals(key); 104 jedis.close(); 105 return result; 106 } 107 108 @Override 109 public Long del(String key) { 110 Jedis jedis = jedisPool.getResource(); 111 Long result = jedis.del(key); 112 jedis.close(); 113 return result; 114 } 115 116 }


1 package cn.e3mall.common.jedis; 2 3 import java.util.List; 4 5 import redis.clients.jedis.JedisCluster; 6 7 public class JedisClientCluster implements JedisClient { 8 9 private JedisCluster jedisCluster; 10 11 12 public JedisCluster getJedisCluster() { 13 return jedisCluster; 14 } 15 16 public void setJedisCluster(JedisCluster jedisCluster) { 17 this.jedisCluster = jedisCluster; 18 } 19 20 @Override 21 public String set(String key, String value) { 22 return jedisCluster.set(key, value); 23 } 24 25 @Override 26 public String get(String key) { 27 return jedisCluster.get(key); 28 } 29 30 @Override 31 public Boolean exists(String key) { 32 return jedisCluster.exists(key); 33 } 34 35 @Override 36 public Long expire(String key, int seconds) { 37 return jedisCluster.expire(key, seconds); 38 } 39 40 @Override 41 public Long ttl(String key) { 42 return jedisCluster.ttl(key); 43 } 44 45 @Override 46 public Long incr(String key) { 47 return jedisCluster.incr(key); 48 } 49 50 @Override 51 public Long hset(String key, String field, String value) { 52 return jedisCluster.hset(key, field, value); 53 } 54 55 @Override 56 public String hget(String key, String field) { 57 return jedisCluster.hget(key, field); 58 } 59 60 @Override 61 public Long hdel(String key, String... field) { 62 return jedisCluster.hdel(key, field); 63 } 64 65 @Override 66 public Boolean hexists(String key, String field) { 67 return jedisCluster.hexists(key, field); 68 } 69 70 @Override 71 public List<String> hvals(String key) { 72 return jedisCluster.hvals(key); 73 } 74 75 @Override 76 public Long del(String key) { 77 return jedisCluster.del(key); 78 } 79 80 }
application-redis.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 连接redis单机版 -->
<bean id="jedisClientPool" class="cn.e3mall.common.jedis.JedisClientPool">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!-- 连接redis集群 -->
<bean id="jedisClientCluster" class="cn.e3mall.common.jedis.JedisClientCluster">
<property name="jedisCluster" ref="jedisCluster"/>
</bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7001"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7002"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7003"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7004"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7005"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="7006"/>
</bean>
</set>
</constructor-arg>
</bean>
</beans>
新增缓存后
@Service
@Transactional
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper;
@Autowired
private JedisClient jedisClient;
@Value("${CONTENT_LIST}")
private String CONTENT_LIST;
/**
* 保存(大广告..)内容
* @param content
* @return
*/
@Override
public E3Result save(TbContent content) {
// 1.封装参数
content.setCreated(new Date());
content.setCreated(new Date());
// 2.插入
contentMapper.insert(content);
try {
jedisClient.hdel(CONTENT_LIST,content.getCategoryId().toString());
} catch (Exception ex) {
ex.printStackTrace();
}
// 3.返回
return E3Result.ok();
}
/**
* 根据分类id,取出各个分类的数据
* @param i
* @return
*/
@Override
public List<TbContent> findByCategoryId(Long i) {
try{
// 1)先从redis缓存中获取,需要的是字符串格式
String json = jedisClient.hget(CONTENT_LIST, i + "");
// 2)转成list
if(StringUtils.isNotBlank(json)){
List<TbContent> list = JsonUtils.jsonToList(json, TbContent.class);
return list;
}
} catch (Exception ex){
ex.printStackTrace();
}
// 1.设置查询条件
TbContentExample example = new TbContentExample();
TbContentExample.Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(i);
// 2.执行查询并返回
List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
try {
// 1)将list转成字符串
String json = JsonUtils.objectToJson(list);
// 2)设置到redis中
jedisClient.hset(CONTENT_LIST,i+"",json);
}catch (Exception ex){
ex.printStackTrace();
}
return list;
}
}