Redis集群中至少应该有三个节点。要保证集群的高可用,需要每个节点有一个备份机。
Redis集群至少需要6台服务器。
搭建伪分布式。可以使用一台虚拟机运行6个redis实例。需要修改redis的端口号7001-7006
1、使用ruby脚本搭建集群。需要ruby的运行环境。
安装ruby
yum install ruby
yum install rubygems
2、安装ruby脚本运行使用的包。
[root@localhost ~]# gem install redis-3.0.0.gem
Successfully installed redis-3.0.0
1 gem installed
Installing ri documentation forredis-3.0.0…
Installing RDoc documentation forredis-3.0.0…
[root@localhost ~]#
[root@localhost ~]# cd redis-3.0.0/src
[root@localhost src]# ll *.rb
-rwxrwxr-x. 1 root root 48141 Apr 1 2015redis-trib.rb
第一步:创建6个redis实例,每个实例运行在不同的端口。需要修改redis.conf配置文件的端口号。配置文件中还需要把cluster-enabled yes前的注释去掉。
第二步:启动每个redis实例。
第三步:使用ruby脚本搭建集群。
创建关闭集群的脚本:
[root@localhost redis-cluster]# vimshutdow-all.sh
redis01/redis-cli -p 7001 shutdown
redis01/redis-cli -p 7002 shutdown
redis01/redis-cli -p 7003 shutdown
redis01/redis-cli -p 7004 shutdown
redis01/redis-cli -p 7005 shutdown
redis01/redis-cli -p 7006 shutdown
[root@localhost redis-cluster]# chmod u+xshutdow-all.sh
[root@localhost redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006
create命令可选replicas参数,replicas表示需要有几个slave 这个命令就代表把这些个redis实例创建为一个集群 上面命令中的1代表主节点和从节点的比值是多少,如果12个主节点,6个从节点那么我们的比值就是2,那么我们是3主3从,所以这个比值是1,而且前三个一定是主节点,redis就是这样规定的。
Redis-cli连接集群。
[root@localhost redis-cluster]#redis01/redis-cli -p 7002 -c
-c:代表连接的是redis集群
jedis 即 java redis
用jedis 操作redis服务器
测试类:
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
public class JedisTest {
/**
* 单机版
* <p>Title: testJedis</p>
* <p>Description: </p>
*/
@Test
public void testJedis() {
Jedis jedis = new Jedis("192.168.25.128",6379);
jedis.set("test", "my first jedis test");
String string =jedis.get("test");
System.out.println(string);
}
/**
* 集群版
* <p>Title: testJedisCluster</p>
* <p>Description: </p>
*/
@Test
public void testJedisCluster() {
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.25.128", 7001));
nodes.add(new HostAndPort("192.168.25.128", 7002));
nodes.add(new HostAndPort("192.168.25.128", 7003));
nodes.add(new HostAndPort("192.168.25.128", 7004));
nodes.add(new HostAndPort("192.168.25.128", 7005));
nodes.add(new HostAndPort("192.168.25.128", 7006));
JedisCluster jedisCluster =new JedisCluster(nodes);
jedisCluster.set("test", "123");
String string =jedisCluster.get("test");
System.out.println(string);
jedisCluster.close();
}
}
单机版和集群版自由切换:
实体类设计:
接口:
import java.util.List;
public interface JedisClient {
String set(String key, String value);
String get(String key);
Boolean exists(String key);
Long expire(String key, int seconds);
Long ttl(String key);
Long incr(String key);
Long hset(String key, String field, String value);
String hget(String key, String field);
Long hdel(String key, String... field);
Boolean hexists(String key, String field);
List<String> hvals(String key);
Long del(String key);
}
单机版实体类:
import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* 单机版
* <p>Title: JedisClientPool</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
public class JedisClientPool implements JedisClient {
private JedisPool jedisPool;
public JedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
@Override
public Boolean hexists(String key, String field) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.hexists(key, field);
jedis.close();
return result;
}
@Override
public List<String> hvals(String key) {
Jedis jedis = jedisPool.getResource();
List<String> result = jedis.hvals(key);
jedis.close();
return result;
}
@Override
public Long del(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}
}
集群版实体类:
import java.util.List;
import redis.clients.jedis.JedisCluster;
/**
* 集群redis实体类
* <p>Title: JedisClientCluster</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
public class JedisClientCluster implements JedisClient {
private JedisCluster jedisCluster;
public JedisCluster getJedisCluster() {
return jedisCluster;
}
public void setJedisCluster(JedisCluster jedisCluster) {
this.jedisCluster = jedisCluster;
}
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}
@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}
@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}
@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}
@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
@Override
public Boolean hexists(String key, String field) {
return jedisCluster.hexists(key, field);
}
@Override
public List<String> hvals(String key) {
return jedisCluster.hvals(key);
}
@Override
public Long del(String key) {
return jedisCluster.del(key);
}
}
applicationContext-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="192.168.25.128"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!-- 连接redis集群版 -->
<!-- <bean id="jedisClientCluster" class="cn.e3mall.common.jedis.JedisClientCluster">
<property name="jedisCluster" ref="jedisCluster"/>
</bean>
<bean name="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.128"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
</bean> -->
</beans>
测试类:
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.e3mall.common.jedis.JedisClient;
public class JedisClientTest {
@Test
public void testJedisClient() throws Exception {
//初始化是spring容器
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("classpath:spring/applicationContext-redis.xml");
//从容器中获得JedisClient对象
JedisClient jedisClient = applicationContext.getBean(JedisClient.class);
jedisClient.set("mytest", "jedisClient");
String string = jedisClient.get("mytest");
System.out.println(string);
}
}
单机版和集群版不能共存,使用单机版时注释集群版的配置。使用集群版,把单机版注释。
不需要改代码,符合策略模式
查询内容列表时添加缓存。
1、查询数据库之前先查询缓存。
2、查询到结果,直接响应结果。
3、查询不到,缓存中没有需要查询数据库。
4、把查询结果添加到缓存中。
5、返回结果。
向redis中添加缓存:
Key:cid
Value:内容列表。需要把java对象转换成json。
使用hash对key进行归类。
HASH_KEY:HASH
|–KEY:VALUE
|–KEY:VALUE
|–KEY:VALUE
|–KEY:VALUE
注意:添加缓存不能影响正常业务逻辑。
/**
* 根据内容分类id查询分类列表
* <p>Title: getContentListByCid</p>
* <p>Description: </p>
* @param cid
* @return
* @see cn.e3mall.content.service.ContentService#getContentListByCid(long)
*/
@Override
public List<TbContent> getContentListByCid(long cid) {
//redis使用第一部分 查询缓存
try {
//缓存中有直接响应结果
String json = jedisClient.hget(CONTENT_LIST, cid+"");
if (StringUtils.isNotBlank(json)) {
List<TbContent> list = JsonUtils.jsonToList(json, TbContent.class);
return list;
}
} catch (Exception e) {
e.printStackTrace();
}
//缓存中没有 查询数据库
TbContentExample tbContentExample=new TbContentExample();
Criteria criteria = tbContentExample.createCriteria();
//设置查询条件
criteria.andCategoryIdEqualTo(cid);
List<TbContent> list = tbContentMapper.selectByExampleWithBLOBs(tbContentExample);
//redis使用第二部分 结果添加到缓存中
try {
jedisClient.hset(CONTENT_LIST, cid+"", JsonUtils.objectToJson(list));
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
对内容信息做增删改操作后只需要把对应缓存删除即可。
可以根据cid删除。
@Override
public E3Result addContent(TbContent content) {
//内容数据插入到内容表
content.setCreated(new Date());
content.setUpdated(new Date());
tbContentMapper.insert(content);
//redis使用 缓存同步 删除缓存中对应的数据
jedisClient.hdel(CONTENT_LIST, content.getCategoryId().toString());
return E3Result.ok();
}
其中:CONTENT_LIST 就是个字符串
为了方便修改 可写在配置文件中:
resource.properties:
CONTENT_LIST=CONTENT_LIST
然后通过注解获得值:
@Value("${CONTENT_LIST}") private String CONTENT_LIST;