对redis、redisson、springcache总结

<一> redis-缓存中间件

  1. 什么是redis
    redis是c语言开发的,一个高性能key-value键值对内存数据库,可以用来做数据库、缓存、消息中间件的一种非关系型数据库。

  2. redis数据存储在哪里
    内存和磁盘中,但是redis的读写都在内存中,这也是速度快的原因之一。
    对于高频繁访问的数据,存储在内存中方便访问。
    为了避免服务宕机或者重启数据丢失,也可以将数据存储在磁盘中持久化。

  3. redis的数据类型
    String、set、zset、list、hash

  4. redis为什么响应速度快
    1) 基于内存存储,redis的读写都是基于内存的key-value操作。内存远大于磁盘响应速度。
    2) 单线程操作,避免了多线程cpu来回切换和各种加锁和解锁的资源消耗。
    redis的单线程操作是指一个模块的操作单线程,其他该多线程的还是使用多线程。
    3)丰富的数据结构
    redis是基于key-velue键值对存储的缓存数据库,对于key都是string类型,但是vlue有多种数据类型
    4)高性能的多复用IO模型

  5. 为什么需要使用redis
    redis的响应速度快读10w+,写8w,对于一些业务场景(可以将计算的结果-菜单等存储到缓存中,下次直接getfromredis)

  6. redis怎么配置、步骤
    1) pom文件加上依赖


    org.springframework.boot
    spring-boot-starter-data-redis



    io.lettuce
    lettuce-core


2) 配置文件加上redis服务器的host port user psw等信息
3)使用springboot自动配置好的StringRedisTemplete工具来操作redis进行读写操作,
@Autowired
StringRedisTemplete stringRedisTemplete;
// 读
stringRedisTemplete.opsForValue.get(“keyName”)
// 写
stringRedisTemplate.opsForValue().set(“keyName”, value, 1, TimeUnit.DAYS); // 设置过期时间 防止缓存数据与数据库不一致

  1. redis怎么进行get,set,读写数据
    使用StringRedisTemplete .get(“keyname”) /.set(“keyname”,“value”,“time”,“时间单位”)

  2. redis有哪些参数
    key-String
    value-list,string、set、zset、hash
    过期时间-过期删除,重新sql获取set到缓存中,与数据库数据保持一致
    过期时间的单位

  3. redis缓存容易出现的问题
    1)缓存穿透
    reason: 大量并发请求一个不存在的数据,到缓存中null,之后大量请求到了数据库中,数据库压力过大崩了。这种是缓存穿透。
    way: 即使数据库中为null的数据,也存储一个标识到缓存中,并且设置一个过期时间。

2)缓存雪崩
r:大量不同业务模块的请求到缓存,但是对应的数据同时过期了,导致所有的请求到db-压力大。
w:设置不同的过期时间,可以在配置文件中统一配置,因为不同业务key存储的时间不同,过期点也不会相同。

3)缓存击穿
r:大量恶意请求到一个热点词,刚好这个key过期了。db压力过大
w:加锁-记得双重验证,每次只允许一个请求进入db-get->db,其他没有进去锁的去访问缓存即可。

  1. 本地锁(不是redis分布式锁,加关键字Synchronized等)
    本地锁只能锁住同一个进程里面的线程,如果是分布式下,即使每个服务仅仅放一个线程进来,相互是隔离的,不能只锁住一个。这个时候需要分布式锁-redisson(使用redis分布式锁-没有看门狗机制)

  2. redis怎么保证与数据库数据一致(更新数据库)
    1)双写模式
    先更新数据库,再去更新缓存对应的key,这种缓存中可能会短暂出现脏数据,稳定后缓存过期-重新读取db即可保证最新数据。
    2)失效模式
    先写数据库,后删除缓存。这种也可能短暂出现缓存有脏数据,稳定后即可

        无论是更新缓存还是删除缓存都会有脏数据,解决如下
    

    1)失效模式-使用双删模式
    先删除缓存->更新db-隔几秒再去删除缓存
    2)使用MQ消息队列,消费者监听queue消息去删除缓存
    生产者(更新db)->MQ->queue有数据->customer监听到->删除缓存->告知queue是否删除成功,失败queue再次发送。(不需要写代码,mq本身会重复出队。解耦修改数据库和查询数据库解耦,不会造成缓存有脏数据)

11.缓存锁使用的原则
正常数据,缓存加上过期时间,就可以实现数据一致性。
对于实时性要求高的,最好是到数据库中读取。
对于频繁修改的数据,不建议加读写锁,性能会慢。

<二> redisson-分布式锁

  1. redisson是什么
    redisson是基于redis的分布式框架,提供了分布式锁等服务

  2. 为什么需要分布式锁
    本地锁只能锁住当前进程-一个服务的线程,所以需要分布式锁。

  3. redission配置步骤
    1)pom文件加上依赖(前提是有redis依赖)

    org.redisson
    redisson
    3.12.0

    2)配置redis配置信息

  4. redisson提供的分布式锁与redis自己的分布式锁区别
    1)redisson提供的分布式锁
    -分布式下也只能有一个线程占用锁,执行业务代码,直至解锁,下一个thread才能进来执行。
    使用RedissonClient加锁—不会出现死锁----锁会自动过期
    @Autowried
    RedissonClient client;
    // 1. 获取锁mylock 只要锁的名字相同 就是同一把锁
    RLock myLock = redisson.getLock(“myLock”);
    // 2. 加锁
    myLock.lock(); // 阻塞锁
    // 业务代码
    try {
    System.out.println(“加锁成功,执行业务…” + Thread.currentThread().getId());
    Thread.sleep(3000);
    } catch (Exception e) {
    } finally {
    // 3. 解锁
    // 即使业务代码执行失败或者断电,没有解锁成功,也不会出现死锁,
    // RedissonClient不会出现死锁
    System.out.println(“释放锁” + Thread.currentThread().getId());
    myLock.unlock();
    }

