当前位置: 首页 > news >正文

中间件专题:Redis

1. Redis 数据结构

# String
set `key` `value`
setnx `key` `value` # 不存在才set
setex `key` `value` `ttl`
incrby `key` `increment` # 自增# Hash 哈希表
hset `key` `field` `value` `field` `value`
hget `key` `field`
hsetnx `key` `value` # 不存在才set# List  双向链表
LPUSH `key` `element1` `element2` ... # 从左侧插入一个或多个元素
LPOP `key` # 移除左侧第一个元素,没有返回null
RPUSH `key` `element1` `element2` ...
RPOP `key`
LRANGE `key` `start` `end` # 返回start到end之间的元素# Set 无序集合
SADD `key` `member1` `member2` # 添加
SREM `key` `member1` `member2` # 删除
SCARD `key` # 返回set中元素的个数
SISMEMBER `key` `membern` # 判断是否是key成员
SmemberS `key` # 查询key的所有成员
SINNER `key1` `key2` # 获取交集
SDIFF `key1` `key2` # 求差集, key1有,key2没有
SUNION `key1` `key2` # 求并集# Zset/SortedSet  ### 跳表 + Hash表, 有序集合,查询效率高
ZADD `key` `score1` `member1` `score2` `member2` ...  # 添加一个或多个元素到sorted set,如果存在更新score
ZREM `key` `member` # 删除
ZSCORE `key` `member` # 获取元素的score
ZRANK `key` `member` # 获取元素排名
ZCARD  `key` # 获取元素个数
ZCOUNT `key` `min` `max` # 求指定范围score的元素个数
ZINCRBY `key` `increment` `member` # 对指定member自增
ZRANGE `key` `min` `max` # 获取指定排名范围的元素
ZRANGEBYSCORE `key` `min` `max` # 获取指定score范围内的元素

2. Redis 线程模型

3. 缓存解决方案

3.1 缓存击穿、缓存雪崩、缓存穿透

缓存击穿 缓存雪崩 缓存穿透
定义 单个热点 key 过期时,大量并发请求瞬间击穿缓存直达数据库 大量缓存 key 同时失效或缓存服务宕机,导致请求洪涌压垮数据库 请求不存在的数据,缓存与数据库均未命中,反复穿透缓存
核心解决方案 互斥锁 1. 随机过期时间:基础 TTL + 随机偏移量
2. 多级缓存:本地缓存(Caffeine)+ 分布式缓存(Redis)
3. 熔断限流:Hystrix/Sentinel 保护数据库
1. 布隆过滤器:拦截非法请求(误判率可控)
2. 缓存空值NULL 结果短时缓存(如 5 分钟)
3. 参数校验:过滤非法 ID(如 ID≤0)

3.2 Redis 内存淘汰策略

  1. noeviction: 默认不淘汰,新增数据时直接报错
  2. volatile-TTL: 如果设置了过期时间,淘汰即将过期的数据
  3. volatile-random: 从设置了过期时间中的数据随机淘汰
  4. allkeys-random: 从所有数据中随机淘汰
  5. allkeys-lru: 在所有数据中,按照最近最少使用的数据进行淘汰
  6. volatile-lru: 在设置了过期时间中的数据,按照最近最少使用的数据进行淘汰。

3.3 全局唯一ID

全局唯一Id生成策略:

  • UUID
  • Redis自增 INCR key
  • 雪花算法
  • 数据库自增

redis自增策略:

  • 每天一个key,方便统计订单量
  • id构造是:时间戳+计数器

4. 分布式缓存

Redis 主要通过三种模式实现分布式缓存,每种模式适用于不同的场景和需求。

特性 主从复制 (Replication) 哨兵模式 (Sentinel) 集群模式 (Cluster)
核心目标 数据备份、读写分离 高可用、自动故障转移 水平扩展、高可用、数据分片
数据分布 全量复制,所有节点数据相同 全量复制,所有节点数据相同 数据分片到16384个槽,每个节点负责部分槽
高可用性 手动故障转移 自动故障转移 自动故障转移
扩展性 读扩展(添加从节点) 读扩展(添加从节点) 读写扩展(添加主节点)
适用场景 数据备份、读多写少 对可用性有要求的业务 大数据量、高并发、需水平扩展

