Redis原理及在业务中的使用场景 - Redis详解

1、什么是Redis?

  • DB,数据存在内存中,其提供了多种数据类型(list,set,zset,hash等数据结构的存储)。

  • 可用来做缓存和分布式锁

  • redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案

  • Redis的一种持久化方式叫快照(snapshotting,RDB)(默认),另一种方式是只追加文件(append-only file,AOF)(影响性能)

2、Redis实现原理

  • redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,根据 socket 上的事件来选择对应的事件处理器进行处理。

  • 文件事件处理器的结构包含 4 个部分:

    • 多个 socket

    • IO 多路复用程序

    • 文件事件分派器

    • 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

    多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

3、Redis的使用场景

  • 热点数据

    存取数据优先从 Redis 操作,如果不存在再从文件(例如 MySQL)中操作,从文件操作完后将数据存储到 Redis 中并返回。同时有个定时任务后台定时扫描 Redis 的 key,根据业务规则进行淘汰,防止某些只访问一两次的数据一直存在 Redis 中。

  • 会话维持 Session

    会话维持 Session 场景,即使用 Redis 作为分布式场景下的登录中心存储应用。每次不同的服务在登录的时候,都会去统一的 Redis 去验证 Session 是否正确。但是在微服务场景,一般会考虑 Redis + JWT 做 Oauth2 模块。

  • 分布式锁 SETNX

    命令格式:SETNX key value:当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作。

    1)超时时间设置:获取锁的同时,启动守护线程,使用 expire 进行定时更新超时时间。如果该业务机器宕机,守护线程也挂掉,这样也会自动过期。如果该业务不是宕机,而是真的需要这么久的操作时间,那么增加超时时间在业务上也是可以接受的,但是肯定有个最大的阈值。

    2)但是为了增加高可用,需要使用多台 Redis,就增加了复杂性,

  • 表缓存

    Redis 缓存表的场景有黑名单。访问频率较高,即读高。根据业务需求,可以使用后台定时任务定时刷新Redis 的缓存表数据。

  • 消息队列 list

    主要使用了 List 数据结构。 List 支持在头部和尾部操作,因此可以实现简单的消息队列。

    1). 发消息:在 List 尾部塞入数据。

    2). 消费消息:在 List 头部拿出数据。同时可以使用多个 List,来实现多个队列,根据不同的业务消息,塞入不同的 List,来增加吞吐量。

  • 计数器 string

    主要使用了 INCR、DECR、INCRBY、DECRBY 方法。

    INCR key:给 key 的 value 值增加一 DECR key:给 key 的 value 值减去一

4、几种缓存问题及解决方案

缓存穿透

当大量的请求无命中缓存、直接请求到后端数据库(业务代码的 bug、或恶意攻击),同时后端数据库也没有查询到相应的记录、无法添加缓存。 这种状态会一直维持,流量一直打到存储层上,无法利用缓存、还会给存储层带来巨大压力。

解决方案:

  1. 请求无法命中缓存、同时数据库记录为空时在缓存添加该 key 的空对象(设置过期时间),缺点是可能会在缓存中添加大量的空值键(比如遭到恶意攻击或爬虫),而且缓存层和存储层数据短期内不一致;

  2. 使用布隆过滤器在缓存层前拦截非法请求、自动为空值添加黑名单(同时可能要为误判的记录添加白名单).但需要考虑布隆过滤器的维护(离线生成/ 实时生成)。

缓存雪崩

缓存崩溃时请求会直接落到数据库上,很可能由于无法承受大量的并发请求而崩溃,此时如果只重启数据库,或因为缓存重启后没有数据,新的流量进来很快又会把数据库击倒。

解决方案:

  • 事前:Redis 高可用,主从 + 哨兵,Redis Cluster,避免全盘崩溃。

  • 事中:本地 ehcache 缓存 + hystrix 限流 & 降级,避免数据库承受太多压力。

  • 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

请求过程

  • 用户请求先访问本地缓存,无命中后再访问 Redis,如果本地缓存和 Redis 都没有再查数据库,并把数据添加到本地缓存和 Redis;

  • 由于设置了限流,一段时间范围内超出的请求走降级处理(返回默认值,或给出友情提示)。