目录
接上一篇:Spring学习笔记—Spring集成Redis数据缓存技术(1)
Redis集群模式
Redis集群是可以在多个Redis节点之间进行数据共享的架构。Redis集群通过分区容错(partition)来提高可用性(availability),即使集群中有一部分节点失效或者无法进行通信,集群也可以继续处理命令请求。
Redis集群特点:
(1)将数据切分到多个Redis节点。
(2)当集群中部分节点失效或者无法通讯时,整个集群仍可以处理请求。
每个Redis集群包含16384个哈希槽(hash slot),可通过计算得知每个key应该存放的具体哈希槽:key存放的哈希槽=CRC16(key)%16384。其中CRC16(key)是计算key的CRC16校验和。
Redis集群中的每个Redis节点负责处理一部分哈希槽。假设1个Redis集群包含3个Redis节点,每个节点可能处理的哈希槽如下:
(1)Redis节点A负责处理0~5500号哈希槽。
(2)Redis节点B负责处理5501~11000号哈希槽。
(3)Redis节点C负责处理11001~16384号哈希槽。
通过这种将哈希槽分布到不同Redis节点的做法使得用户可以很容易地向集群中添加或者删除Redis节点。如向Redis集群中加入节点D,只需将节点A、B和C中的部分哈希槽移动到节点D即可。
Redis集群架构
Redis集群中所有的节点彼此之间互相通信,使用二进制协议优化传输速度和带宽。集群中过半数的节点检测到某个节点失效时,集群会将这个节点标记为失败(fail)。因为Redis客户端与Redis集群中的节点直连,所以Redis客户端只要连接到集群中的任一个节点即可。
Redis集群中的一致性问题
CAP原则又称CAP定理:
指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance),三者不可兼得。
分区容错性:主从复制保证一定的分区容错性。为了使Redis集群在出现问题时仍然可以正常运行,Redis集群对节点使用了主从复制功能。即集群中的每个节点有1个Master主节点和若干个从节点。一个Redis集群有A、B和C 3个节点,当节点B下线时,整个集群将无法正常工作。如果在创建Redis集群时,为节点B创建了从节点Slave_B,那么当主节点B下线时,集群就可以将Slave_B作为新的主节点,并让其替代主节点B,这样整个集群就不会因为主节点B下线而无法正常工作,即Redis集群拥有分区容错性。
Redis集群模式下数据一致性存在一定的问题,Redis集群不保证强一致性。在Redis集群中,主从节点之间的复制是异步执行的,即主节点对命令的复制工作发生在返回命令回复给客户端之后,如果每次处理命令请求都需要等待复制操作完成,那么主节点处理命令请求的速度将极大地降低——必须在性能和一致性之间做出权衡。这种情况下会存在数据一致性问题,即集群中部分节点短时间内获取不到最新的主节点新增的数据。
Redis集群环境搭建
6个Redis节点,这6个节点会分为两种,其中3个是Master主节点,另外3个是Master主节点对应的从节点。
(1)进入Redis目录,创建一个新的目录cluster,在这个目录中创建Redis集群所需的配置文件:
mkdir cluster
(2)进入cluster目录后,将redis.conf文件复制6份,每份配置文件对应一个Redis节点:
(3)分别修改redis6001.conf~redis6006.conf文件。每个配置文件具体修改如下:
(4)由于需要启动的节点较多,可以使用Shell脚本管理。下面的命令将会创建两个Shell脚本,start-all.sh是用来启动6个Redis节点的,stop-all.sh是用来停止6个Redis节点的:
(5)执行start-all.sh脚本启动6个节点:
(6)查看6个Redis节点的运行进程。grep -ef|grep redis |grep -v grep
(7)使用启动的6个Redis节点创建Redis集群。其中“--cluster-replicas 1”表示自动为每个Master节点分配一个Slave节点。在这个案例中有6个节点,因此这个Redis集群会生成3个Master节点和3个Slave节点。
其中这一行是与用户交互的,输入yes的含义是在nodes.conf配置文件中保存更新的配置。集群启动后,生成6个nodes-6001.conf~nodes-6006.conf配置文件。
(8)执行以下命令查看当前集群的状态。
Spring集成Redis
将Redis作为缓存,可减少对数据库查询的次数,降低数据库负载。
1. 准备环境在maven项目的pom.xml文件中加入以下依赖,本例中使用Jedis实现对Redis集群的连接:
2、创建Redis配置文件redis.properties,代码如下:
3、Spring集成Redis分别将多个Redis节点配置到Redis集群中,并配置Jedis连接池 :
4、创建Service接口和实现创建BookService接口,其中含有save()方法和query()方法,代码如下:创建BookServiceImpl实现类,实现BookService接口。其中save()方法直接将Book对象持久化到数据库中。
在query()方法中,首先从Redis集群中查询对应bookId的Book对象,如果Redis缓存未命中,将从数据库中查询对应bookId的Book对象。
10. 测试代码编写单元测试,首先在book表中插入数据,然后从book表查询记录。
此时通过以下命令查询Redis集群状态,发现集群中有一个Redis节点包含了1个key,
使用以下命令查询节点127.0.0.1 6003的book_1剩余存活时间。
Redis缓存穿透
正常的缓存使用场景是,所有的查询请求先经过缓存,当缓存命中后,直接返回缓存中的数据;在缓存未命中的情况下,去数据库查询数据,并写入缓存。缓存的目的是为了尽可能将请求在缓存层处理,避免大量的请求进入存储层,以达到保护存储层的效果。
缓存穿透的含义是频繁查询根本不存在的数据,会导致缓存层和存储层都不会命中,因为这部分数据频繁查询,缓存不能有效命中,导致存储层负载加大。
解决办法:
1、缓存空对象
2. 布隆过滤器拦截
Redis缓存雪崩
缓存层承载着大量的请求,有效保护了存储层。但是如果由于缓存大量失效或者缓存整体不能提供服务,导致大量的请求到达存储层,会使存储层负载增加。
解决办法:
1. 保持缓存层的高可用性
2. 限流降级组件
3. 缓存不过期
4. 优化缓存过期时间
5. 使用互斥锁重建缓存
6. 异步重建缓存
---------------------------------------------------------------------------------------------------------------------------
ps: 以上内容整理自《Spring 5企业级开发实战》。