4.1 主从模式

4.1.1 主从结构

image-20250921173351153

4.1.2 数据同步原理

(1)全量同步

  1. slave执行replicaof命令,建立连接
    1. slave请求数据同步
    2. master判断是否时第一次请求同步,是第一次请求则slave获取master数据版本信息
    3. slave保持版本信息
  2. master异步执行bgsave,生成RDB
    1. master发送RDB文件给slave
    2. slave清空本地数据,加载RDB文件
  3. master记录生成RDB后的所有命令到repl_baklog
    1. 发送repl_baklog中的命令到slave
    2. 循环同步

master如何判断slave是否是第一次来同步数据的?

slave做数据同步,必须向master声明自己的replication idoffset, master才可以判断到底需要同步哪些数据。判断是否是第一次来,只需要判断master和slave的replid是否一致即可。

Replication Id: 是数据集的标识,id一致说明是同一个数据集。每一个master都有唯一的replid, slave 则会继承master的replid。

offset: 偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完全同步时也会记录当前同步的offset。如果slave的offset小于master的offset。说明slave数据落后于master,需要更新。

(4)增量同步

  1. slave 重启
    1. slave请求数据同步
    2. 判断replid一致,回复slave:continue
  2. 去repl_baklog中获取slave offset后的数据
    1. 发送offset后的命令

repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。

image-20250921185654356

(3)主从同步优化

  • 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时写入RDB文件的磁盘IO,直接将RDB IO流直接发送给slave。
  • Redis单节点上的内存占用要太大,减少RDB导致的过多磁盘IO。
  • 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步
  • 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主从-从链式结构,减少master压力

image-20250921191806600

(4)总结

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

  • 全量同步:master将完整的内存数据生成RDB,发送RDB文件到slave。在生成RDB文件之后的命令操作,则记录在repl_baklog, 逐个发送给slave;
  • 增量同步:slave提交自己的offset到master,master获取repl_baklog中offset偏移量之后的命令给slave

什么时候执行全量同步?

  • slave初次同步
  • slave的偏移量offset超过了repl_baklog的大小

什么时候执行增量同步?

  • slave从故障中恢复并且offset在repl_baklog中能找到时

4.1.2. 哨兵模式

主从模式中slave宕机后恢复可以从master中同步数据,如果是master宕机呢?

哨兵的作用和原理

Redis 提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:

  • 监控:Sentinel会不断检查您的master和slave是否按预期工作
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也会以新的master为主,实现主从切换。
  • 通知: Sentinel充当Redis客户端的服务发现来源。当Redis集群发送故障转移时,会将最新的信息推送到Redis客户端。

image-20250921193313845

(1)服务状态监控

Sentinel基于心跳机制检测服务状态,每隔一秒向集群的每个实例发送一个ping命令:

  • 主观下线:如果某个sentinel节点发现某个实例未在规定的时间响应,则认为该实例主观下线。
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例下线,则该实例客观下线。 quorum最好超过实例数量的一半。

(2)选举master

一旦发现master故障,sentinel需要在slave中选择一个作为新的master。

  • 断开时间:首先判断slave节点与master节点断开时间的长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
  • 优先级:然后判断slave节点的slave-priority值,越小的优先级越高,如果是0则永不参与选举。
  • 偏移值offset:如果slave-priority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高。
  • 运行id:最后判断slave节点的运行id大小,越小优先级越高(运行id是redis自动生成的id,也就是说这里随机挑选一个slave作为master)

(3)故障转移

当选中了一个slave作为新的master节点之后,需要进行故障转移。

  • sentinel给备选的slave发送slaveof no one命令,让该节点成为master
  • sentinel给所有其他slave发送slaveof 192.168.2.2 7002命令,让其他slave成为新master的从节点,开始从新的master上同步数据。
  • 最后,sentinel将故障节点标记未slave,当故障节点恢复后会自动成为新master节点的slave节点。

