分布式缓存 Redis

一. 缓存
缓存是⼀个⾼速数据交换的存储器,使⽤它可以快速的访问和操作数据。

相⽐于数据库⽽⾔,缓存的操作性能更⾼,缓存性能⾼的主要原因有以下⼏个:

  1. 缓存⼀般都是 key-value 查询数据的,因为不像数据库⼀样还有查询的条件等因素,所以查询的性能 ⼀般会⽐数据库⾼;
  2. 缓存的数据是存储在内存中的,⽽数据库的数据是存储在磁盘中的,因为内存的操作性能远远⼤于磁 盘,因此缓存的查询效率会⾼很多;
  3. 缓存更容易做分布式部署(当⼀台服务器变成多台相连的服务器集群),⽽数据库⼀般⽐较难实现分布 式部署,因此缓存的负载和性能更容易平⾏扩展和增加。

二.缓存分类
缓存⼤致可以分为两⼤类:
本地缓存 :Spring Cache、MyBatis 的缓存等。
分布式缓存 :Redis 和 Memcached。
三.分布式缓存:Redis
在 Spring 框架中我们也可以直接操作 Redis 缓存,它的操作流程如下图所示:
分布式缓存 Redis
Redis 和 Memcached 有什么区别?
存储⽅式不同:memcache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存⼤⼩; Redis 有部份存在硬盘上,这样能保证数据的持久性;
数据⽀持类型:memcache 对数据类型⽀持相对简单;Redis 有复杂的数据类型;
存储值⼤⼩不同:Redis 最⼤可以达到 512mb,memcache 只有 1mb。
4.Redis 数据类型和使⽤
Redis 有 5 ⼤基础数据类型:
String——字符串类型
Hash——字典类型
List——列表类型
Set——集合类型
ZSet——有序集合类型
其中最常⽤的是字符串和字典类型。
① 字符串类型
字符串类型(Simple Dynamic Strings 简称 SDS),译为:简单动态字符串,它是以键值对 key-value 的形式进⾏存储的,根据 key 来存储和获取 value 值,它的使⽤相对来说⽐较简单,但在实际项⽬中应⽤ ⾮常⼴泛。
② 字典类型
字典类型 (Hash) ⼜被成为散列类型或者是哈希表类型,它是将⼀个键值 (key) 和⼀个特殊的“哈希表”关 联起来,这个“哈希表”表包含两列数据:字段和值,它就相当于 Java 中的 Map<String,Map<String,String>> 结构。
③ 列表类型
列表类型 (List) 是⼀个使⽤链表结构存储的有序结构,它的元素插⼊会按照先后顺序存储到链表结构中, 因此它的元素操作 (插⼊和删除) 时间复杂度为 O(1),所以相对来说速度还是⽐较快的,但它的查询时间复 杂度为 O(n),因此查询可能会⽐较慢。
④ 集合类型
集合类型 (Set) 是⼀个⽆序并唯⼀的键值集合。
⑤ 有序集合类型
有序集合类型 (Sorted Set) 相⽐于集合类型多了⼀个排序属性 score(分值),对于有序集合 ZSet 来 说,每个存储元素相当于有两个值组成的,⼀个是有序结合的元素值,⼀个是排序值。有序集合的存储元素值也是不能重复的,但分值是可以重复的。

5.持久化
所谓的持久化就是将数据从内存保存到磁盘的过程,它的⽬的就是为了防⽌数据丢失。因为内存中的数据 在服务器重启之后就会丢失,⽽磁盘的数据则不会,因此为了系统的稳定起⻅,我们需要将数据进⾏持久 化。同时持久化功能⼜是 Redis 和 Memcached 最主要的区别之⼀,因为 Redis ⽀持持久化⽽ Memcached 不⽀持。
Redis 持久化的⽅式有以下 3 种:
快照⽅式(RDB, Redis DataBase)将某⼀个时刻的内存数据,以⼆进制的⽅式写⼊磁盘;
⽂件追加⽅式(AOF, Append Only File),记录所有的操作命令,并以⽂本的形式追加到⽂件中;
混合持久化⽅式,Redis 4.0 之后新增的⽅式,混合持久化是结合了 RDB 和 AOF 的优点,在写⼊的 时候,先把当前的数据以 RDB 的形式写⼊⽂件的开头,再将后续的操作命令以 AOF 的格式存⼊⽂ 件,这样既能保证 Redis 重启时的速度,⼜能减低数据丢失的⻛险。

RDB 优点: RDB 的内容为⼆进制的数据,占⽤内存更⼩,更紧凑,更适合做为备份⽂件;
RDB 对灾难恢复⾮常有⽤,它是⼀个紧凑的⽂件,可以更快的传输到远程服务器进⾏ Redis 服务恢 复;
RDB 可以更⼤程度的提⾼ Redis 的运⾏速度,因为每次持久化时 Redis 主进程都会 fork() ⼀个⼦进 程,进⾏数据持久化到磁盘,Redis 主进程并不会执⾏磁盘 I/O 等操作;
与 AOF 格式的⽂件相⽐,RDB ⽂件可以更快的重启。
RDB 缺点: 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终⽌了,则会丢失⼀段时间内 的 Redis 数据; RDB 需要经常 fork() 才能使⽤⼦进程将其持久化在磁盘上。如果数据集很⼤,fork() 可能很耗时,并 且如果数据集很⼤且 CPU 性能不佳,则可能导致 Redis 停⽌为客户端服务⼏毫秒甚⾄⼀秒钟。

