# Redis 应用场景

  • 缓存:热点数据 (经常查询,但不修改或删除数据) 首选 Redis 缓存,性能优秀

    • 分布式锁:多个 tomcat 通过 Redis 获取锁后才能访问 MySQL 数据库

    • 实现方式:Jedis,Lettuce,RedisTemplete,Redisson (更加方便,无需额外写代码)

    • 具体实现

      1. 获取锁:setnx key value
      2. 设置锁过期时间:expire key 30
      3. 执行业务代码
      4. 释放锁: del key
    • Redisson 实现分布式锁

      1. 获取锁:redisson.getLock ("lock");lock.lock ();
      2. 执行业务代码
      3. 释放锁:lock.unlock ();
    • Redisson 实现的分布式锁是可重入的吗?

      可重入:即可重复获取,它指的是线程 T 获取到锁 A 之后,线程 T 再次获取锁 A 还是可以获取到的,java 中的 synchronized,ReentrantLock 都是可重入锁

  • Token 存储

  • 短信验证码存储 (后端生成的验证码存入 Redis, 然后与用户发送的验证码进行比较)

  • 计数器

  • 全局唯一 ID

  • 排行榜 (使用 ZSet 结构)

  • 限流

  • 购物车

  • 点赞关注

# 实现分布式锁需要注意哪些问题

  • 不是原子操作 (即必须将获取锁和设置锁的过期时间变成一个整体进行操作)

  • 没有释放锁 (没有 del 锁,导致后面的线程无法拿到锁,当然如果设置了过期时间,还可以等过期时间结束)

  • 释放了锁,但业务还未执行完毕 (即执行业务代码耗时超过了锁的过期时间)

  • 释放了别人的锁 (因锁的过期时间过短,导致他人拿到自己的锁,而通过释放锁的操作将他人拿到的锁释放,解决方法为在释放锁时加入判断是否是自己的锁)

  • 大量请求竞争锁失败

    解决方法

    1. 重试 (重试三到五次,若未拿到锁,返回获取锁失败)
    2. 让业务流程尽可能短
    3. 限流
  • 多节点 Redis 主从复制的问题

  • 锁的性能问题 (采用分段锁的方式,减少获取锁的排队时间)

  • 锁的可重入性

# 采用 Redis 缓存,遇到缓存穿透,缓存击穿,缓存雪崩怎么办?

# 缓存穿透

缓存穿透是由于请求一个不存在的数据而导致的

  • 方案一:缓存空结果,对数据库查询不存在的数据依然缓存到缓存中,比如缓存一条空值 unknow, 有效减少查询数据库的效率。优点是实现简单。缺点是缓存了无效数据,占用 Redis 缓存,可能存在缓存与数据库不一致的情况

  • 方案二:布隆过滤器。在访问 Redis 之前,先通过布隆过滤器进行筛选。优点是不会缓存无效数据,缺点是实现比较复杂,存在一定的误判.

    布隆过滤器

    布隆过滤器用于检索一个元素是否在一个集合中。它采用一个很长的二进制数组,通过一些列 hash 函数来确定该数据是否存在.

    具体实现如下

    在向布隆过滤器中添加元素时,会使用多个哈希函数对元素进行 hash, 然后使用数组长度取余,算出一个索引位置,再把数组这几个位置都设置为 1, 这样就完成了元素的添加操作.

    向布隆过滤器查询元素是存在时,和添加元素一样,. 算出数组位置。然后看数组对应位置是否为 1, 只要有一个位置为 0, 代表存在。如果这几个位置都为 1, 代表可能存在.

    目前的具体实现由 Guava,Hutool,Redisson

# 缓存击穿

高并发情况下,对于热点数据,当数据失效的一瞬间,或者刚开始时缓存中还没有对热点数据进行缓存,所有请求被发送到数据库去查询,导致数据库被压垮.

  • 方案一:全局锁:在访问数据库之前都请求全局锁,获得的锁的线程才有资格去访问数据库,其他线程必须等待。由于现在的业务都是分布式的,本地锁没法控制其他服务的线程也等待,所以要用全局锁,比如分布式锁.
  • 方案二:对于热点数据,设置永不过期.
    • 实现方案一:不设置过期时间,即 "物理" 不过期。优点是简单。缺点是缓存的热点数据是静态的,得不到更新
    • 实现方案二:逻辑不过期,通过一个异步线程,当检测到超过了过期时间,即更新缓存数据,这样只有前几条是旧数据,后面拿到的即为更新的数据.

# 缓存雪崩

在某一时刻,大量的 key 或者整个缓存的数据全部过期了或者缓存发生了故障,然后瞬间所有的请求都落到数据库,数据库被压垮

如何解决?

  1. Redis 高可用 (搭建 Redis Sentinel 或者 Redis Cluster 集群), 避免 Redis 不可用
  2. 给不同的 key 设置不同的过期时间
  3. 本地缓存 (二级缓存) + 限流 & 降级,避免数据库被压垮

缓存雪崩与缓存击穿的区别

缓存击穿某些热点数据 (或者说是同一条数据) 过期了,而走数据库 (即主体为被频繁访问的少量数据)

缓存雪崩强调的是大量数据 (或者说是所有数据) 都过期了,而走数据库 (即主题为大量数据)

因此,缓存雪崩核心就是,缓存无法使用,就全部走数据库 \

# Redis 内存使用完了怎么办

通过内存配置文件配置最大使用内存

当达到最大使用内存时使用内存淘汰策略

默认淘汰策略为 noeviction

# Redis 的 String 类型的值最大能放多大的数据

  • string:512MB

  • List:2^32-1 (4,294,967,295) 个元素

  • Set:2^32-1 (4,294,967,295) 个元素

  • Hash: 每个 hash 值最大能放 2^32-1 (4,294,967,295) 个 filed-value 对,Hash 类型仅受部署 Redis 的服务器上的总内存的限制

  • ZSet 与 Set 一样

# 如何保证数据库与 Redis 的数据一致性

即数据库发生增删改的时候,数据库的数据要和 Redis 缓存的数据保持一致性

# Redis 集群最大能部署多少个主节点

16384

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

KagurazakaAsahi 微信支付

微信支付