(4)总结

  • sentinel的三个作用是什么?

    • 状态监控
    • 故障修复
    • 故障恢复通知
  • Sentinel如何判断一个redis实例是否健康?

    • 心跳机制:基于心跳机制,每隔一秒向每个实例发送一个ping命令
    • 主观判断:如果某个实例没有在规定时间内响应,则认为该节点主观下线。
    • 客观判断:如果超过指定数量的sentinel都认为该节点主观下线,则该实例客观下线。
  • 故障转移步骤有哪些?

    • master选举
    • sentinel给备选slave发送slaveof no one命令,让该节点成为master
    • sentinel给其他slave节点发送该节点的ip + 端口信息,让其他slave节点成为新master节点的从节点。
    • sentinel把故障master标记为slave,恢复后会成为新master的slave节点。

搭建哨兵集群

RedisTemplate的哨兵模式

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

  1. 在pom文件中引入redis的starter依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 在配置文件中配置sentinel信息
spring:redis:sentinel:master: mymaster # 指定master名称nodes: # 指定redis-sentinel集群信息- 192.168.56.2:27001- 192.168.56.3:27001- 192.168.56.4:27001
  1. 配置主从读写分离
@Bean
public LettuceClientConfigurationBuilderCustomer configurationBuilderCustomer(){return configBuilder -> configBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

这里ReadFrom是配置Redis的读写策略。

  • MASTER:从节点读取
  • MASTER_PREFERRED: 优先从master节点读取
  • REPLICA: 仅从slave节点读取
  • REPLICA_PREFERRED: 优先从slave节点读取

4.1.3. 分片集群模式

3.1 搭建分片集群

3.2 散列插槽

3.3 集群伸缩

3.4 故障转移

3.5 RedisTemplate访问分片集群

http://www.hskmm.com/?act=detail&tid=13312

相关文章:

  • 微信个人号开发API/文档/教程
  • 微指令控制器基本原理
  • 一个拒绝过度设计的 .NET 快速开发框架:开箱即用,专注干活
  • 个人微信号二次开发API调用、微信API接口
  • 2025.9.21+7 [未完]
  • VisualStudio-Python-工具指南-全-
  • Gevent和Subprocess问题
  • Ansible自动化运维实战 - 详解
  • 建筑行业能源管理破局:MyEMS 打造商业楼宇 “能耗可视化 + 智能调控” 方案
  • 【数据结构】双向链表 - 指南
  • 告别“能源糊涂账”:MyEMS如何帮企业把能耗数据“算明白、用到位”
  • Windows 离线环境下使用 VS Code 连接容器 Python 环境完整指南(亲测可用)
  • Macos 安装kali报错
  • 完整教程:线程、进程、协程
  • CF913G Power Substring
  • YC大佬分享的 10 个 vibe coding技巧,看完收获巨大
  • ES集群部署-EFK架构实战 - 实践
  • 《BOE解忧实验室》第四季圆满收官 以科技重塑文化生活新范式
  • 洛谷P2261 [CQOI2007] 余数求和
  • arc206 总结
  • 科研必读|提升酿酒酵母表达蛋白产量的关键技术
  • 完整教程:uniapp、devceo华为鸿蒙运行模拟器报错:未开启Hyper-V
  • 浏览器访问页面卡顿刷新页面方法
  • 完整教程:散斑深度相机原理
  • 如何用 Dify 无代码工作流实现 AI 自动化抓取与分析 LinkedIn 招聘数据
  • WSL+共享文件夹搭建zephyr工作环境
  • 如果 Spring Cloud Feign 配置了 OkHttp3 非阻塞 IO(NIO),那么还需要reactor 模型来提高性能吗
  • 数据结构-单链表基础2
  • G1垃圾回收过程
  • Trellix自动化大规模修复开源漏洞,已修补超6万个项目