SpringCloud-08 分布式缓存-Redis集群

单点Redis的问题

数据丢失问题:Redis是内存存储,服务重启可能会丢失数据

并发能力问题:单节点Redis并发能力虽然不错,但也无法满足如618这样的高并发场景

故障恢复问题:如果Redis宕机,则服务不可用,需要一种自动的故障恢复手段

存储能力问题:Redis基于内存,单节点能存储的数据量难以满足海量数据需求

利用Redis集群解决这些:

数据丢失问题:实现Redis数据持久化。
并发能力问题搭建主从集群,实现读写分离。
故障恢复问题:利用Redis哨兵,实现健康检测和自动恢复。
存储能力问题:搭建分片集群,利用插槽机制实现动态扩容

1、Redis持久化-解决数据丢失问题

1.1 RDB持久化

是什么
        RDB全称Redis Database Backup fileRedis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。
备份如何执行的

        Redis会单独创建(fork)一个子进程来进行持久化,会将数据入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失
Fork

  • Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
  • Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术
  • 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

1.1.1 执行时机

RDB持久化在四种情况下会执行:

执行save命令

save时只管保存,其它不管,全部阻塞。手动保存。不建议。

执行bgsave命令

Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。1

Redis停机时

Redis停机时会执行一次save命令,实现RDB持久化。若是宕机的话数据会丢失。

触发RDB条件时
Redis内部有触发RDB的机制,可以在redis.conf文件中找到,格式如下:

RDB的其它配置也可以在redis.conf文件中设置:

1.1.2 RDB原理

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件。

fork采用的是copy-on-write技术:

  • 当主进程执行读操作时,访问共享内存;

  • 当主进程执行写操作时,则会拷贝一份数据,执行写操作。

 

1.2 AOF持久化

AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

禁用RDB,因为要演示AOF

 因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

AOF持久化流程

(1)客户端的请求写命令会被append追加到AOF缓冲区内;
(2)AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;

AOF启动/修复/恢复

 1.3 RDB与AOF对比

AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)

2、Redis主从-解决并发能力问题

实现读写分离、性能扩展;容灾快速恢复

2.1 搭建主从架构

 具体搭建流程参考课前资料《Redis集群.md》

假设有AB两个Redis实例,如何让B作为Aslave节点?

B 节点执行命令: slaveof A IP A port

2.2 主从数据同步原理

2.2.1 全量同步

简述全量同步的流程?

slave 节点请求增量同步
master 节点判断 replid ,发现不一致,拒绝增量同步
master 将完整内存数据生成 RDB ,发送 RDB slave
slave 清空本地数据,加载 master RDB
master RDB 期间的命令记录在 repl_baklog ,并持续将 log 中的命令发送给 slave
slave 执行接收到的命令,保持与 master 之间的同步

2.2.2  增量同步

主从第一次同步是全量同步,但如果slave重启后同步,则执行增量同步

2.2.3 优化Redis主从集群

2.3 总结

简述全量同步和增量同步区别?

全量同步: master 将完整内存数据生成 RDB ,发送 RDB slave 。后续命令则记录在 repl_baklog ,逐个发送给 slave
增量同步: slave 提交自己的 offset master master 获取 repl_baklog 中从 offset 之后的命令给 slave

什么时候执行全量同步?

slave 节点第一次连接 master 节点时
slave 节点断开时间太久, repl_baklog 中的 offset 已经被覆盖时

什么时候执行增量同步?

slave 节点断开又恢复,并且在 repl_baklog 中能找到 offset

3、Redis哨兵-解决故障恢复问题

slave节点宕机恢复后可以找master节点同步数据,那master节点宕机怎么办?Redis哨兵可以解决

3.1 哨兵的作用和原理

 哨兵如何得知每个集群中的状态呢?

3.1.1 服务状态监控

Sentinel如何判断一个redis实例是否健康?