AOF 优点 AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存⼀次、跟随 系统的持久化策略保存,其中每秒保存⼀次,从数据的安全性和性能两⽅⾯考虑是⼀个不错的选择,也 是 AOF 默认的策略,即使发⽣了意外情况,最多只会丢失 1s 钟的数据;
AOF 采⽤的是命令追加的写⼊⽅式,所以不会出现⽂件损坏的问题,即使由于某些意外原因,导致了 最后操作的持久化数据写⼊了⼀半,也可以通过 redis-check-aof ⼯具轻松的修复;
AOF 持久化⽂件,⾮常容易理解和解析,它是把所有 Redis 键值操作命令,以⽂件的⽅式存⼊了磁 盘。即使不⼩⼼使⽤ flushall 命令删除了所有键值信息,只要使⽤ AOF ⽂件,删除最后的 flushall 命令,重启 Redis 即可恢复之前误删的数据。
AOF 缺点 对于相同的数据集来说,AOF ⽂件要⼤于 RDB ⽂件;
在 Redis 负载⽐较⾼的情况下,RDB ⽐ AOF 性能更好;
RDB 使⽤快照的形式来持久化整个 Redis 数据,⽽ AOF 只是将每次执⾏的命令追加到 AOF ⽂件 中,因此从理论上说,RDB ⽐ AOF 更健壮。
6.常问题
① 缓存雪崩 缓存雪崩是指在短时间内,有⼤量缓存同时过期,导致⼤量的请求直接查询数据库,从⽽对数据库造成了 巨⼤的压⼒,严重情况下可能会导致数据库宕机的情况叫做缓存雪崩。
缓存雪崩的常⽤解决⽅案有以下⼏个。加锁排队 随机化过期时间 设置⼆级缓存

② 缓存穿透 缓存穿透是指查询数据库和缓存都⽆数据,因为数据库查询⽆数据,出于容错考虑,不会将结果保存到缓 存中,因此每次请求都会去查询数据库,这种情况就叫做缓存穿透。
③ 缓存击穿 缓存击穿指的是某个热点缓存,在某⼀时刻恰好失效了,然后此时刚好有⼤量的并发请求,此时这些请求 将会给数据库造成巨⼤的压⼒,这种情况就叫做缓存击穿。
④ 缓存预热 ⾸先来说,缓存预热并不是⼀个问题,⽽是使⽤缓存时的⼀个优化⽅案,它可以提⾼前台⽤户的使⽤体 验。缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便⽤户后⾯查询时可以直接从缓存中 读取,以节约⽤户的等待时间。

7.Redis 集群
① 主从同步 主从同步 (主从复制) 是 Redis ⾼可⽤服务的基⽯,也是多机运⾏中最基础的⼀个。我们把主要存储数据 的节点叫做主节点 (master),把其他通过复制主节点数据的副本节点叫做从节点 (slave)
主从同步具有以下 3 个优点
性能⽅⾯:有了主从同步之后,可以把查询任务分配给从服务器,⽤主服务器来执⾏写操作,这样极⼤ 的提⾼了程序运⾏的效率,把所有压⼒分摊到各个服务器了;
⾼可⽤:当有了主从同步之后,当主服务器节点宕机之后,可以很迅速的把从节点提升为主节点,为 Redis 服务器的宕机恢复节省了宝贵的时间;
防⽌数据丢失:当主服务器磁盘坏掉之后,其他从服务器还保留着相关的数据,不⾄于数据全部丢失。

主从同步的缺点:这种模式本身存在⼀个致命的问题,当主节点奔溃之后,需要⼈⼯⼲预才能恢复 Redis 的正常使⽤
② 哨兵模式
假如晚上发⽣了主从服务器宕机的情况,尤其是在主从服务器节点⽐较多的情况下,如果需要⼈⼯恢复, 那么需要的时间和难度是很⼤的,因此我们需要⼀个⾃动的⼯具——Redis Sentinel (哨兵模式) 来把⼿动 的过程变成⾃动的,让 Redis 拥有⾃动容灾恢复 (failover) 的能⼒。
③ Redis 集群服务
Redis 集群(Redis Cluster)是 Redis 多机运⾏最完美的终极⽅案,它是 Redis 3.0 之后推出的服务, 它的出现可以让我们完全抛弃主从同步和哨兵模式来实现 Redis 多机运⾏。
分布式缓存 Redis
从上图可以看出 Redis 的主从同步只能有⼀个主节点,⽽ Redis Cluster 可以拥有⽆数个主从节点,因此 Redis Cluster 拥有更强⼤的平⾏扩展能⼒,也就是说当 Redis Cluster 拥有两个主从节点时,从理论上 来讲 Redis 的性能相⽐于单机服务来说性能提升了 2 倍。