# 概述
Redis是一个开源(BSD许可)的内存中的数据结构存储系统,可 以用作数据库、缓存和消息中间件,
Redis内置了复制、Lua脚本、LRU驱动事 件、事务和不同级别的磁盘持久化,并通过Redis哨兵(Sentinel)模式和集群模式(Cluster)提供高可用性(High Availability)。
Redis 支 持 String 、 Hash 、 List 、 Set 、 ZSet 、 Bitmap 、HyperLogLog和Geospatial这 8种数据类型。
# 数据类型
String是Redis基本的数据类型,一个key对应一个value。String类型的值最大能存储 512MB数据。
Hash(映射)是一个键值(key->value)对集合(JSON对象)。
List是简单的字符串列表,按照插入顺序排 序。我们可以添加一个元素到列表的头部(左边)或者尾部(右 边)。列表最多可存储 231-1(4 294 967 295≈4亿多)个元素。
Set是String类型的无序集合。集合是通过散列表实现 的,所以添加、删除、查找的复杂度都是O(1)。
ZSet和Set一样也是String类型元素的集合, 且不允许有重复的成员,不同的是,每个元素都会关联一个double类 型的分数。Redis正是通过分数来为集合中的成员进行从小到大的排序的。
Bitmap:通过操作二进制位记录数据。
HyperLogLog:被用于估计一个Set中元素数量的概率性的数据结构。
Geospatial:用于地理空间关系计算
# 管道
# 事务
Redis支持分布式环境下的事务操作,其事务可以一次执行多个命 令,事务中的所有命令都会序列化地顺序执行。事务在执行过程中, 不会被其他客户端发送来的命令请求打断。
Redis的事务操 作分为开启事务、命令入队列、执行事务三个阶段。
# 发布、订阅
Redis发布、订阅是一种消息通信模式:发送者(Pub)向频道 (Channel)发送消息,订阅者(Sub)接收频道上的消息。
# 主从复制
Redis提供了复制功能,可以实现在主数据库(Master)中的数据 更新后,自动将更新的数据同步到从数据库(Slave)。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
# 持久化
Redis支持RDB(快照版,记录的是结果)和AOF(增量版,记录的是过程)两种持久化方式。
(1)RDB(Redis DataBase):RDB在指定的时间间隔内对数据进 行快照存储。
RDB的特点在于:文件格式紧凑,方便进行数据传输和数 据恢复;
在保存.rdb快照文件时父进程会fork出一个子进程,由子进 程完成具体的持久化工作,所以可以最大化Redis的性能;
同时,与AOF相比,在恢复大的数据集时会更快一些。
(2)AOF(Append Of Flie):AOF记录对服务器的每次写操作, 在Redis重启时会重放这些命令来恢复原数据。
AOF命令以Redis协议追 加和保存每次写操作到文件末尾,Redis还能对AOF文件进行后台重 写,使得AOF文件的体积不至于过大。
AOF的特点有:可以使用不同的fsync策略(无fsync、每秒fsync、每次写的时候fsync),只有某些 操作追加命令到文件中,操作效率高;同时,AOF文件是日志的格式,更容易被操作。
# 集群模式
# SpringBoot使用Redis
# 分布式缓存设计
分布式缓存设计的核心问题是以哪种方式进行缓存预热和缓存更新,以及如何优雅解决缓存雪崩、缓存穿透、缓存降级等问题。
# 缓存预热
缓存预热指在用户请求数据前先将数据加载到缓存系统中,用户 查询事先被预热的缓存数据,以提高系统查询效率。缓存预热一般有系统启动加载、定时加载等方式。
# 缓存更新
缓存更新指在数据发生变化后及时将变化后的数据更新到缓存中。常见的缓存更新策略有以下4种。
◎ 定时更新:定时将底层数据库内的数据更新到缓存中,该方法比较简单,适合需要缓存的数据量不是很大的应用场景。
◎ 过期更新:定时将缓存中过期的数据更新为最新数据并更新缓存的过期时间。
◎ 写请求更新:在用户有写请求时先写数据库同时更新缓存,这适用于用户对缓存数据和数据库的数据有实时强一致性要求的情况。
◎ 读请求更新:在用户有读请求时,先判断该请求数据的缓存是 否存在或过期,如果不存在或已过期,则进行底层数据库查询并将查询结果更新到缓存中,同时将查询结果返回给用户。
# 缓存淘汰策略
在缓存数据过多时需要使用某种淘汰算法决定淘汰哪些数据。常用的淘汰算法有以下几种。
◎ FIFO(First In First Out,先进先出):判断被存储的时间,离目前最远的数据优先被淘汰。
◎ LRU(Least Recently Used,最近最少使用):判断缓存最近被使用的时间,距离当前时间最远的数据优先被淘汰。
◎ LFU(Least Frequently Used,最不经常使用):在一段时间内,被使用次数最少的缓存优先被淘汰。
# 常见问题
# 缓存雪崩(同时过期失效)
缓存雪崩指在同一时刻由于大量缓存失效,导致大量原本应该访 问缓存的请求都去查询数据库,而对数据库的CPU和内存造成巨大压 力,严重的话会导致数据库宕机,从而形成一系列连锁反应,使整个系统崩溃。
◎ 设置不同的失效时间:为不同的数据设置不同的缓存失效时间,防止在同一时刻有大量的数据失效。
◎ 请求加锁:对于并发量不是很多的应用,使用请求加锁排队的方案防止过多请求数据库。
◎ 失效更新(自己定义过期,而不用redis的expire过期时间):为每一个缓存数据都增加过期标记来记录缓存数据是否失效,如果缓存标记失效,则更新数据缓存。
# 缓存穿透(不存在的数据)
缓存穿透指由于缓存系统故障或者用户频繁查询系统中不存在 (在系统中不存在,在自然数据库和缓存中都不存在)的数据,而这 时请求穿过缓存不断被发送到数据库,导致数据库过载,进而引发一连串并发问题。
常用的解决缓存穿透问题的方法有布隆过滤器和cache null策略。
◎ 布隆过滤器:指将所有可能存在的数据都映射到一个足够大的Bitmap中,在用户发起请求时首先经过布隆过滤器的拦截,一个一定不存在的数据会被这个布隆过滤器拦截,从而避免对底层存储系统带来查询上的压力。
◎ cache null策略:指如果一个查询返回的结果为null(可能是 数据不存在,也可能是系统故障),我们仍然缓存这个null结果,但 它的过期时间会很短,通常不超过 5 分钟。
# 缓存降级(减少或关闭非核心业务对数据库资源的使用)
缓存降级指由于访问量剧增导致服务出现问题(如响应时间慢或 不响应)时,优先保障核心业务的运行,减少或关闭非核心业务对资源(数据库资源的使用)的使用。常见的服务降级策略如下。
◎ 写降级(异步写):在写请求增大时,可以只进行Cache的更新,然后将 数据异步更新到数据库中,保证最终一致性即可,即将写请求从数据库降级为Cache。
◎ 读降级(只读取缓存,不读取数据库):在数据库服务负载过高或数据库系统故障时,可以只 对Cache进行读取并将结果返回给用户,在数据库服务正常后再去查询 数据库,即将读请求从数据库降级为Cache。这种方式适用于对数据实 时性要求不高的场景,保障了在系统发生故障的情况下用户依然能够访问到数据,只是访问到的数据相对有延迟。