Redis新手入门 -- 学习笔记

前言

最近小编在学习后端相关的知识,而Redis作为后端必不可少的技术栈,因此写下这篇博客记录一下新手学习的过程。过程中如有疏漏/错误,欢迎大佬在评论区指正!!

是什么?

Redis:远程字典服务,是一个开源、基于 内存 、键值对 NoSQL 数据库。 具有多种数据类型(基本数据类型和高级数据类型),同时读写速度极快,QPS 可达十万级别,并且支持持久磁盘。

为什么Redis会这么快?

  1. 由于Redis是直接存储在内存当中,IO速度比起MySQL这类存储在磁盘的数据库当然会快上很多很多。

  2. Redis 使用IO 多路复用模型 + 命令执行单线程。 单线程执行命令避免了多线程频繁上下文切换、锁竞争开销;配合非阻塞 IO 多路复用,可以用单个线程监听大量客户端连接。。

  3. Redis底层使用了多种数据结构,不同的数据结构分别进行了优化,这也是查询速度快的原因。

常见使用场景

1. 缓存: 面对一些热门,需要经常访问的数据,可以将其放在Redis中,大大加快查找速度;

2. 计数器 : 文章浏览,点赞数据,Redis原子自增命令INCR,适合统计计数,并发安全;

3. 消息队列 : 通过ListStream实现消息队列实现异步通知、简单任务削峰。

4. 限流:通过key过期+计数器,限制请求数量,防止高并发打垮后端数据库;

简单上手

Redis支持多种数据类型,包括简单类型(字符串,哈希,列表,集合等)和 复杂数据类型(hyperLoglog, 位图,位域)。下面从简单数据类型入手,先上手Redis。

String字符串

Redis中最基础的数据类型,value可以是字符串,数字,二进制,最大支持512MB。 用起来类似于Map,注意Redis是区分大小写的。

csharp 复制代码
# 设置key value
set name momo
get name

使用场景:

  1. 缓存普通对象/文本, 比如将业务数据序列化后存入string
swift 复制代码
set user:info:100 '{"id":100,"name":"xxxx"}'
  1. 高频计数器:比如阅读数,点赞数,访问次数等
arduino 复制代码
incr count  //将count+1
inceby count 10 //增长指定步长
  1. 验证码,短信码等设置过期时间
arduino 复制代码
set sms:code:13800138000 8888 EX 300

List列表

底层是双向链表,元素允许重复,左右两端增删极快;中间查询慢。

less 复制代码
lpush list:a a b c //从左边插入
rpush list:a a b c //从右边插入

lpop list:a //左边弹出
brpop list:a 30 //阻塞弹出

常用场景:

  1. 简单消息入队,rpush入队,lpop/brpop消费;brpop 实现阻塞等待。
  2. 时间线消息,比如主页展示最新XX条信息。

Hash哈希

