本文共 2680 字,大约阅读时间需要 8 分钟。
使用redisson进行redis客户端操作
Redisson是一个在Redis的基础上实现的Java驻内存数据网络(In-Memory Data Grid)。不仅提供了一些列的分布式java常用对象,还提供了许多分布式服务。 Redission提供了Redis最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离,集中精力在业务处理上。
org.redisson redisson 3.13.4
@Configurationpublic class MyRedisConfig { @Value("${spring.redis.host}") private String redisIp; @Value("${spring.redis.port}") private String redisPort; //注入RedissonClient @Bean(destroyMethod = "shutdown") RedissonClient redisson(){ //编写配置 Config config = new Config(); //单节点模式 config.useSingleServer().setAddress("redis://"+redisIp +":"+redisPort); return Redisson.create(config); }}
如果A调用B。A、B都需要同一把锁,此时使用可重入锁(Reetrant Lock)就能实现可重入,A调用B。否则如果是不可重入,调用B的前提是A释放锁,A释放锁的前提是调用B,此时就形成死锁。
@ResponseBody@RequestMapping("/hello")public String hello(){ //获取一把锁 只要锁的名字一样就说是同一把锁 RLock lock = redisson.getLock("my-lock"); lock.lock(); try { System.out.println("走业务代码"); }finally { lock.unlock(); } return "hello";}
看门狗的原理是定时任务:重新给锁设置过期时间,新的过期时间就是看门狗的默认时间;锁时间/3是定时任务周期;
分布式可重入读写锁允许同时又多个读锁和写锁处于加锁状态。
读时处于无锁状态。@GetMapping("/park")@ResponseBodypublic String park() { RSemaphore park = redisson.getSemaphore("park"); try { park.acquire(2); } catch (InterruptedException e) { e.printStackTrace(); } return "park";}@GetMapping("/go")@ResponseBodypublic String go() { RSemaphore park = redisson.getSemaphore("park"); park.release(2); return "go";}
信号量可以做限流等应用
双写模式:
并发时,2号线程进入,写完DB后写缓存。而此时1号线程还没有写缓存,造成短时间内缓存有脏数据。 失效模式: 并发时, 1号线程先写数据库,删缓存, 2号线程此时依然还在写数据库, 但是3号线程读缓存发现没有缓存,此时去读取数据库,读数据库完成之后,2号线程才写完 在3号线程写缓存之前,2号线程写完数据库,也删完了缓存, 此时3号线程更新缓存。但是更新的依然是1号线程写的数据,2号线程写的数据没有加入到缓存。如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加上过期时间,每隔一段时间触发读的主动更新即可。
如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式
缓存数据+过期时间也足够解决大部分业务对于缓存的要求。通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。(业务不关心脏数据,允许临时脏数据可忽略);
我们能放入缓存的数据本就不应该是实时性、一致性要求超高的。所以缓存数据的时候加上过期时间,保证每天拿到当前最新数据即可。
我们不应该过度设计,增加系统的复杂性
遇到实时性、一致性要求高的数据,就应该查数据库,即使慢点。
转载地址:http://vexni.baihongyu.com/