1 Redis 是什么
1.1 定义
Redis
是一种开源的、基于内存的数据结构存储系统,可以用作数据库、缓存、消息队列等。它支持多种数据结构,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)、位图(Bitmaps)、HyperLogLogs、地理空间索引(Geospatial Indexes)等。Redis 的高性能和丰富的数据结构使其在分布式系统中广泛应用。
总结:
从官方的解释,我们知道 Redis 是一个内存数据库且支持多种数据结构
从经验的角度,我们知道 Redis 常用作缓存,排行榜
1.2 特性
在深入探讨Redis
之前,我们首先了解一些Redis
特性或者说一些核心概念:
- 键值存储:Redis 是一种键值存储系统,将数据以键值对的形式存储。这种简单的数据结构使得 Redis 能够快速检索数据。
- 内存存储:Redis 将数据存储在内存中,因此可以提供极快的读写速度,但同时也受限于可用内存的大小。
- 持久性:Redis 支持将数据持久化到磁盘,以便在系统重启后能够恢复数据。
- 单线程:Redis 采用单线程模型,每次只处理一个请求。然而,得益于高效的事件驱动机制,Redis 仍然能够实现高并发处理。
1.3 功能概览
这张图引用自博文 《多图深入理解 Redis》。该图清晰概括了 Redis 提供的功能及其应用场景,帮助我们更好地理解 Redis 的强大之处。
2 Centos7 基于Docker 启动 Redis
我个人的学习方式是理论结合实践,因此在学习一门新知识时,通常会先搭建一个最简单的测试环境,边学边实践,以加深理解和记忆。
关于基于 Docker 的搭建教程,网上已经有很多资源,我也是参考了一些教程来完成搭建。在此推荐一篇我使用过的教程:《CentOS7 使用 Docker 安装 Redis 图文教程》。
进入redis-cli:
docker exec -it redis redis-cli
输入info
验证下:
# 有设置密码的话要先认证下,""内填写启动时设置的密码
$ auth "xxxx"
$ info
3 详解常见数据类型
redis 命令手册大全
redis 命令参考大全
3.1 String(字符串)
3.1.1 介绍
String
是 Redis
中最简单同时也是最常用的一个数据类型。
String
是一种二进制安全的数据类型,可以用来存储任何类型的数据。
3.1.2 常用命令
命令 | 描述 |
---|---|
SET key value | 设置指定key的值 |
GET key | 获取指定key的值 |
MSET key1 value1 key2 value2 | 批量设置key的值 |
MGET key1 key2 | 批量获取key的值 |
SETNX key value | 只有在 key 不存在时设置 |
INCR key | 将key中存储的数值+1 |
INCRBY key 2 | 将key种存储数值+2 |
DECR key | 将key中存储的数值-1 |
DECRBY key 2 | 将key中存储的数值-2 |
STRLEN key | 返回key存储字符串长度 |
EXISTS key | 判断key是否存在 |
DEL key | 删除key |
APPEND key value | 将 value 追加到 key 原来的值的末尾 |
EXPIRE key seconds | 给key设置过期时间 |
3.1.3 实践
、
3.1.4 应用场景
- 缓存数据: 用于缓存数据库查询结果、API 响应、网页内容等数据,以减少对后端数据库或服务的访问次数,提升系统性能。
- 计数器: 支持原子性的自增 (
INCR
)、自减 (DECR
) 操作,可以用来实现简单的计数器功能。 - 分布式锁: 利用
SETNX key value
命令可以实现一个最简易的分布式锁,不过集群版本下会存在不少问题,不建议直接使用。 - 会话管理: 将用户的会话信息(如登录状态、购物车数据等)存储为
string
类型,利用 Redis 的过期机制自动管理会话的有效期。 - 分布式系统唯一 ID 生成: 通过 Redis 的自增操作,可以生成全局唯一的 ID,用于分布式系统中的数据标识。
3.2 List(列表)
3.2.1 介绍
在 Redis
中,list
是一个双向链表。每个 list
可以存储多个有序的字符串元素,支持从两端进行高效的插入和删除操作。
3.2.2 常用命令
命令 | 描述 |
---|---|
LINDEX key index | 通过索引获取列表中的元素 |
LINSERT key BEFORE|AFTER pivot value | 在列表的元素前或者后插入元素 |
LLEN key | 获取列表长度 |
LPOP key | 移出并获取列表的第一个元素 |
LPUSH key value | 将一个或多个值插入到列表头部 |
LRANGE key start stop | 获取列表指定范围内的元素 |
LREM key count value | 移除列表元素 |
RPOP key | 移除并获取列表最后一个元素 |
RPUSH key value | 在列表中添加一个或多个值 |
BLPOP key timeout | 移出并获取列表的第一个元素LPOP命令的阻塞版本 |
BRPOP key timeout | 移出并获取列表的最后一个元素BPOP命令的阻塞版本 |
3.2.3 实践
通过LPUSH
和RPOP
实现队列(先进先出)
通过LPUSH
和LPOP
实现栈(先进后出)
3.2.4 应用场景
- 消息队列: 可以用作简单的消息队列,支持从一端推送消息,从另一端消费消息。通过
BLPOP
或BRPOP
命令,还可以实现阻塞式的消息队列。不过和专业的消息队列相比,还是有很多欠缺的地方比如消息丢失和堆积问题。生产环境我们一般用RabbitMQ
这种比较专业的消息中间件。 - 社交媒体时间线: 可以用于存储有序的内容,例如社交媒体的时间线、留言板或评论系统的内容列表。
- 分页存储: 将大量数据存储在
list
中,通过索引实现分页读取。
3.3 Hash(哈希)
3.3.1 介绍
hash
数据类型是一个非常适合存储对象类型数据的结构。它可以将多个键值对存储在一个集合中,这些键值对可以表示对象的属性和值。
3.3.2 常用命令
命令 | 描述 |
---|---|
HDEL key field | 用于删除哈希表中一个或多个字段 |
HEXISTS key field | 用于判断哈希表中字段是否存在 |
HGET key field | 获取存储在哈希表中指定字段的值 |
HGETALL key | 获取在哈希表中指定 key 的所有字段和值 |
HINCRBY key field increment | 为存储在 key 中的哈希表指定字段做整数增量运算 |
HKEYS key | 获取存储在 key 中的哈希表的所有字段 |
HLEN key | 获取存储在 key 中的哈希表的字段数量 |
HSET key field value | 用于设置存储在 key 中的哈希表字段的值 |
HVALS key | 用于获取哈希表中的所有值 |
3.3.3 实践
3.3.4 应用场景
-
对象属性存储: 在需要存储对象属性的场景中,可以将对象的各个属性以字段形式存储在
hash
中,从而实现高效的读取和修改操作。譬如对于一个商品,可以将商品的名称、价格、库存等属性分别存储在
hash
的字段中,并通过HGET
、HSET
操作快速获取或更新这些属性。
3.4 Set(集合)
3.4.1 介绍
set
是一种无序的集合数据结构,用于存储不重复的字符串元素。set
提供了丰富的集合操作,如求交集、并集、差集等,非常适合用来处理关系性数据。
3.4.2 常用命令
命令 | 描述 |
---|---|
SADD key member | 向集合添加一个或多个成员 |
SCARD key | 获取集合的成员数 |
SDIFF key key1 | 返回给定所有集合的差集 |
SINTER key key1 | 返回给定所有集合的交集 |
SISMEMBER key member | 判断 member 元素是否是集合 key 的成员 |
SMEMBERS key | 返回集合中的所有成员 |
SMOVE source destination member | 将 member 元素从 source 集合移动到 destination 集合 |
SPOP key | 移除并返回集合中的一个随机元素 |
SRANDMEMBER key [count] | 返回集合中一个或多个随机数 |
SREM key member | 移除集合中一个或多个成员 |
SUNION key key1 | 返回所有给定集合的并集 |
SSCAN key cursor | 迭代集合中的元素 |
3.4.3 实践
3.4.4 应用场景
- 需要获取多个数据源交集、并集和差集的场景: 共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等场景。
- 抽奖系统:
set
非常适合用于抽奖活动的参与者管理,可以确保每个用户只能参与一次,并且能够从中随机选取获奖者。
3.5 Sortedset(有序集合)
3.5.1 介绍
(Sorted Set
)是一个兼具集合与排序特性的数据结构。它不仅能够保证集合中元素的唯一性,还能够为每个元素关联一个评分(score
),并根据评分对元素进行排序。
3.5.2 常用命令
命令 | 描述 |
---|---|
ZADD key score member | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD key | 获取有序集合的成员数 |
ZINCRBY key increment member | 有序集合中对指定成员的分数加上增量 increment |
ZRANGE key start stop | 通过索引区间返回有序集合成指定区间内的成员 |
ZRANGEBYSCORE key min max | 通过分数返回有序集合指定区间内的成员 |
ZRANK key member | 返回有序集合中指定成员的索引 |
ZREM key member | 移除有序集合中的一个或多个成员 |
ZREMRANGEBYRANK key start stop | 移除有序集合中给定的排名区间的所有成员 |
ZREMRANGEBYSCORE key min max | 移除有序集合中给定的分数区间的所有成员 |
ZREVRANGE key start stop | 返回有序集中指定区间内的成员,通过索引,分数从高到底 |
ZREVRANGEBYSCORE key min max | 返回有序集中指定分数区间内的成员,分数从高到低排序 |
ZREVRANK key member | 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
ZSCORE key member | 返回有序集中,成员的分数值 |
3.5.3 实践
3.5.4 应用场景
-
排行榜:
Sorted Set
非常适合用于实现各种排行榜系统,如游戏积分排行榜、网站活跃度排行榜等。譬如在游戏中,使用
ZADD
为每个玩家添加或更新分数,通过ZRANGE
获取前 N 名玩家的排行榜。 -
延时队列: 可以用于实现延时队列或定时任务调度,根据任务的执行时间作为
score
来排序,按时取出和执行任务。譬如将任务的执行时间戳作为
score
存入 ,通过ZRANGEBYSCORE
获取到期需要执行的任务。 -
游戏匹配系统: 将玩家的等级作为
score
存储,通过ZRANGEBYSCORE
匹配相似等级的玩家进行对战。
4 持久化
Redis
作为内存数据库,提供了多种持久化机制,以确保数据在服务器重启或发生故障时不会丢失。主要的持久化方式包括RDB
、AOF
,以及混合持久化。
4.1 RDB
4.1.1 概述
RDB
是通过生成数据快照的方式将内存中的数据持久化到磁盘。Redis
会在指定的时间间隔或满足一定条件时,生成数据快照并将其保存为二进制文件(.rdb
)。
4.1.2 工作流程
Redis
会在后台执行 RDB
保存操作,并创建一个新的子进程(fork)。子进程将内存中的数据快照写入一个临时文件,待写入完成后再将临时文件替换为新的 RDB
文件。
4.1.3 触发持久化方式
手动出发:
- save:
save
命令会阻塞Redis
服务器进程,直到RDB
文件创建完成。在此期间,服务器无法处理任何命令请求。 - bgsave:
bgsave
命令通过fork
一个子进程在后台生成快照文件,不会阻塞Redis
服务器,服务器主进程(父进程)可以继续处理命令请求。
自动方式:
通过在服务器配置文件中设置 save
选项,可以让 Redis 自动定期执行 bgsave
操作。其本质仍然是通过 bgsave
命令来实现定时快照。
save 3600 1 # 3600秒内如果超过1个key被修改则生成 RDB
save 300 100 # 300秒内如果超过100个key被修改则生成 RDB
save 60 10000 # 60秒内如果超过10000个key被修改则生成 RDB
4.1.4 写时复制技术原理
在 Redis
中,写时复制技术主要用于 RDB
快照的生成以及 AOF
文件的重写。
工作原理:
- 通过
fork
创建一个子进程,这时父子进程是共享相同的数据副本,这种共享机制能够避免直接复制整个内存空间,从而节省内存和提高效率。 - 当父进程需要修改某个内存页面时,写时复制机制会触发。操作系统会先为该内存页面创建一个副本,然后将修改操作应用到这个副本上。子进程继续使用原来的页面,而父进程则使用新的副本。这一过程确保了父子进程的内存数据彼此独立,不会互相影响。
- 子进程可以安全地生成
RDB
快照或重写AOF
文件,而父进程则可以继续处理客户端请求。在整个过程中,父子进程在内存上独立操作,且不会对彼此产生干扰。
优点:
- 节省内存:通过共享内存页面,写时复制技术避免了不必要的内存复制,节省了大量内存资源。
- 数据一致性:写时复制确保了父进程和子进程的数据独立性,即使在快照生成或日志重写期间,也能够保持数据的一致性。
缺点:
- 内存开销:如果在快照或重写期间,父进程修改了大量数据,则会触发大量的写时复制操作,可能导致内存开销显著增加。
4.1.5 RDB 配置详解
-
save
: 定义 Redis 在多长时间内发生多少次写操作时触发一次 RDB 快照保存。save <seconds> <changes> save 900 1 # 900秒内至少发生了一次写操作,则触发一次快照内存
-
stop-writes-on-bgsave-error
: 该选项用于控制在 RDB 持久化过程中如果发生错误,Redis 是否应当停止接受写操作。默认值为yes
,以确保数据的一致性和持久性。stop-writes-on-bgsave-error yes/no yes:快照失败时,redis会停止处理写请求,防止数据进一步损坏 no:快照失败时,redis继续处理写请求,但是会记录错误日志
-
rdbcompression
: 此选项用于控制 RDB 文件是否采用 LZF 压缩。默认值为yes
。 -
rdbchecksum
: 该选项用于控制 Redis 在保存 RDB 文件时是否进行数据校验和(checksum)。默认值为yes
,推荐启用以确保数据完整性。yes
:Redis 会在生成 RDB 文件时计算校验和,并在加载 RDB 文件时验证数据的完整性,确保文件没有损坏。no
:不进行校验和计算,RDB 文件生成和加载速度更快,但无法检测到文件损坏。 -
dbfilename
: 指定生成的 RDB 文件的文件名。默认文件名为dump.rdb
。你可以根据需要更改文件名。dbfilename dump.rdb
-
dir
: 指定 RDB 文件的保存目录。dir /var/lib/redis/
-
rdb-del-sync-files
: 使用fsync
同步写入 RDB 文件后是否删除旧的 RDB 文件。默认值为yes
。
4.1.6 优缺点
优点:
- 高效性:RDB 文件是二进制文件,加载速度非常快。
- 节省空间:RDB 文件占用空间较小,便于备份和复制。
- 快速恢复:从 RDB 文件恢复数据的速度很快,适合大规模数据集。
缺点:
- 数据持久化不及时:由于 RDB 是周期性保存,如果 Redis 异常退出,可能会丢失最近一次快照之后的数据。
- 开销较大:RDB 持久化需要 fork 子进程,会占用 CPU 和内存资源,尤其是大数据集情况下。
4.2 AOF
4.2.1 概述
AOF 通过记录每个写操作的日志,将这些日志以追加的方式写入磁盘,从而实现数据的持久化。当Redis服务器重新启动时,可以通过重新执行 AOF 中的命令来恢复服务器的状态。
4.2.2 工作流程
4.2.3 同步策略
AOF 缓存区同步至 AOF 文件,这一过程由名为 flushAppendonlyFile
的函数完成。
而 flushAppendOnlyFile
函数的行为由服务器配置文件的 appendfsync
选项来决定,该参数有以下三个选项:
always
: 每次写操作都同步到磁盘,最安全但性能较低。everysec
: 每秒同步一次(推荐),在性能和安全之间取得平衡。no
: 不进行同步,由操作系统决定何时写入磁盘,性能最好但可能丢失数据。
4.2.4 AOF重写
AOF 重写,可以看作是对 AOF文件 进行的一次精简操作。它的目的是减少AOF文件的大小,并去除那些冗余的、不再必要的命令,使得该文件只包含恢复当前数据集所需的最小命令集。
AOF重写缓冲区:
AOF 重写缓冲区用于在 Redis 进行 AOF 重写时,记录主进程在重写期间处理的所有写操作。这确保了在 AOF 文件重写过程中生成的 AOF 文件不会丢失任何写操作。AOF 重写缓冲区是为了在 AOF 重写过程中保持数据一致性而特别设计的。
4.2.5 AOF配置详解
-
appendonly
: 此选项用于开启或关闭 AOF 持久化机制。默认值:no
-
appendfilename
: 用于指定 AOF 文件的文件名。默认值:appendonly.aof
。可以根据需要更改文件名。appendfilename "appendonly.aof"
-
appendfsync
: 用于控制 Redis 将 AOF 缓冲区的数据同步(fsync
)到磁盘的频率。appendfsync always/everysec/no
-
no-appendfsync-on-rewrite
: 控制在 AOF 文件重写过程中,是否暂停fsync
操作。默认值:no
。在需要更高性能且可容忍一定数据丢失的场景下,可以设置为yes
。 -
auto-aof-rewrite-percentage
: 控制 AOF 文件的自动重写。当 AOF 文件的大小达到上一次重写后的指定百分比时,Redis 会自动触发重写操作。默认值:100
,可以根据实际情况调整。 -
auto-aof-rewrite-min-size
: 指定触发 AOF 文件自动重写的最小大小。即使 AOF 文件增长超过auto-aof-rewrite-percentage
指定的比例,但其大小未达到该选项指定的最小值,也不会触发重写。默认值:64mb
。 -
aof-load-truncated
: Redis 在加载 AOF 文件时,如果检测到文件末尾被截断,是否继续加载。默认值为yes
。 -
aof-use-rdb-preamble
: AOF 文件重写时,是否使用 RDB 格式作为新 AOF 文件的开头部分。默认值为yes
。 -
aof-rewrite-incremental-fsync
: AOF 文件重写时,是否采用增量fsync
,即在写入过程中周期性地同步数据到磁盘。默认值为yes
。
4.2.6 AOF优缺点
优点:
- 不易丢数据:AOF 记录每个写操作,丢失数据的风险较低。
- 可读性强:AOF 文件是以文本形式存储的 Redis 命令,便于分析和修复。
- 数据恢复灵活:通过回放 AOF 文件,可以精确恢复到某一时刻的状态。
缺点:
- 文件较大:AOF 文件通常比 RDB 文件大得多,且随着操作增多,文件会不断增长。
- 写入性能较低:频繁写入磁盘的操作会影响性能,尤其是在
appendfsync always
模式下。 - 恢复速度较慢:恢复过程需要逐条执行日志命令,速度比直接加载 RDB 文件要慢。
4.3 混合持久化
4.3.1 概述
混合持久化是 Redis 提供的一种持久化机制,它结合了 AOF和 RDB两种持久化方式的优点,以提供更好的性能和数据安全性。这种机制通过在 AOF 文件中嵌入 RDB 快照的方式,实现了数据恢复速度与数据完整性之间的平衡。仅当 AOF 重写被触发时,混合持久化才开始发挥作用。
4.3.2 开启
aof-use-rdb-preamble yes
在进行 AOF 重写时,首先生成 RDB 快照,并将其作为新的 AOF 文件的前导部分。这种方式结合了 RDB 和 AOF 的优势,既能提供快速的数据恢复,又能确保数据的高完整性。
4.3.3 混合模式优缺点
优点: 可以说是结合了RDB和AOF的优点
- 快速恢复
- 高数据完整性
- 较小的AOF文件
缺点:
- **实现更复杂: ** 混合持久化的实现比单一的 RDB 或 AOF 复杂。
4.4 三种模式对比
持久化方式 | 数据恢复速度 | 数据完整性 | 文件大小 |
---|---|---|---|
RDB | 快 | 可能丢失更多数据。取决于同步周期 | 二进制格式,通常比 AOF 文件紧凑 |
AOF | 慢 | 高 | 时间推移会不断增大 |
混合 | 快 | 高 | 小 |
总结:
- AOF:适合对数据持久性要求高的场景,提供了更细粒度的持久化机制和更高的数据完整性,但恢数据复速度较慢,文件会随着时间推移不断增长。
- RDB:适合快速恢复和定期备份的场景,具有较高的恢复速度和紧凑的文件结构,但可能会丢失更多数据。
- 混合: 适合快速的数据恢复和高数据完整性的场景。
5 高可用之主从复制
5.1 定义
Redis
的主从复制(Master-Slave Replication
)是一种数据同步机制,通过在主节点(Master
)和从节点(Slave
)之间复制数据,实现数据的冗余备份、负载均衡,以及数据的高可用性。
- 主节点: 负责处理客户端的写(或者读)请求,并将写操作同步到从节点
- 从节点: 负责处理客户端的读请求,并将主节点发送过来的数据更新数据复制到本地
5.2 工作过程
5.2.1 初次全量同步
当从节点连接到主节点时,首先会进行一次全量同步。在这个过程中,主节点会生成一份 RDB 快照并将其发送给从节点,从节点接收快照并将其加载到自己的内存中。随后,主节点会将从快照生成到同步完成期间的所有写操作命令以增量方式发送给从节点,从节点执行这些命令以保持与主节点的数据一致。
时序图如下:
5.2.2 增量同步
在初次全量同步后,主从服务器之间会保持一个 TCP 连接,主从节点会通过命令传播机制保持增量同步。主节点执行的每一条写操作命令都会立即异步地发送给从节点,从节点收到这些命令后会执行相应操作,以保持与主节点的一致性。
5.2.3 断线重连后的同步
当从节点与主节点的连接断开(TCP连接)后重新连接时,Redis 会尝试进行部分重同步,即仅同步断开期间的增量数据。这通过 PSYNC
命令实现。如果部分重同步失败,Redis 会重新进行全量同步。
怎么知道断开前同步到哪里了呢?
在发送PSYNC
命令的时候是会携带runID
和 offset
。
runID
是每个 Redis 实例的唯一标识,当主从复制进行时,该值为 Redis 主节点实例的ID。
offset
数据同步的偏移量。
有了这两个值就能知道数据同步到哪里了。
5.3 特性
- 异步复制:Redis 的主从复制是异步的,主节点不会等待从节点的响应就立即返回客户端。这种异步机制提升了主节点的性能,但也带来了数据一致性问题,即在主节点崩溃前的一些写操作可能尚未被从节点同步。
- 读写分离:在主从架构下,读操作可以通过从节点分担,从而减轻主节点的负载。
5.4 总结
Redis 的主从复制机制为数据的高可用性、负载均衡和故障恢复提供了基础保障。但会存在数据一致性,复制延迟,需要手动切换故障等问题。
6 高可用之哨兵机制
6.1 定义
Redis 的哨兵机制(Sentinel)是用于监控 Redis 主从复制架构的工具,它不仅可以监控主节点和从节点的运行状态,还能在主节点出现故障时自动执行故障转移,将某个从节点提升为新的主节点,以确保系统的高可用性。
6.2 哨兵机制的功能
- 监控(Monitoring):哨兵会持续监控主节点和从节点的状态,通过定期向每个节点发送
PING
命令,检查节点是否处于正常工作状态。 - 配置提供(Configuration Provider):哨兵会将当前的 Redis 主节点地址提供给客户端,确保客户端始终能够连接到正确的主节点。
- 自动故障转移(Automatic Failover):当哨兵检测到主节点发生故障时,它会自动选举出一个从节点,并将其提升为新的主节点。并且将其他的从节点指向新的主节点。
- 通知(Notification):当被监控的 Redis 实例发生状态变化(如主节点下线)时,哨兵可以通过发布/订阅机制将这些变化通知给客户端或其他应用程序。
6.3 故障检测和自动切换流程
6.3.1 故障检测
主观下线:当哨兵节点连续多次 PING
主节点未得到响应时,哨兵认为主节点主观下线。
客观下线:如果多个哨兵节点通过投票认为主节点确实已经下线,则将其标记为客观下线。这一状态触发故障转移。
6.3.2 自动故障转移
- 选举领头sentinel: 基于Raft算法选举出一个哨兵节点负责执行故障转移操作。
- 选举从节点成为新的主节点: 选择一个最合适的从节点,将其提升为新的主节点。选择依据包括从节点的同步数据情况、网络延迟等。
- 重新配置: 将其他的从节点指向新的主节点。
- 通知客户端:哨兵集群更新所有配置,让客户端连接新的主节点。
6.4 总结
Redis 哨兵机制为 Redis 主从复制架构提供了自动故障检测和自动故障转移能力,显著提高了 Redis 系统的高可用性和容灾能力。但同时实现起来也变的更加复杂增加维护成本。
7 高可用之集群
7.1 定义
Redis 集群模式是 Redis 官方提供的分布式解决方案,旨在实现数据的水平扩展、高可用性和自动故障恢复。通过将数据分布在多个节点上,Redis 集群模式可以支持更大的数据量和更高的吞吐量,同时在节点故障时仍能提供持续的服务。
总结一句话如果redis的数据量不是很大,使用哨兵模式即可,如果Redis存储的数据量比较大,而且需要持续扩容,那么就需要选择集群模式。集群模式的核心是数据分片。
- 节点: Redis 集群由多个 Redis 节点组成,每个节点都是一个独立的,负责存储一部分数据,并处理相应的读写请求。
- 分片: Redis 集群采用哈希分片来分布数据。整个数据集被分成 16384 个槽位,每个键通过哈希函数映射到一个槽位。然后,槽位被分配给集群中的不同节点,从而实现数据的分布式存储。
- 其他包括主从复制、故障检测、故障转移跟哨兵机制类似。
7.2 数据分片与哈希槽
- 哈希计算: CRC16 哈希函数计算键的哈希值,并将其对 16384 取模,得到对应的槽位编号。
- 槽位分配: 集群中的每个主节点负责管理一定数量的槽位。
- 数据存储: 根据哈希槽的分配,键会存储到对应槽位所属的节点中。
7.3 集群通信
Redis 集群中的节点通过一种叫做 Gossip 协议的机制相互通信。Gossip 协议确保每个节点都能及时获得整个集群的状态信息,包括其他节点的健康状况、槽位分配和故障信息。
7.4 集群使用限制
跨槽操作限制: Redis 集群不支持跨槽的多键操作(如 MGET
、MSET
),除非这些键使用了相同的哈希标签。
线性扩展: 虽然 Redis 集群支持水平扩展,但在集群扩展时需要手动调整槽位的分布。
7.5 总结
Redis 集群模式赋予了 Redis 强大的分布式能力,支持数据的水平扩展与高可用性。通过哈希槽机制,Redis 集群能够将数据均匀地分布在多个节点上,并依靠主从复制和自动故障转移机制,确保即便在节点发生故障时也能持续提供服务。虽然集群模式增加了系统的复杂性,但对于需要高性能和大规模数据存储的场景,Redis 集群仍是一个非常有效的解决方案。
7.6 三种模式如何选择
- 小规模系统,读多写少:如果系统规模较小,且主要是读操作,可以选择 主从复制模式,通过从节点分担读负载。
- 中小型系统,高可用性要求较高:如果希望在出现故障时自动恢复服务,并且对高可用性有要求,可以选择 哨兵模式。哨兵模式既提供了高可用性,又相对易于管理。
- 大规模系统,高可用性和扩展性要求高:如果你的系统需要处理大量数据和高并发请求,并且需要高度的扩展性和高可用性, 集群模式 是最佳选择。集群模式虽然复杂,但在大规模应用中能够提供最好的性能和可靠性。
8 内存淘汰策略
Redis 的存储淘汰策略是指在 Redis 达到内存上限时,如何处理新写入的数据。由于 Redis 是内存数据库,内存资源有限,当数据量超过可用内存maxmemory
时,Redis 会根据配置的淘汰策略决定如何处理数据。
淘汰策略:
- noeviction: 当内存达到上限时,不再接受任何写入操作,返回错误。
- allkeys-lru: 在所有键中,淘汰最近最少使用的键。
- volatile-lru: 在设置了过期时间的键中,淘汰最近最少使用的键。
- allkeys-random: 在所有键中,随机淘汰一些键。
- volatile-random: 在设置了过期时间的键中,随机淘汰一些键。
- volatile-ttl: 在设置了过期时间的键中,淘汰即将过期的键。
- allkeys-lfu: 在所有键中,淘汰访问频率最低的键。
- volatile-lfu: 在设置了过期时间的键中,淘汰访问频率最低的键。
9 过期策略
Redis 的过期策略决定了在何时以及如何移除那些设置了过期时间的键。
9.1 惰性删除
描述: Redis 不会主动检查和删除过期键,而是当客户端尝试访问这些键时,Redis 才会检查它们是否已经过期。如果键已过期,则在被访问时删除并返回空值
**优点:**惰性删除的优点是对 CPU 资源影响最小,因为只在访问时才会检查过期。
缺点: 如果某些键在过期后一直没有被访问,它们会继续占用内存,直到某个时候被访问才会被删除。
总结: 对cpu友好,对内存不友好。
9.2 定期删除
描述: 周期性地随机抽取一些设置了过期时间的键,检查它们是否过期,并删除已过期的键。
优点: 定期删除可以确保在键到期后不久就被清理,从而释放内存。
缺点: 周期性的检查会消耗一定的 CPU 资源。
总结: 对内存友好,对cpu不友好。
9.3 策略选择
- 性能优先:如果系统对 CPU 性能要求较高,且可以容忍部分过期键暂时占用内存,那么可以依赖惰性删除策略。
- 内存优先:如果系统对内存利用率要求较高,需要及时释放内存,可以适当提高定期删除的频率(通过调整
hz
参数),以确保更多的过期键能及时被清理。 - 平衡策略:大多数情况下,Redis 默认的策略(惰性删除 + 定期删除)已经能够在性能与内存利用率之间取得良好的平衡。
10 Redis 为什么这么快
-
基于内存
所有的数据都存储在内存中,访问和操作数据的速度极快。
-
单线程模型
极大地减少了上下文切换的开销和并发竞争问题。在单线程模型下,所有的请求依次执行,避免了多线程环境中的锁竞争、死锁等复杂问题,从而提升了处理效率。
-
高效的数据结构
-
合理的数据编码
-
I/O多路复用
高效地处理大量客户端的连接。I/O 多路复用允许 Redis 在一个线程中同时处理多个网络连接,避免了传统同步 I/O 模型中的阻塞问题,从而实现了高效的网络通信。
-
丰富的内存淘汰策略
-
C语言实现
总结:
Redis 能够如此快速,归因于其对内存的高效利用、单线程模型、优化的数据结构、非阻塞 I/O 机制以及轻量级的协议设计等多个方面。
如果您觉得有帮助,请关注我,另公众号【小张的编程世界】,如有任何错误或建议,欢迎指出。感谢您的阅读!