文章目录
缓存分类:
- 进程级缓存:集合
- 分布式缓存:Redis、Memcached、Ehcache
8.1 分布式缓存介绍
8.2 Ehcache、Memcached
详情请阅读《Offer来了(原理篇)》。
8.3 Redis的原理及应用
- 数据类型:String(字符串)、Hash(散列)、List(列表)、Set(集合)、ZSet(有序集合)、Bitmap(位图)、HyperLogLog(超级日志)、Geospatial(地理空间)
- 支持:分布式事务、数据持久化、数据分片、复制、Lua脚本、LRU驱动事件
- 高可用性(High Availability):Redis哨兵(Sentinel)模式、集群模式(Cluster)
8.3.1 Redis的原理
1.Redis的数据类型
(1)String:Redis String类型的值最大能存储 512MB数据。
(2)Hash:Redis Hash是一个键值(key->value)对集合。
(3)List:Redis List是简单的字符串双向链表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可存储 2^31-1(4 294 967 295≈4亿多)个元素。
(4)Set:Set是String类型的无序集合。集合是通过散列表实现的,所以添加、删除、查找的复杂度都是O(1)。
(5)ZSet:Redis ZSet和Set一样也是String类型元素的集合,且不允许有重复的成员,不同的是,每个元素都会关联一个double类型的分数。Redis正是通过分数来为集合中的成员进行从小到大的排序的。
(6)Bitmap:通过操作二进制位记录数据。
(7)HyperLogLog:被用于估计一个Set中元素数量的概率性的数据结构。
(8)Geospatial:用于地理空间关系计算。
2.Redis管道
Redis的管道技术指在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
管道技术能减少客户端和服务器交互的次数,将客户端的请求批量发送给服务器,服务器针对批量数据分别查询并统一回复,能显著提高Redis的性能。
Redis管道技术基于Spring Boot的使用如下:
3.Redis的事务
满足:隔离性、持久性;不满足:原子性、一致性。
Redis支持分布式事务,一次执行多个命令,序列化地顺序执行。
事务在执行过程中,不会被其他客户端发送来的命令请求打断。服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令。
Redis的事务操作分为开启事务、命令入队列、执行事务三个阶段。
- 事务开启:客户端执行Multi命令开启事务。
- 提交请求:客户端提交命令到事务。
- 任务入队列:Redis将客户端请求放入事务队列中等待执行。
- 入队状态反馈:服务器返回QURUD,表示命令已被放入事务队列。
- 执行命令:客户端通过Exec执行事务。
- 事务执行错误:在Redis事务中如果某条命令执行错误,则其他命令会继续执行,不会回滚。可以通过Watch监控事务执行的状态并处理命令执行错误的异常情况。
- 执行结果反馈:服务器向客户端返回事务执行的结果。
Redis事务基于Spring Boot的使用如下:
4.Redis发布、订阅
Redis发布、订阅是一种消息通信模式:发送者(Pub)向频道(Channel)发送消息,订阅者(Sub)接收频道上的消息。Redis客户端可以订阅任意数量的频道,发送者也可以向任意频道发送数据。
5.Redis集群数据复制的原理
Redis提供了复制功能,可以实现在主数据库(Master)中的数据更新后,自动将更新的数据同步到从数据库(Slave)。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
- 一个从数据库在启动后,会向主数据库发送SYNC命令。
- 主数据库在接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。在该持久化过程中会生成一个.rdb快照文件。
- 在主数据库快照执行完成后,Redis会将快照文件和所有缓存的命令以.rdb快照文件的形式发送给从数据库。
- 从数据库收到主数据库的.rdb快照文件后,载入该快照文件到本地。
- 从数据库执行载入后的.rdb快照文件,将数据写入内存中。以上过程被称为复制初始化。
- 在复制初始化结束后,主数据库在每次收到写命令时都会将命令同步给从数据库,从而保证主从数据库的数据一致。
在Redis中开启复制功能时需要在从数据库配置文件中加入如下配置,对主数据库无须进行任何配置:
6.Redis的持久化
- RDB(Redis DataBase):RDB在指定的时间间隔内对数据进行快照存储。RDB的特点在于:文件格式紧凑,方便进行数据传输和数据恢复;在保存.rdb快照文件时父进程会fork出一个子进程,由子进程完成具体的持久化工作,所以可以最大化Redis的性能;同时,与AOF相比,在恢复大的数据集时会更快一些。
- AOF(Append Of Flie):AOF记录对服务器的每次写操作,在Redis重启时会重放这些命令来恢复原数据。AOF命令以Redis协议追加和保存每次写操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。AOF的特点有:可以使用不同的fsync策略(无fsync、每秒fsync、每次写的时候fsync),只有某些操作追加命令到文件中,操作效率高;同时,AOF文件是日志的格式,更容易被操作。
7.Redis的集群模式及工作原理
(1)主从模式:所有的写请求都被发送到主数据库上,再由主数据库将数据同步到从数据库上。主数据库主要用于执行写操作和数据同步,从数据库主要用于执行读操作缓解系统的读压力。
(2)哨兵模式:在主从模式上添加了一个哨兵的角色来监控集群的运行状态。哨兵通过发送命令让Redis服务器返回其运行状态。哨兵是一个独立运行的进程,在监测到Master宕机时会自动将Slave切换成Master,然后通过发布与订阅模式通知其他从服务器修改配置文件,完成主备热切。
(3)集群模式:Redis集群实现了在多个Redis节点之间进行数据分片和数据复制。基于Redis集群的数据自动分片能力,我们能够方便地对Redis集群进行横向扩展,以提高Redis集群的吞吐量。基于Redis集群的数据复制能力,在集群中的一部分节点失效或者无法进行通信时,Redis仍然可以基于副本数据对外提供服务,这提高了集群的可用性。
Redis集群模式:
- 所有Redis节点彼此都通过PING-PONG 机制互联,内部使用二进制协议优化传输速度和带宽。
- 在集群中超过半数的节点检测到某个节点Fail后将该节点设置为Fail状态。
- 客户端与Redis节点直连,客户端连接集群中任何一个可用节点即可对集群进行操作。
- Redis-Cluster把所有的物理节点都映射到0~16383的slot(槽)上,Cluster负责维护每个节点上数据槽的分配。Redis的具体数据分配策略为:在Redis集群中内置了16384个散列槽;在需要在Redis集群中放置一个Key-Value时,Redis会先对Key使用CRC16 算法算出一个结果,然后把结果对 16384 求余数,这样每个Key都会对应一个编号为0~16383的散列槽;Redis会根据节点的数量大致均等地将散列槽映射到不同的节点。
8.3.2 Redis的应用
8.4 分布式缓存设计的核心问题
8.4.1 缓存预热
启动加载、定时加载。
8.4.2 缓存更新
定时更新、过期更新、读请求更新、写请求更新。
8.4.3 缓存淘汰策略
FIFO(First In First Out,先进先出)、LFU(Least Frequently Used,最少使用)、LRU(Least Recently Used,最久不用)。
8.4.4 缓存雪崩
请求加锁、设置不同的时效时间、失效更新。
8.4.5 缓存穿透
- 布隆过滤器:指将所有可能存在的数据都映射到一个足够大的Bitmap中,在用户发起请求时首先经过布隆过滤器的拦截,一个一定不存在的数据会被这个布隆过滤器拦截,从而避免对底层存储系统带来查询上的压力。
- cache null策略:指如果一个查询返回的结果为null(可能是数据不存在,也可能是系统故障),我们仍然缓存这个null结果,但它的过期时间会很短,通常不超过 5 分钟;在用户再次请求该数据时直接返回null,而不会继续访问数据库,从而有效保障数据库的安全。其实cache null策略的核心原理是:在缓存中记录一个短暂的(数据过期时间内)数据在系统中是否存在的状态,如果不存在,则直接返回null,不再查询数据库,从而避免缓存穿透到数据库上。
8.4.6 缓存降级
- 写降级:在写请求增大时,可以只进行Cache的更新,然后将数据异步更新到数据库中,保证最终一致性即可,即将写请求从数据库降级为Cache。
- 读降级:在数据库服务负载过高或数据库系统故障时,可以只对Cache进行读取并将结果返回给用户,在数据库服务正常后再去查询数据库,即将读请求从数据库降级为Cache。这种方式适用于对数据实时性要求不高的场景,保障了在系统发生故障的情况下用户依然能够访问到数据,只是访问到的数据相对有延迟。