一、java中操作Redis实践
1.Jedis
是Java中操作redis的一个客户端,类似通过jdbc访问mysql数据库。
1.首先在父工程添加pom文件,在子工程添加依赖
2.Jedis jedis=new Jedis("192.168.126.129",6379);
2.JedisPool
不需要每次new直接在池里面取
public class JedisPoolTests {
@Test
public void testJedisPool(){
//定义连接池的配置
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(1000);//最大连接数
config.setMaxIdle(60);//最大空闲数
//创建连接池
JedisPool jedisPool=
new JedisPool(config,"192.168.126.130",6379);
//从池中获取一个连接
Jedis resource = jedisPool.getResource();
resource.auth("123456");
//应用
//通过jedis连接存取数据
resource.set("class","cgb2004");
String clazz=resource.get("class");
System.out.println(clazz);
//将链接返回池中
resource.close();
//关闭连接池
jedisPool.close();
}
}
可以基于池对象,设计一个数据源
public class JedisDataSource {
private static final String IP="192.168.126.128";
private static final int PORT=6379;//redis.conf 默认端口
public static Jedis getConnection(){
//双重校验
if(jedisPool==null) {
synchronized (JedisDataSource.class) {
if (jedisPool == null) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(16);
config.setMaxIdle(8);
jedisPool = new JedisPool(config, IP, PORT);
//创建对象分析
//1.开辟内存空间
//2.执行属性的默认初始化
//3.执行构造方法
//4.将创建的对象的内存地址赋值给jedisPool变量
//假如使用了volatile修饰jedisPool变量,可以保证如上几个步骤是顺序执行的
}
}
}
//有了这个直接调用即可
return jedisPool.getResource();
}
public static void close(){
jedisPool.close();
}
}
3.RedisTemplate
1.准备:配置pom,yml,maven
2.依赖注入
@Autowired
private RedisTemplate redisTemplate;
3.常用API
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
4.我们还可以将其转化为json,已经按照我们自己的方式序列化
二、SpringBoot工程中Redis与Aop技术的整合
缓存有则查缓存,缓存没有,查数据库,然后再把数据存入缓存并设定存储的时间。
// @Autowired
// private RedisTemplate redisTemplate;
@Resource(name="redisTemplate")
private ValueOperations valueOperations;//从spring.io官方的data项目中去查这种注入方式
@Override
public Menu selectById(Long id) {
//ValueOperations valueOperations = redisTemplate.opsForValue();
Object obj=valueOperations.get(String.valueOf(id));
if(obj!=null){
System.out.println("Get Data from redis");
return (Menu)obj;
}
Menu menu=menuMapper.selectById(id);
valueOperations.set(String.valueOf(id), menu, Duration.ofSeconds(120));
return menu;
}
当然也可以直接重新写一个Default类
public class DefaultMenuService implements MenuService{
@Autowired
private MenuMapper menuMapper;
/**
* 由此注解描述的方法为切入点方法,此方法执行时,底层会通过AOP机制
* 先从缓存取数据,缓存有则直接返回,缓存没有则查数据,最后将查询的数据
* 还会向redis存储一份
* @param id
* @return
*/
@Cacheable(value = "menuCache",key="#id")
@Override
public Menu selectById(Long id) {
return menuMapper.selectById(id);
}
}
三、持久化
1.why
Redis是一种内存数据库,在断电时数据可能会丢失
2.what
Redis中为了保证在系统宕机(类似进程被杀死)情况下,能更快的进行故障恢复,设计了两种数据持久化方案,分别为rdb和aof方式。
3.how
第一种:将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据。(RDB)
第二种:将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程。(ROF)
如何选择redis的持久化方式?
第一:不要仅仅使用RDB,因为那样会导致你丢失很多数据。
第二:也不要仅仅使用AOF,因为AOF做冷备没有RDB做冷备进行数据恢复的速度快,并且RDB简单粗暴的数据快照方式更加健壮。
第三:综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备。
四、Redis事务
概述
事务是一个业务,也可以看成是一个逻辑工作单元,是为了保证业务的完整,数据的正确而推出的一种控制机制,原则上来讲,事务必须要满足ACID四个特性(原子性,一致性,隔离性,持久性),在多个事务
在并发执行,为更好保证事务的四个特性的实现,通常会对事务加锁,Redis为了性能,采用了乐观锁方式进行事务控制,它使用watch命令监视给定的key,当exec(提交事务)的时候,如果监视的key从调用watch后发生过变化,则整个事务会失败。也可以调用watch多次监视多个key。注意watch的key是对整个连接有效的,如果连接断开,监视和事务都会被自动清除。当然exec,discard,unwatch命令都会清除连接中的所有监视。
基本指令
redis进行事务控制时,通常是基于如下指令进行实现,例如:
multi 开启事务
exec 提交事务
discard 取消事务
watch 监控,如果监控的值发生变化,则提交事务时会失败
unwatch 去掉监控
Redis保证一个事务中的所有命令要么都执行,要么都不执行(原子性)。如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
五、Redis架构设计应用实践
1.主从复制
结论:
为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据冗余备份。
2.哨兵机制
哨兵的作用:
-
监控:监控master和slave
不断的检查master和slave是否正常运行
master存活检测、master与slave运行情况检测
-
通知(提醒):当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知
-
自动故障转移:断开master与slave连接,选取一个slave作为master,将其他slave连接新的master,并告知客户端新的服务器地址
注意:哨兵也是一台redis服务器,只是不提供数据相关服务,通常哨兵的数量配置为单数
3.集群
常见问题分析
- Redis主从架构,哨兵,集群架构诞生的一个背景?
- 单纯的Redis主从架构存在什么问题?(主机点宕机,整个主从不再支持写操作)
- Redis哨兵(sentinel)做用是什么?(监控主从节点工作状态,主节点宕机,自动选择新的主节点)
- Redis 从节点下还可有从节点吗?(可以的,薪火相传)
- Redis主从加哨兵还存在什么明显缺陷?(主节点只有一个,支持可存储的数据量受限)
- 集群架构要解决的主要问题是什么?(横向扩容,单个主节点不能支持更大并发的写操作,且容量有限)
- 当架构设计中的redis服务有问题时怎么办?(一定要看容器日志)