目录
7.3 题目 3:Redis 持久化机制有哪些?它们各自的优缺点是什么?
7.5 题目 5:Redis 有哪些数据结构?分别适用于哪些场景?
一、Redis 是什么?
Redis,全称为 Remote Dictionary Server,即远程字典服务 ,是一个开源的、基于内存的数据结构存储系统。它可以被用作数据库、缓存和消息中间件,支持多种数据结构,如字符串(String)、哈希表(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等,提供了丰富的操作命令,能对这些数据结构进行高效的读写操作。
1.1 Redis 的数据结构
-
字符串(String):最基本的数据类型,可存储字符串、整数或浮点数,应用场景包括缓存用户信息、做全局计数器等。
-
哈希表(Hash):由键值对组成的无序散列,适用于存储对象,比如可以将用户的多个属性存储为一个 Hash 结构,每个属性作为一个 field,属性值作为 value。
-
列表(List):按照插入顺序排序的字符串元素集合,支持在头部和尾部插入元素,可用作栈、队列或阻塞队列。例如实现消息队列时,生产者通过rpush往列表右侧插入消息,消费者通过brpop从列表右侧阻塞式获取消息。
-
集合(Set):无序、唯一的字符串集合,支持集合操作,如交集、并集、差集等。比如可以用来实现标签系统,一个用户可以有多个标签,多个用户的标签集合就可以进行相关的集合运算。
-
有序集合(Sorted Set):与集合类似,但每个成员都关联一个分数,用于排序,可根据分数范围进行检索。常见应用是排行榜,比如游戏中的玩家分数排行榜,通过分数来对玩家进行排序。
1.2 Redis 的特点
-
高性能:基于内存存储,读写速度极快,官方数据显示 Redis 每秒可以进行数万次甚至数十万次的读写操作,能大大提高应用程序的响应速度,减少延迟。例如在高并发的电商场景中,商品详情页的部分数据可以缓存在 Redis 中,用户快速获取数据,提升购物体验。
-
多样化的数据结构:支持上述多种数据结构,能满足不同业务场景的需求,开发者可以根据具体业务选择合适的数据结构,提高开发效率和系统性能。
-
支持事务:Redis 支持事务操作,可将一系列命令打包成一个事务,保证这些命令的原子性,要么全部执行成功,要么全部执行失败,确保数据的一致性和完整性。
-
发布订阅机制:支持发布订阅机制,可将消息发送到指定的频道,并让订阅了该频道的客户端接收到消息,实现简单的消息队列功能 ,在实时通信、消息推送等场景中有广泛应用。
-
高可用性:通过主从复制和哨兵机制,实现数据的备份和故障转移。当主节点出现故障时,哨兵会自动将从节点晋升为主节点,保证系统的可用性,提高系统的可靠性和稳定性。
-
简单易用:命令简单易懂,学习成本低,同时有丰富的客户端库和工具可供使用,方便开发者进行集成和开发。
1.3 Redis 的应用场景
-
缓存:是 Redis 最常用的场景之一,由于其高性能和低延迟,将经常访问的数据存储在 Redis 中,可显著提高应用程序的响应速度,减轻数据库压力。如网站的页面缓存、数据库查询结果缓存等。
-
会话存储:可用于存储和管理用户会话数据,在分布式系统中,能实现会话数据的共享和统一管理,保证用户在不同服务器节点间切换时会话的一致性。
-
消息队列:利用发布 / 订阅功能和列表数据结构,实现消息的发布和接收以及简单的消息队列功能,用于业务解耦、流量削峰及异步处理实时性低的业务。
-
实时排行榜:有序集合数据结构非常适合实现实时排行榜功能,将用户分数存储在有序集合中,方便对用户进行排名和排序,如游戏排行榜、视频播放量排行榜等。
-
分布式锁:原子操作和高性能使其成为实现分布式锁的理想选择,通过使用 SETNX 命令可实现简单的分布式锁,控制分布式系统中对共享资源的并发访问 ,比如在秒杀场景中,保证同一时间只有一个线程能执行秒杀操作。
-
应用程序中的计数器:原子操作使其适用于实现计数器功能,应用程序可使用 INCRBY 命令来实现递增和递减操作,如统计网站的访问量、文章的点赞数等。
-
地理位置信息存储:地理位置数据结构(Geo)可用于存储和查询地理位置信息,例如查找附近的商家、用户位置定位等 。
二、Redis 数据类型
2.1 常见数据类型
字符串(String):最基本的数据类型,能存储任何形式的字符串、整数或浮点数,最大容量为 512MB 。操作简单,支持 GET、SET、INCR、DECR 等命令,常被用于缓存用户信息、页面内容,实现计数器功能,如统计文章阅读量、点赞数,也可实现分布式锁 。比如,电商网站可以将商品的基本信息(如名称、价格)以字符串形式缓存起来,减少数据库查询次数,提高页面加载速度。
哈希(Hash):一种键值对集合,适用于存储对象,每个键可以包含多个字段,每个字段又有对应的值。操作命令包括 HSET、HGET、HDEL 等,常用于存储用户信息、配置文件等,可方便地对对象的单个属性进行操作,避免了对整个对象的序列化和反序列化。例如,在社交平台中,将用户的详细信息(如姓名、年龄、性别、个性签名等)存储为一个 Hash 结构,方便对用户信息进行管理和更新。
列表(List):基于双向链表实现,可在列表两端进行插入(LPUSH、RPUSH)和弹出(LPOP、RPOP)操作,还能获取指定范围的元素列表(LRANGE)。可实现消息队列,如生产者将消息通过 RPUSH 插入列表,消费者通过 BRPOP 从列表中阻塞式获取消息;也可用于分页展示,比如实现文章列表的分页,根据索引获取指定范围的文章。以物流系统为例,订单消息可以通过列表数据结构进行传递,保证消息的有序处理。
集合(Set):无序且元素唯一的字符串集合,支持集合运算,如 SADD(添加元素)、SREM(删除元素)、SISMEMBER(判断元素是否存在)、SMEMBERS(获取所有元素)、SINTER(交集)、SUNION(并集)、SDIFF(差集)等。常用于去重、标签系统、社交关系的处理,如统计网站的独立访客,找出用户的共同好友。例如,在音乐平台中,每个用户喜欢的音乐列表可以看作一个集合,通过集合运算可以推荐用户可能喜欢的其他音乐。
有序集合(Sorted Set):每个元素都关联一个分数(score),根据分数进行排序,元素唯一但分数可重复。支持 ZADD(添加元素)、ZRANGE(按分数范围获取元素)、ZREM(删除元素)、ZREVRANGE(按分数逆序获取元素)、ZCOUNT(统计指定分数范围内的元素个数)等操作,常用于排行榜、优先级队列等场景,如游戏中的玩家排名、任务调度系统中的任务优先级排序。以在线教育平台为例,学生的成绩排行榜可以使用有序集合来实现,根据学生的考试分数进行排序展示。
2.2 高级数据类型
HyperLogLog:一种用于基数统计的数据结构,用于估算集合中不重复元素的数量,具有内存占用小的优点,只需 12KB 内存就能计算接近 2^64 个不同元素的基数,但存在一定误差,标准误算率约为 0.81%。操作命令有 PFADD(添加元素)、PFCOUNT(计算基数)、PFMERGE(合并多个 HyperLogLog),常用于统计网站的独立访客数(UV)、广告的独立点击用户数等对准确性要求不是特别高的大规模基数统计场景。例如,在分析电商平台的每日访问用户数时,使用 HyperLogLog 可以在节省内存的情况下快速获取大致的用户数量。
Bitmap:基于字符串类型实现,可看作是一串连续的二进制数组,通过偏移量(offset)来操作每一位(0 或 1),可以用来表示某个元素的状态。操作命令包括 SETBIT(设置指定偏移量的位值)、GETBIT(获取指定偏移量的位值)、BITCOUNT(统计值为 1 的位的数量)、BITOP(对多个 Bitmap 进行位运算)等,常用于二值状态统计,如用户签到统计、判断用户登录状态、活跃用户统计等场景。例如,在一个拥有大量用户的应用中,使用 Bitmap 记录用户的签到情况,每天对应一位,0 表示未签到,1 表示已签到,能极大地节省存储空间。
Geo:Redis 3.2 版本引入的地理空间数据类型,用于存储地理位置信息,并提供基于地理位置的查询功能,如距离计算、范围查询等。操作命令包括 GEOADD(添加地理位置)、GEODIST(计算两个位置之间的距离)、GEORADIUS(以给定经纬度为中心,获取指定范围内的位置元素)、GEOHASH(获取地理位置的哈希值)等,常用于 LBS(基于位置的服务)应用,如打车应用中查找附近的车辆、外卖应用中查找附近的商家。以共享单车应用为例,通过 Geo 数据类型可以快速定位附近可租用的单车位置。
三、Redis 持久化机制
3.1 RDB 快照
RDB(Redis Database)是 Redis 默认的持久化方式 ,它通过将内存中的数据以快照的形式保存到磁盘上来实现持久化 。在指定的时间间隔内,Redis 会将当前内存中的所有数据写入到一个压缩的二进制文件(默认文件名为 dump.rdb)中,相当于给数据库拍了一张照片,记录下某个时间点的数据状态 。
3.1.1RDB 的触发方式
-
自动触发:可通过 Redis 配置文件中的 save 选项来配置自动快照,save 选项指定了在一定时间间隔内,达到一定数量的写操作后触发 RDB 快照。例如:
save 900 1 # 900秒(15分钟)内至少有1次写操作
save 300 10 # 300秒(5分钟)内至少有10次写操作
save 60 10000 # 60秒内至少有10000次写操作
只要满足上述任意一个条件,Redis 就会生成 RDB 快照。
- 手动触发:
-
SAVE 命令:会阻塞 Redis 主进程,直到 RDB 文件创建完毕,期间 Redis 不能处理其他命令,不建议在生产环境中使用。
-
BGSAVE 命令:Redis 会 fork 一个子进程来执行快照操作,主进程可以继续处理客户端请求,不会阻塞主进程,这是常用的手动触发方式 。
3.2 RDB 的优点
-
文件紧凑:RDB 文件是二进制压缩文件,体积小,占用磁盘空间少,便于传输和保存,非常适合用于备份和灾难恢复,比如可以定期将 RDB 文件复制到远程服务器进行数据备份。
-
恢复速度快:由于是完整的数据快照,在恢复数据时,直接将 RDB 文件读入内存,速度比 AOF 快得多,在大规模数据恢复场景中优势明显。
-
对性能影响小:BGSAVE 通过子进程进行快照操作,除了 fork 子进程时会有短暂阻塞外,对主进程的正常处理命令请求影响较小,能保证 Redis 的高性能。
3.3 RDB 的缺点
-
数据丢失风险:RDB 是定期执行持久化操作的,如果在两次持久化操作之间 Redis 发生故障,那么这段时间内的数据将会丢失,数据丢失的量取决于快照的频率。例如,若设置每 15 分钟进行一次 RDB 快照,在这 15 分钟内发生故障,那么这 15 分钟内的数据就会丢失 。
-
大数据集恢复慢:当数据集较大时,RDB 的加载速度可能会较慢,影响系统的恢复时间,因为需要将整个数据集从磁盘读取到内存 。
-
fork 进程开销:BGSAVE 需要 fork 子进程,当数据量很大时,fork 过程可能会比较耗时,并且 fork 时内存中的数据会被克隆一份,可能会导致内存占用瞬间增加,若服务器内存资源紧张,可能会影响其他服务的正常运行。
3.2 AOF 日志
AOF(Append Only File)是 Redis 的另一种持久化方式,它通过将写命令追加到 AOF 文件中来实现数据的持久化,就像一个操作日志,记录了 Redis 接收到的每一条写命令(包括 SET、DEL、HSET 等),以追加的方式写入到 AOF 文件中 。
3.2.1 AOF 的工作原理
当 Redis 执行一个写命令时,会将该命令以文本协议的格式追加到 AOF 文件的末尾。例如,执行SET key value命令,AOF 文件中会追加记录*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n。在 Redis 重启时,会重新执行 AOF 文件中的所有命令,将数据恢复到内存中,从而实现数据的恢复。
3.2.2 AOF 的写回策略
AOF 机