每隔 1 秒发送一次 ping 命令,如果超过一定时间没有相向则认为是主观下线
如果大多数 sentinel 都认为实例主观下线,则判定服务下线

3.1.2  选举新的master

一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:

首先会判断 slave 节点与 master 节点断开时间长短,如果超过指定值( down-after-milliseconds * 10 )则会排除该 slave 节点
然后判断 slave 节点的 slave-priority 值,越小优先级越高,如果是 0 则永不参与选举
如果 slave- prority 一样,则判断 slave 节点的 offset ,越大说明数据越新,优先级越高
最后是判断 slave 节点的运行 id 大小,越小优先级越高。

3.1.3 如何实现故障转移

故障转移步骤有哪些?

首先选定一个 slave 作为新的 master ,执行 slaveof no one
然后让所有节点都执行 slaveof master
修改故障节点配置,添加 slaveof master

3.2 搭建哨兵集群

《Redis集群.md》

3.3 RedisTemplate的哨兵模式

Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。SpringRedisTemplate底层利用lettuce实现了节点的感知和自动切换。

3.3.1 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3.3.2 application.yml中指定sentinel相关信息

spring:
  redis:
    sentinel:
      master: mymaster    # 指定master名称
      nodes:    # 指定redis-sentinel集群信息 
        - 192.168.150.101:27001
        - 192.168.150.101:27002
        - 192.168.150.101:27003

3.3.3 配置主从读写分离

@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

这里的ReadFrom是配置Redis的读取策略,是一个枚举,包括下面选择:

MASTER :从主节点读取
MASTER_PREFERRED :优先从 master 节点读取, master 不可用才读取 replica
REPLICA :从 slave replica )节点读取
REPLICA _PREFERRED :优先从 slave replica )节点读取,所有的 slave 都不可用才读取 master

4、Redis分片集群-解决存储能力问题

4.1 搭建分片集群

《Redis集群.md》

4.2 散列插槽

Redis会把每一个master节点映射到0~1638316384个插槽(hash slot)上,查看集群信息时就能看到:

数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

key 中包含 "{}" ,且“ {} ”中至少包含 1 个字符,“ {} ”中的部分是有效部分
key 中不包含“ {} ”,整个 key 都是有效部分

例如:keynum,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

Redis如何判断某个key应该在哪个实例?

16384 个插槽分配到不同的实例
根据 key 的有效部分计算哈希值,对 16384 取余
余数作为插槽,寻找插槽所在实例即可

如何将同一类数据固定的保存在同一个Redis实例?

这一类数据使用相同的有效部分,例如 key 都以 { typeId } 为前缀

4.3 集群伸缩

redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看

4.4 故障转移

自动实现

 手动实现数据迁移

案例

4.5 RedisTemplate访问分片集群

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud 是一个基于 Spring 框架的开发工具集,其中包含了许多开箱即用的组件和库,用于快速开发分布式系统。 要将 Spring CloudRedis 集成,您需要使用 Spring Data Redis 库。Spring Data Redis 提供了与 Redis 交互的 API,它是一个面向对象的 Redis 数据访问库,可以简化与 Redis集成和操作。 以下是将 Spring CloudRedis 集成的一些步骤: 1. 在 pom.xml 文件中添加 Spring Data Redis 的依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 在 application.yml 文件中添加 Redis 的配置信息: ``` spring: redis: host: your-redis-host port: your-redis-port password: your-redis-password ``` 3. 使用 @EnableCaching 注解启用 Spring 缓存,并配置 Redis 缓存管理器: ``` @Configuration @EnableCaching public class RedisCacheConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; } @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory).build(); return redisCacheManager; } } ``` 4. 在需要缓存的方法上使用 @Cacheable 注解,指定缓存的 key 和缓存的名称: ``` @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "userCache", key = "#id") public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } } ``` 通过以上步骤,您可以在 Spring Cloud 项目中集成 Redis,实现数据缓存的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值