2)redis提供的分布式锁
使用StringRedisTemplate加锁
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(
“lockValue”,
uuid,
5,
TimeUnit.SECONDS);

3) redis-StringRedisTemplate分布式锁与redisson-RedissonClient 分布式锁区别。
区别在于
1.–redisson分布式锁有看门狗机制,一个线程占用锁之后,如果锁没有释放之前,redisson会自动给锁续期(10s检查一次锁是否释放,续期time-30s),不会过期,直至线程结束锁释放。
2- -redis 的stringRedisTemplate分布式锁不会自动续期。
redisson加锁的业务代码只要完成,就不会自动给锁续期,即使不unlock,锁默认在30s后自动删除。即使服务宕机-业务结束,也不会出现死锁,锁会自动过期。

  1. 读写锁相关
    // 6.1 读写锁(可以获read-write)
    RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(“catalogJson-lock”);
    // 6.2 写锁
    RLock wLock = readWriteLock.writeLock();
    // 6.3 读锁
    RLock rLock = lock.readLock();
    注意
    1)一个读锁可以被多个thread线程占用不互斥。
    2)写锁与其他锁都互斥,一次只能有一个线程占用锁,其他写或者读必须等待。

  2. 分布式锁的几个参数
    创建锁的过期时间,时间单位,redisson分布式锁默认是10s查看一次锁是否还在,如果在自动延长30s(前提是没有手动设置过期时间)

  3. redisson分布式锁的特点
    1)一次只能有一个进程的一个线程进来
    2)有看门狗机制,redisson–自动续期30s,业务未执行完,其他锁进来造成数据紊乱
    3)自动过期-避免死锁(什么是死锁,加锁->执行业务->执行完解锁,没有解锁业务代码出异常或者服务挂了,锁就一直存在redis缓存数据库中-死锁)

  4. redisson看门狗机制(给线程看门,线程进去执行业务,redisson看门)
    redisson-redissonClient提供的分布锁,一旦某个线程进入到占了锁,在业务代码没有执行完成,释放锁之前,redisson没10s会自动检测锁是否还在,并续期30s。直至业务完成,解锁,不再自动续期。这种情况只针对没有手动配置过期时间的前提,如果配置了则失效。

  5. redission的可重入锁机制
    Redisson 可重入锁是一种分布式锁,它基于 Redis 实现。可重入指的是同一个线程在持有锁的情况下,可以多次获取该锁而不会造成死锁。

<三>SpringCache-分布式缓存使用

  1. springcache是什么
    spring提供的一个缓存框架,使用一些注解解决缓存的问题,不需要关心底层代码逻辑如何实现

  2. 使用redis作为缓存工具,cache使用步骤
    1)pom文件加上依赖
    引入依赖 spring-boot-starter-cache
    spring-boot-starter-data-redis
    2)手动在配置文件加上缓存类型(其他配置后面使用场景再说)
    spring.cache.type=redis
    3)开启缓存@EnableCaching // 开启缓存,加在对应Configuration类上面

3.springcache 主要的注解
1)@EnableCaching-开启缓存
2)@Cacheable 加上方法上面,触发方法更新缓存(如果缓存不是null则不存储db数据到缓存中)
3)@CacheEvict,更新数据库触发删除缓存对应的数据-失效模式
4)@CachePut,更新数据库,在不影响更新数据库的情况下,更新缓存数据-双写模式。

  1. springcache有哪些不足之处?该缓存框架默认不加锁
    1)读模式(@Cacheable-读db->set->redis)
    只要涉及读db数据到redis缓存,且不加锁的情况,大并发就会暴露redis存储缺陷。
    a. 缓存穿透-开启db空值也存到redis中
    配置文件加
    spring.cache.redis.cache-null-values=true

    b. 缓存雪崩-配置设置缓存的过期时间
    spring.cache.redis.time-to-live=600000

    c. 缓存击穿-加锁
    springCache默认是不加分布式锁的,可以对应方法上
    @Cacheable注解上面加上sync = “true”,线程加锁-一次只允许一个线程占用锁访问db-避免热点击穿db。
    @Cacheable(value = “category”, key = “#root.method.name”, sync = true)

    2)写模式
    数据写模式对应的是更新数据,势必涉及更新db与更新缓存,两者存在数据一致性问题。
    解决方法:对于读多写少的数据,直接使用springcache缓存即可,key设置过期时间,查询触发再次更新db数据到缓存redis中。

总结
redis-缓存中间件-暂时的非关系key-value键值对数据库,StringRedisTemplate操作。
redisson-基于redis操作的数据库,提供分布式锁,解决分布式下操作redis缺陷。-使用redissonClient操作分布式锁(单体不需要redisson,本地锁就可以解决)
springcache-spring提供的分布式缓存框架,可以使用多种缓存中间件存储数据,本文type是redis,直接使用一些注解实现redis读-存储,写-写/删数据。不需要再单独使用redis执行一些列繁琐的代码实现。

你可能感兴趣的:(redis,分布式,缓存,spring)