类似HashMap,适合存储对象,key 是 redis 键,field 是对象属性,value 是属性值。(不宜存储过多信息,性能容易差

arduino 复制代码
hset user:001 name momo age 22 //设置多个字段
hmget user:100 name age //获取多个字段
hkeys user:100 //获取所有的keys
hvalues user:100 //获取所有value
  1. 存储用户对象 ,用户信息,不用序列化 JSON,局部更新。 hset user:200 username:xxx email:xxx

  2. 购物车:key = 购物车 id,field = 商品 id,value = 商品数量。

  3. AI 场景:存储会话的部分元信息,会话创建时间、模型版本。

Set集合

无序集合,元素不允许重复,底层是哈希表。支持交集、并集、差集。

go 复制代码
sadd tag:news java go python // 添加元素
smembers tag:news // 展示所有元素
sismember tag:news java //判断元素是否存在
srandmember tag:news //随机弹出一个元素
  1. 去重的业务, 比如点赞用户集合,一个用户只能点赞一次 sadd article:like:101 userId
  2. 共同好友模块,用交集快速计算出。

另外由于Set是无序的,部分场景我们可能希望这个集合按照一定顺序排列,就可以使用ZSet Sorted Set:

Set 基础上,每个成员带一个score 分数,根据 score 自动排序;元素唯一,score 可以重复。

arduino 复制代码
zadd rank 100 userA 90 userB 95 userC //给每个user加上分数
zrange rank 0 -1 withscores // 按从小到大排列
// ..支持各种类型的排列

使用场景:

  1. 排行榜(最经典):热度榜、积分榜、AI 回答点赞排行,zrevrange 拿 topN。
  2. 延时队列:score 存时间戳,轮询读取到期的数据。
  3. 权重排序,推荐系统。

Stream 消息队列

由于List 做消息队列时存在一系列缺陷:

  • 无消息确认
  • 消息丢失
  • 历史消息无法回溯

因此,reids设计了一种消息队列的可靠数据类型stream,注意stream具有一些为了可靠设计的概念:

  1. 消息ID: 格式为时间戳-序号,例如 1690000000000-0,Redis 自动生成,全局有序。
  2. 消息内容: 又是键值对格式 key field value,一条消息可以携带多个字段。
  3. 消费者组 Consumer Group : 一组共同消费一个流的客户端,实现消息分发、消息确认 ACK、故障转移。
  4. 待确认队列Peding List: 已经发给客户端,但还没有执行 XACK 确认消费成功的消息。
go 复制代码
XADD my_stream * type chat user_id 123 question "你好AI" // 添加消息XDD
XREAD BLOCK 0 STREAMS my_stream $ //读取消息
XGROUP CREATE my_stream group1 $ MKSTREAM //创建消费者组
XACK my_stream group1 1690000000000-0 //手动确认消息组执行完毕

业务场景:

  1. 异步事件队列: 比如订单创建、支付完成、发货事件
  2. 消息回溯、历史回放(可重放日志)
  3. 数据流、时间序列事件流:比如直播中的点赞,评论等行为流。

业务问题解析

缓存击穿

是什么: 缓存里某一个热点 Key 过期的瞬间,大量并发请求同时打到数据库,压垮 DB。

举个例子:比如我们设置了一个首页热门商品的缓存,当这个缓存过期时恰好有大量的请求直接访问,那就会直接到达DB,造成DB崩溃

解决思路:

1. 互斥锁

思路:key 过期后,只放行一个请求去查 DB 并回写缓存,其他请求等待重试

优点: 可靠,精准防止击穿

缺点: 可能存在死锁(设置释放时间)

2. 逻辑过期

思路:Redis 不设置 TTL 自动过期,而是在 value 里面存一个逻辑过期时间

相当于每次拿到缓存先去判断是否过期,如果过期就先将旧数据返回再去更新DB

优点:无锁、无等待、不会打崩 DB,高并发友好

缺点:会短暂返回旧数据(数据一致性弱一点)

3. 预热更新

思路:定时任务主动刷新热点缓存,不让它走到过期,比如凌晨去主动更新热门商品缓存。

优点::实现简单,没有并发排队、没有脏数据问题,流量可控

缺点: 热点流量突发时灵活性差(相当于提前预备

缓存穿透

是什么:大量不存在的key直接绕过缓存,直接访问DB。由于数据库也没有,因此也不会记录缓存,每一次都实打在DB上

解决思路:

1. 前置校验参数合法(id 不能负数、格式校验),恶意高频请求直接拦截。

2. 设置空缓存:当访问不存在时,写入一个短TTL的空缓存,后续相同请求直接返回

3. 布隆过滤器:所有合法存在的业务 id提前(比如初始化)存入布隆过滤器。 请求进来先过布隆过滤器,过滤器判定不存在的数据,直接拦截,不进缓存、不查 DB

这个奇怪的名字来自发明者:Burton Howard Bloom(伯顿・霍华德・布隆)

缓存雪崩

是什么:大量 key 同时过期,大量请求打到 DB。

1. 避免同时: 由于是某一原因导致大量key同时过期,我们可以思考让这些key的时间偏移一部分,比如给key加上随机的时间量,打散同一过期时间

2. 逻辑过期: 与上述的击穿思路一致

3. 服务限流: 面对大量的请求,肯定要限制流量,保护数据库

总结

问题 核心现象 核心现象 典型方案
缓存击穿 单个热点 key 过期,流量打DB 热点 key 到期,并发量大 分布式互斥锁、逻辑过期、定时预热
缓存雪崩 大量 key 同时过期,流量打 DB 过期时间集中 TTL 加随机值、逻辑过期、多级缓存、限流熔断
缓存穿透 不存在的数据,一直打 DB 缓存、DB 均无数据,无法命中缓存 缓存空值、布隆过滤器、参数校验

主从同步架构

Redis再强也是运行在单机服务器上,如果这台服务器挂了,Redis也就不可用了。因此,为了让Redis保证高可用和高性能,我们实际的生产场景往往会使用Redis的主从架构。

什么是主从同步: 这里我们通常指一主多从,也就是用一个主节点Master负责写操作,其余从节点Replica负责读操作。

当用户进行读取数据时,优先去访问从节点,这样子就减轻了主节点的压力。

当用户进行写操作时,访问主节点进行操作并且完成之后再同步通知到从节点去更新数据。

以上操作会导致出现少量数据不是最新的情况,比如用户改了某一项数据,当访问的是从节点的数据,还没来得及更新。但在大多数情况下,这种情况是可以被接受的。

哨兵模式

是什么: Redis的高可用方案,用来监控主从集群,当主节点挂掉时自动转移故障,将从节点推举成新的主节点。

注意: 一般哨兵模式设置的数量是3个以上,并且是奇数。是因为新的主节点是通过从节点选举选出来的,如果是双数的话可能会出现投票僵局而导致脑裂

脑裂: 原本统一的主从集群分裂成了两个独立运作的"大脑"------即同时出现两个 Master 节点,且都能接收客户端写请求的状态、

Redis持久化

Redis数据是保存在内存当中,当关机时数据就会丢失。持久化就是把数据放在磁盘当中,当重启时仍能读取数据。Redis提供两种持久化方案: RDB快照和AOF日志追加。可以单独开,也可以同时开启。

RDB

按一定的时间间隔,把内存里全量数据生成一个二进制快照文件dump.rdb,然后再将文件保存到磁盘中。相当于拍了一张照片;

好处: 文件紧凑二进制,体积小,适合备份、迁移并且恢复速度快。

坏处: 会丢失最后一次快照之后的数据并且如果复制的量比较大会阻塞线程。

AOF

记录每一条写命令 (set、hset 等),追加写入日志文件 appendonly.aof。 相当于视频录像,记录所有写操作,重启时重新执行一遍AOF里的命令恢复数据。

只记录操作,不记录数据

好处: 数据安全性好丢失数据少,文本可读出现问题可修复

坏处: 数据恢复慢且文件体积较大

总结

以上只是小编学习到Redis的一些浅层的内容,更偏向于学习Redis的理念(一方面内容实在有点多,作为前端更多是了解和学习)。 后续还会持续更新内容,创作不易,礼貌集赞🫡

相关推荐
井云AI1 小时前
vendor 资源包是什么:井云 DSH 客户端打包为什么离不开它
后端·智能体小程序
重生之我是Java开发战士2 小时前
【Spring Cloud】Nacos注册中心
后端·spring·spring cloud
程序员20072 小时前
AI 编程工具链碎片化?基于多端兼容的统一 Agent Rules 架构实践
后端
程序员20072 小时前
拒绝 AI 代码“暗度陈仓”:工程级 AI 编码边界与防护规则设计
后端
yunwei372 小时前
eBPF 教程:追踪 CUDA GPU 操作
linux·后端·性能优化
搬搬砖得了2 小时前
从“我写的”到“我懂它”——论工程师对代码的心理模型
后端
小满zs2 小时前
Go语言第十二章(通道)
后端·go
林冠宏_指尖下的幽灵3 小时前
AI发展下的后编程时代思考
前端·人工智能·后端
孙启超3 小时前
【AI开发之Rust】第 3 课:字符串与复合类型 —— 数据怎么放
开发语言·人工智能·后端·rust·llm·transformer