86人参与 • 2026-05-14 • Redis
redis 是一个开源的、高性能的内存数据存储系统,可以作为数据库、缓存以及消息中间件使用。它支持丰富的数据结构,如字符串、哈希、列表、集合和有序集合等,因此被广泛用于需要高性能、高并发的应用场景。redis 采用单线程模型和基于内存的存储方式,保证了非常高的读写速度。
简而言之,redis 是一个键值数据库,它通过将数据存储在内存中,以实现快速的数据访问。redis 支持丰富的功能,如持久化(将数据保存在硬盘上以防丢失)、事务处理、发布/订阅模式、lua 脚本执行等。
redis 的最大特点是它的速度极快,而这一点正是它在 web 应用、高并发系统以及分布式环境中大受欢迎的原因之一。
redis 因为其高速的读写能力和多种数据结构支持,应用场景非常广泛,常见的场景包括:
1.2.1 缓存系统
redis 最常见的应用场景就是作为缓存层。在应用中,我们常常会缓存一些查询频繁且不经常变动的数据。redis 作为缓存系统,可以极大提升数据读取速度,减轻数据库的负担。例如,网站首页的广告推荐信息、商品详情页的缓存等。
1.2.2 实时数据处理
redis 支持的数据结构非常适合实时数据处理,例如排行榜、计数器、实时消息推送等。通过 redis 的有序集合(zset),我们可以轻松实现排行榜等功能,并能实时更新排名数据。
1.2.3 消息队列
redis 提供的列表(list)和发布/订阅(pub/sub)功能,非常适合用作消息队列。在一个分布式系统中,生产者将消息推送到队列中,消费者异步处理这些消息。redis 提供的高效操作能确保消息队列处理的低延迟和高吞吐量。
1.2.4 会话管理
redis 的高效性和内存存储使它非常适合用作 会话管理(session store)。比如,在 web 应用中,用户登录时,常将用户会话信息存储在 redis 中,这样可以快速访问与更新会话信息。
1.2.5 分布式锁
redis 还可以用于实现分布式锁,通过它的 setnx 命令,可以实现保证分布式环境下任务的互斥访问。
redis 作为 nosql (对非关系型数据库的统称)数据库,与传统的关系型数据库(如 mysql 和 sqlite3)相比,有许多显著的区别。我们从几个关键维度来对比 redis 和传统数据库:
1.3.1 数据存储方式
1.3.2 数据结构支持
1.3.3 性能与可扩展性
1.3.4 查询能力
1.3.5 数据一致性
补充:acid特性
| 缩写 | 全称 | 中文名 | 作用 |
|---|---|---|---|
| a | atomicity | 原子性 | 确保事务中的所有操作要么全部执行成功,要么全部不执行 |
| c | consistency | 一致性 | 确保事务前后,数据库始终处于一致的状态 |
| i | isolation | 隔离性 | 确保并发事务之间互不干扰 |
| d | durability | 持久性 | 一旦事务提交,其修改的数据应永久保存在数据库中 |
原子性(atomicity):
一个事务中的所有操作要么全部成功,要么全部失败,不可能只执行部分操作。
举例说明:
银行转账中,从账户 a 扣钱、给账户 b 加钱,这两个操作必须绑定执行。如果只扣了 a 的钱,但没给 b 加上,那事务就是不完整的 —— 原子性就被破坏了。
一致性(consistency):
事务执行前后,数据库必须处于一致的状态,即遵守所有的约束条件(如唯一性、外键、业务规则等)。
举例说明:
继续银行转账的例子,假设两个账户总额是 10000 元,无论转多少次,只要每次事务正确执行,总额都不能改变 —— 这就体现了一致性。
隔离性(isolation):
多个事务并发执行时,彼此之间互不干扰,各自的中间状态对其他事务不可见。
举例说明:
如果两个事务同时修改同一个库存,系统必须采取机制避免数据“被多次扣减”或出现“脏读”等问题。传统数据库通过锁机制或 mvcc(多版本并发控制)实现事务隔离,支持不同的隔离级别(如 read committed、repeatable read、serializable 等)。
持久性(durability):
一旦事务提交,其对数据库的更改必须永久保存,即使系统崩溃也不会丢失数据。
举例说明:
你转账后收到“转账成功”的提示,这笔交易即使服务器此时崩溃,系统重启后也必须能恢复该记录。数据库通常通过写 wal(write-ahead log)日志、刷盘等机制来保证持久性。
1.4.1 优势
1.4.2 局限性
在 redis 中,每条数据都是一个键值对(key-value)。
key 就是数据的唯一标识符,相当于传统数据库中的主键(primary key)。它的特性如下:
keys 命令)。user:1001:name值的类型可以是多种结构,不仅仅是字符串。这是 redis 最有特色的设计。
redis 支持五大基础数据结构(以及一些高级结构,如 hyperloglog、bitmap、geo):
| 类型 | 简介 | 使用场景 | 示例命令 |
|---|---|---|---|
| 字符串(string) | 最基本的数据类型,可存储文本或二进制 | 缓存、计数器、token 存储 | set key value, incr key |
| 哈希(hash) | 键值对集合,适用于对象表示 | 存储用户信息、配置项 | hset user:1001 name zhang |
| 列表(list) | 有序链表,支持左右两端插入弹出 | 消息队列、时间线 | lpush, rpop |
| 集合(set) | 无序不重复元素集合 | 标签、好友推荐、去重 | sadd, sinter |
| 有序集合(zset) | 每个元素有一个分数,用于排序 | 排行榜、带权集合 | zadd, zrange |
redis 的强大正是因为值(value)不仅是数据,也可以是结构化的数据集合。
redis 是内存数据库,数据读写全部在内存中完成,这也是其高性能的核心原因。
【rdb】(快照)
.rdb 文件)。【aof】(append only file)
.aof)。redis 支持 rdb 和 aof 混合持久化,也可以配置成只使用其中一种。
save 或 bgsave 手动触发。[redis 内存数据]
|
|(定期快照)
v
rdb 文件 (或 aof 日志)
|
|
v
磁盘持久化文件redis 在高性能方面的设计非常值得称道,以下三点是核心:
redis 的命令处理采用单线程模型,不加锁、不阻塞,避免了线程切换开销。
客户端请求
|
v
+-----------+
| redis 主线程 |
+-----------+
|
v
处理命令(串行执行)ae_event_loop 实现事件驱动模型。+-------------+
| 客户端连接池 |
+-------------+
|
v
[ epoll 监听 socket 事件 ]
|
v
[ 有请求来了 ]
|
v
[ 主线程按序处理请求 ]
redis 完全基于内存工作,数据访问无需磁盘 i/o:
这就是 redis 快如闪电的根本原因。
+----------------+ +----------------------+
| 客户端请求 | -----> | 网络层(非阻塞 io) |
+----------------+ +----------------------+
|
v
+------------------+
| 单线程命令处理 | <- redis 主线程(串行)
+------------------+
|
+----------------+----------------+
| |
+----------------+ +--------------------+
| 内存数据结构区 | | 持久化(rdb / aof) |
+----------------+ +--------------------+
sudo apt update sudo apt install redis-server
安装完成后,可以使用以下命令启动和查看 redis 服务:
sudo systemctl start redis sudo systemctl enable redis # 开机启动 sudo systemctl status redis
默认配置文件路径为 /etc/redis/redis.conf,默认端口是 6379。
# 1. 下载源码 wget https://download.redis.io/releases/redis-7.2.4.tar.gz tar -xzf redis-7.2.4.tar.gz cd redis-7.2.4 # 2. 编译 make -j4 # 3. 可选:执行测试(需要 tcl) make test # 4. 安装 sudo make install
安装后,会将 redis-server、redis-cli 等可执行文件放到 /usr/local/bin/。
你可以直接运行:
redis-server # 启动服务 redis-cli # 客户端命令行
配置文件可在源码目录中找到:redis.conf,你可以复制到合适位置如 /etc/redis/。
redis 的核心配置文件是:redis.conf,默认位置因安装方式而异。
你可以使用:
redis-server /redis.conf的path
来自定义启动 redis。
| 配置项 | 作用 | 示例 |
|---|---|---|
port | 监听端口 | port 6379 |
bind | 限制绑定的 ip | bind 127.0.0.1 |
requirepass | 设置访问密码 | requirepass yourpassword |
dir | 持久化文件保存目录 | dir /var/lib/redis/ |
dbfilename | rdb 文件名 | dbfilename dump.rdb |
appendonly | 是否开启 aof | appendonly yes |
appendfilename | aof 文件名 | appendfilename "appendonly.aof" |
maxmemory | 限制最大内存 | maxmemory 256mb |
maxmemory-policy | 内存淘汰策略 | allkeys-lru、volatile-ttl |
绑定指定 ip:
bind 127.0.0.1 # 限制本地访问
设置访问密码:要求所有客户端在执行任何命令前必须提供这个密码
requirepass mystrongpassword 客户端连接时输入上述步骤设置的密码: redis-cli -a mystrongpassword
关闭危险命令(如 flushall):
rename-command flushall "" rename-command flushdb ""
内存限制(适用于缓存场景):
# 设置 redis 使用的最大内存为 512mb,超出后会触发内存淘汰策略 maxmemory 512mb # 设置内存淘汰策略为 allkeys-lru(从所有键中挑选最近最少使用的键淘汰) maxmemory-policy allkeys-lru
持久化控制(视业务需求选择):
关闭持久化(仅做缓存):
save "" appendonly no
开启 aof 且设置为每秒同步:
appendonly yes appendfsync everysec
redis 中最基本的数据类型,类似于传统数据库中的单个字段值。
redis 的字符串结构是:
key -> "value"
常用命令:
set key value:设置键值。get key:获取键值。del key:删除键。incr key / decr key:对数值型字符串进行自增/自减操作。incrby key amount / decrby key amount:按指定步长增减。append key value:向原字符串追加内容。strlen key:返回字符串长度。mset key1 val1 key2 val2 ...:批量设置多个键值对。mget key1 key2 ...:批量获取多个键值。setnx key value:仅当 key 不存在时设置。setex key seconds value:设置值并指定过期时间。示例:
## 设置与获取 set name "alice" # 返回: ok # 当前键值对为: # name -> "alice" get name # 返回: "alice" # 说明: "name" 键的值为 "alice" ## 批量操作 mset age 25 city "shanghai" # 返回: ok # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" mget name age city # 返回: # 1) "alice" # 2) "25" # 3) "shanghai" # 说明: 返回 "name", "age", "city" 键的值 ## 自增自减 set counter 10 # 返回: ok # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" # counter -> "10" incr counter # 返回: 11 # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" # counter -> "11" incrby counter 5 # 返回: 16 # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" # counter -> "16" decr counter # 返回: 15 # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" # counter -> "15" decrby counter 2 # 返回: 13 # 当前键值对为: # name -> "alice" # age -> "25" # city -> "shanghai" # counter -> "13" ## 字符串追加与长度 append name " smith" # 返回: 11 # 新字符串长度 # 当前键值对为: # name -> "alice smith" # age -> "25" # city -> "shanghai" # counter -> "13" get name # 返回: "alice smith" # 说明: "name" 键的值已更新为 "alice smith" strlen name # 返回: 11 # 说明: "name" 字段的长度为 11("alice smith") ## 设置过期键值对 setex token 60 "abc123" # 返回: ok # 当前键值对为: # name -> "alice smith" # age -> "25" # city -> "shanghai" # counter -> "13" # token -> "abc123"(将在60秒后自动过期) get token # 返回: "abc123" # 说明: "token" 键的值为 "abc123",且将在60秒后过期 ## 条件设置(键不存在时才设置) setnx city "beijing" # 返回: 0 # 因为 city 已存在,未设置成功 # 当前键值对为: # name -> "alice smith" # age -> "25" # city -> "shanghai" # counter -> "13" # token -> "abc123"(将在60秒后过期) get city # 返回: "shanghai" # 说明: "city" 键的值仍为 "shanghai" ## 最终键值状态(执行完上述命令后) name -> "alice smith" age -> "25" city -> "shanghai" counter -> "13" token -> "abc123" (将于60秒后自动失效)
哈希表用于存储对象,常用于表示用户信息、商品信息等。
redis 的哈希结构是:
key -> {
field1: value1,
field2: value2,
...
}常用命令:
hset key field value:设置字段。hget key field:获取字段值。hgetall key:获取所有字段和值。hmset key field1 val1 field2 val2 ...:一次设置多个字段(redis 4.0 后不推荐)。hmget key field1 field2 ...:一次获取多个字段。hdel key field [field ...]:删除字段。hexists key field:判断字段是否存在。hlen key:返回字段数量。hincrby key field increment:字段数值加减。hstrlen key field:字段值长度。示例:
## 设置与获取
hset user:1001 name "bob" age "30" gender "male"
# 返回: 3 # 表示新增了3个字段
# 当前哈希表 user:1001 内容为:
# user:1001 -> {
# "name": "bob",
# "age": "30",
# "gender": "male"
# }
hget user:1001 name
# 返回: "bob"
# 说明: "name" 字段值为 "bob"
## 批量设置与获取
hmset user:1001 email "bob@example.com" phone "123456789"
# 返回: ok
# 当前哈希表 user:1001 内容为:
# user:1001 -> {
# "name": "bob",
# "age": "30",
# "gender": "male",
# "email": "bob@example.com",
# "phone": "123456789"
# }
hmget user:1001 name email phone
# 返回:
# 1) "bob"
# 2) "bob@example.com"
# 3) "123456789"
# 说明: 分别返回 "name", "email", "phone" 字段的值
## 删除字段与判断字段是否存在
hdel user:1001 gender
# 返回: 1 # 成功删除1个字段
# 当前哈希表 user:1001 内容为:
# user:1001 -> {
# "name": "bob",
# "age": "30",
# "email": "bob@example.com",
# "phone": "123456789"
# }
hexists user:1001 age
# 返回: 1 # 字段 age 存在
# 说明: "age" 字段仍然存在
## 哈希结构长度信息
hlen user:1001
# 返回: 4 # 当前哈希表中还有 4 个字段
# 当前哈希表 user:1001 内容为:
# user:1001 -> {
# "name": "bob",
# "age": "30",
# "email": "bob@example.com",
# "phone": "123456789"
# }
hstrlen user:1001 name
# 返回: 3 # name 字段的字符串长度为 3("bob")
# 说明: "name" 字段的值长度为 3
## 自增字段(用于数值字段)
hincrby user:1001 age 2
# 返回: 32 # 将 age 从 30 增加到 32
# 当前哈希表 user:1001 内容为:
# user:1001 -> {
# "name": "bob",
# "age": "32",
# "email": "bob@example.com",
# "phone": "123456789"
# }
## 获取全部字段和值
hgetall user:1001
# 返回:
# 1) "name"
# 2) "bob"
# 3) "age"
# 4) "32"
# 5) "email"
# 6) "bob@example.com"
# 7) "phone"
# 8) "123456789"
# 说明: 返回所有字段和值
## 最终哈希表 user:1001 的结构如下:
{
"name": "bob",
"age": "32",
"email": "bob@example.com",
"phone": "123456789"
}列表是一种双向链表结构,支持从两端插入和弹出元素。
redis 的列表结构是:
key -> [ value1, value2, value3, ... ]
常用命令:
lpush key value [value ...] / rpush key value [value ...]:从左/右插入。lpop key / rpop key:从左/右弹出。lrange key start stop:获取指定范围元素。llen key:获取列表长度。lrem key count value:移除指定值。lset key index value:设置指定索引的值。lindex key index:获取指定索引值。ltrim key start stop:保留指定区间,删除其余元素。blpop key [key ...] timeout / brpop key [key ...] timeout:阻塞式弹出。示例:
# 插入元素 lpush tasks "task3" "task2" rpush tasks "task4" head <--> "task2" <--> "task3" <--> "task4" <--> tail # 查询 llen tasks #llen tasks 返回列表的长度,结果是 3。 lrange tasks 0 -1 #lrange tasks 0 -1 返回从索引 0 到 -1(即整个列表),结果是 ["task2", "task3", "task4"]。 lindex tasks 1 lindex tasks 1 返回索引 1 的元素,结果是 "task3"。 # 设置与移除 lset tasks 1 "task2_updated" head <--> "task2" <--> "task2_updated" <--> "task4" <--> tail lrem tasks 0 "task3" head <--> "task2" <--> "task2_updated" <--> "task4" <--> tail # 截取与弹出 ltrim tasks 0 1 head <--> "task2" <--> "task2_updated" <--> tail lpop tasks head <--> "task2_updated" <--> tail rpop tasks head <--> tail
集合用于存储不重复元素,支持集合运算。
redis 的集合结构是:
key -> {value1,value2,value3,...}常用命令:
sadd key member [member ...]:添加元素。smembers key:获取所有元素。srem key member [member ...]:删除元素。sismember key member:判断是否存在。scard key:集合元素数量。srandmember key [count]:随机返回一个或多个元素。spop key [count]:随机弹出元素。sunion key1 key2 ...:求并集。sinter key1 key2 ...:求交集。sdiff key1 key2 ...:求差集。示例:
## 添加元素
sadd tags "redis" "database" "nosql"
# 返回: 3 # 成功添加了3个新元素
# 当前集合内容(顺序可能不同):
# tags -> {
# "redis",
# "database",
# "nosql"
# }
## 再次添加重复元素
sadd tags "redis" "backend"
# 返回: 1 # 只有 "backend" 是新元素
# 当前集合内容(顺序可能不同):
# tags -> {
# "redis",
# "database",
# "nosql",
# "backend"
# }
## 查看所有成员
smembers tags
# 返回:
# 1) "redis"
# 2) "nosql"
# 3) "database"
# 4) "backend"
# (集合是无序的,顺序可能不同)
## 判断元素是否存在
sismember tags "redis"
# 返回: 1 # 表示存在
sismember tags "mysql"
# 返回: 0 # 表示不存在
## 移除元素
srem tags "nosql"
# 返回: 1 # 成功移除1个元素
# 当前集合内容(顺序可能不同):
# tags -> {
# "redis",
# "database",
# "backend"
# }
## 集合大小
scard tags
# 返回: 3
## 随机弹出一个元素
spop tags
# 返回: (例如)"backend" # 每次随机,结果可能不同
# 当前集合内容(顺序可能不同):
# tags -> {
# "redis",
# "database"
# }
## 最终集合内容
smembers tags
# 返回:
# 1) "redis"
# 2) "database"
# (假设弹出了 "backend")每个元素有一个 score,成员按照 score 自动从小到大排序。与集合(set)相比,多了一个“分数”维度,且结果是有序的。
redis 的有序集合结构是:
key -> {
member1: score1,
member2: score2,
...
}常用命令:
zadd key score member [score member ...]:添加元素。zrange key start stop [withscores] / zrevrange:按分数排序查询。zrem key member [member ...]:删除成员。zscore key member:获取某成员的分数。zrank key member / zrevrank:获取排名。zincrby key increment member:对成员分数自增。zcount key min max:统计分数在范围内的元素数量。zrangebyscore key min max:按分数范围查询。示例:
# redis 有序集合操作演示(scoreboard)
# 1. 添加与查询
zadd scoreboard 100 "alice" 150 "bob" 130 "carol"
# 返回结果:
# (integer) 3 # 成功添加 3 个成员
# redis 中有序集合 scoreboard 内容为(按 score 排序):
# scoreboard -> {
# "alice": 100,
# "carol": 130,
# "bob": 150
# }
zrange scoreboard 0 -1 withscores
# 返回结果(按 score 从小到大):
# 1) "alice"
# 2) "100"
# 3) "carol"
# 4) "130"
# 5) "bob"
# 6) "150"
zrevrange scoreboard 0 1
# 返回结果(按 score 从大到小,前两个成员):
# 1) "bob"
# 2) "carol"
# 2. 分数与排名查询
zscore scoreboard alice
# 返回结果:
# "100"
# 说明: "alice" 的分数为 100
zrank scoreboard carol
# 返回结果:
# 1
# 说明: "carol" 排名第 2(从 0 开始)
zrevrank scoreboard bob
# 返回结果:
# 0
# 说明: "bob" 在倒序中排名第 1(最高分)
# 3. 分数修改与范围查询
zincrby scoreboard 10 alice
# 返回结果:
# "110"
# 说明: "alice" 的分数已增加 10,变为 110
zrange scoreboard 0 -1 withscores
# 返回结果(按 score 从小到大):
# 1) "alice"
# 2) "110"
# 3) "carol"
# 4) "130"
# 5) "bob"
# 6) "150"
zcount scoreboard 120 160
# 返回结果:
# (integer) 2
# 说明: "scoreboard" 中分数在 120 到 160 之间的成员有 2 个("carol" 和 "bob")
zrangebyscore scoreboard 120 200
# 返回结果:
# 1) "carol"
# 2) "bob"用于管理所有键的通用命令。
常用命令:
expire key seconds:设置键过期时间。ttl key:查看剩余时间。persist key:取消过期时间。del key [key ...]:删除键。rename key newkey:重命名键。type key:查看键类型。keys pattern:通配符查询。exists key:判断键是否存在。move key db:将指定的键迁移到指定的数据库double object key:查看给定键的内部信息(包括内存占用等)# 1. expire key seconds:设置键的过期时间 set mykey "hello" # 返回: ok expire mykey 60 # 返回: 1 # 设置成功,键 mykey 将在60秒后过期 ttl mykey # 返回: 60 # 返回剩余过期时间为 60 秒 # 2. ttl key:查看剩余时间 ttl mykey # 返回: 60 # mykey 剩余过期时间 60 秒 # 3. persist key:取消过期时间 persist mykey # 返回: 1 # 表示取消了过期时间 ttl mykey # 返回: -1 # 不再有过期时间 # 4. del key [key ...]:删除一个或多个键 del mykey # 返回: 1 # 删除成功 ttl mykey # 返回: (error) no such key # 键已删除,不存在 # 5. rename key newkey:重命名键 set mykey "hello" # 返回: ok rename mykey newkey # 返回: ok # 重命名成功 get newkey # 返回: "hello" # 可以通过新键名获取相同的值 # 6. type key:查看键的类型 set mykey "hello" # 返回: ok type mykey # 返回: string # 表示 mykey 的类型是 string # 7. keys pattern:通配符查询 set user1 "alice" set user2 "bob" set admin "charlie" # 返回: ok keys user* # 返回: # 1) "user1" # 2) "user2" # 8. exists key:判断键是否存在 exists mykey # 返回: 0 # 表示 mykey 不存在 exists newkey # 返回: 1 # 表示 newkey 存在 # 9. move key db:将键迁移到指定的数据库 set mykey "hello" # 返回: ok move mykey 1 # 返回: 1 # 表示成功将 mykey 从当前数据库迁移到数据库 1 select 1 # 返回: ok get mykey # 返回: "hello" # 在数据库 1 中可以找到 `mykey` # 10. object key:查看给定键的内部信息 set mykey "hello" # 返回: ok object encoding mykey # 返回: "raw" # 返回键的编码方式 object idletime mykey # 返回: 0 # 返回 mykey 的空闲时间(单位:秒)
select index
切换 redis 数据库。redis 默认有 16 个数据库,使用索引来切换。
select 2 # 返回: ok # 选择数据库 2
flushdb
删除当前数据库中的所有键。清空当前数据库,但不会影响其他数据库中的数据。
pflushdb
异步删除当前数据库中的所有键,redis 5.0+ 引入,减少阻塞。
flushall
删除所有数据库中的所有键。执行后会清空 redis 实例中的所有数据。此命令操作不可逆。
pflushall
异步删除所有数据库中的所有键,类似于 flushall,但执行时不会阻塞其他客户端请求。
dbsize
返回当前数据库中键的数量。用于获取当前数据库中的键数量。
info [section]
获取 redis 实例的各种信息,可以指定某一部分的详细信息(如服务器、内存、客户端、持久化等)。
info # 返回: # # server # redis_version:6.2.1 # # clients # connected_clients:10 # # memory # used_memory:100000
latency latest
查看 redis 实例的最新延迟信息。
client list
返回当前所有客户端的连接信息。包括客户端的 id、连接地址、空闲时间等。
client list # 返回: # 1) id=1 addr=127.0.0.1:6379 fd=8 name= age=10 idle=5 flags=n db=0 # 2) id=2 addr=127.0.0.1:6380 fd=9 name= age=20 idle=15 flags=n db=1
client kill id
关闭指定的客户端连接。
config get parameter
获取 redis 配置参数的当前值。
config get maxmemory # 返回: # 1) "maxmemory" # 2) "0"
config set parameter value
设置 redis 配置参数的值。注意某些配置只能在启动时设置。
config set maxmemory 1024mb # 返回: ok # 将最大内存限制设置为 1024mb
config rewrite
重写 redis 配置文件,将当前的配置更新到 redis 配置文件中。适用于持久化配置更改。
config rewrite # 返回: ok # 配置文件重写成功
shutdown
关闭 redis 实例。
lastsave
返回 redis 上次成功保存数据的时间戳
redis 提供了两种主要的持久化机制:rdb(快照)持久化和aof(追加文件)持久化。此外,redis 还支持 混合持久化,即同时启用 rdb 和 aof 持久化。
rdb 是 redis 的一种持久化方式,能够在指定时间间隔内创建 redis 数据库的快照,保存在磁盘上。rdb 文件存储了 redis 数据的完整快照,能够在 redis 重启时用于数据恢复。
redis 的 rdb 快照持久化通过配置文件中的 save 指令来控制触发条件。每当 redis 发生某些变化时,它会在满足特定条件后自动保存数据。
save 配置参数示例:
save 900 1 # 在 900 秒(15分钟)内,如果有至少 1 个键被修改,则触发 rdb 快照保存 save 300 10 # 在 300 秒(5分钟)内,如果至少有 10 个键被修改,则触发 rdb 快照保存 save 60 10000 # 在 60 秒内,如果至少有 10000 个键被修改,则触发 rdb 快照保存
配置说明:
save 规则由两个数字组成,<seconds> 和 <changes>,即在 <seconds> 秒内,如果发生了至少 <changes> 次写操作,redis 会触发 rdb 快照持久化。save 900 1 表示在 900 秒(15分钟)内,如果有至少 1 个键被修改,则触发快照保存。手动触发 rdb 快照:
你也可以手动触发 rdb 快照:
bgsave
该命令会在后台创建 rdb 快照,并保存到磁盘中,允许 redis 继续响应客户端请求。
rdb 快照触发的场景:
save 配置的规则触发。bgsave 或 save 命令手动触发。rdb 恢复过程非常简单,redis 启动时会自动加载最新的 rdb 快照文件。恢复时需要注意以下几点:
dump.rdb,位于 redis 配置文件中指定的 dir 目录。dump.rdb 文件并加载它。如果找到了该文件,redis 会根据快照中的数据来恢复数据库。aof(append only file)是 redis 的另一种持久化方式,它通过记录每个写命令到一个日志文件中,以此来实现持久化。
redis 默认情况下不启用 aof 持久化,若启用 aof,redis 会将所有写命令追加到 aof 文件中。你可以在 redis 配置文件中通过设置 appendonly 参数来启用 aof。
aof 配置参数示例:
appendonly yes # 启用 aof 持久化 appendfsync everysec # 每秒同步一次 aof 文件
aof 文件的三种同步策略:
aof 恢复过程如下:
aof 恢复时的注意事项:
appendonly.aof。aof-load-truncated 配置项)。aof 重写(aof rewrite)功能,它会根据当前数据库状态生成一个新的 aof 文件,去除重复操作。redis 5.0 引入了混合持久化模式,它结合了 rdb 和 aof 的优势,既能提供数据的持久化,又能保证数据恢复时的快速性和完整性。
混合持久化工作原理
混合持久化在 rdb 快照的基础上,将 aof 文件和 rdb 文件结合。在持久化时,redis 会将数据库的快照存储在 rdb 文件中,同时将增量的写操作记录到 aof 文件中。这样做的好处是:
混合持久化启用方式:
在配置文件中,可以通过设置 appendonly 和 appendfsync 参数来启用混合持久化。redis 默认启用了这种模式:
appendonly yes # 启用 aof 持久化 appendfsync everysec # 每秒同步一次 aof 文件
混合持久化的优势
混合持久化恢复
结合了两者的优势,在每次生成 rdb 快照时,它不仅会写入 rdb 文件,还会嵌入到 aof 文件的开头,作为基准状态。随后,aof 文件会继续追加快照生成之后的写操作增量,以保证最新的数据不会丢失。再生成下一次快照时会将aof文件覆盖,并将新生成的快照继续嵌入到aof文件的开头,循环往复。这样,恢复数据时,redis 先加载嵌入的快照快速恢复大部分数据,再顺序执行快照之后的增量操作,就能完整恢复到最新状态,这样就同时兼顾恢复速度和数据安全性。
redis 提供了内建的发布/订阅消息系统(pub/sub),允许消息从发送者(发布者)广播给一个或多个接收者(订阅者),而无需两者之间直接通信。
它是一种典型的消息广播模型,适用于聊天室、实时通知、系统广播等场景。
核心命令:
| 命令 | 说明 |
|---|---|
subscribe channel [channel ...] | 订阅一个或多个频道 |
publish channel message | 向指定频道发布消息 |
unsubscribe [channel ...] | 取消订阅 |
psubscribe pattern [pattern ...] | 使用通配符订阅多个频道 |
punsubscribe [pattern ...] | 取消模式订阅 |
示例:
开启终端 a(作为订阅者):
subscribe news
此时 redis 会将该客户端状态切换为“订阅模式”,并阻塞式监听名为 news 的频道。redis 会自动推送任何发布到该频道的消息到这个客户端。
注意:客户端一旦 subscribe 或 psubscribe,进入阻塞状态,就不能再发送普通命令(比如 set、get),只能接收消息,直到:unsubscribe或连接断开。
开启终端 b(作为发布者):
publish news "redis 7.0 released!"
注意: redis 不会缓存消息,消息是实时广播的,若发布时没有任何订阅者,消息直接被丢弃,消息传递是同步推送到所有订阅者,大量订阅者可能拖慢发布速度。
终端 a 将自动接收到消息:
1) "message" 表示这条数据是一个消息类型的推送。 2) "news" 这是消息来自的频道名称。 3) "redis 7.0 released!" 这是发布者发送的具体消息内容。
redis 协议会把推送过来的内容打包成一个“数组”,所以你看到的是 1)、2)、3),这其实就是 redis 的 resp 协议(redis serialization protocol)中的数组结构形式。
+-------------------+ +-------------------+
| publisher | | subscriber a |
|-------------------| |-------------------|
| publish news "..."|-----> | subscribe news |
+-------------------+ +-------------------+
+-------------------+
| subscriber b |
|-------------------|
| subscribe news |
+-------------------+
-- 任何 publish news 的消息将同时被 a 和 b 接收到 --redis 支持简单形式的事务机制,允许将多个命令打包为一个事务块执行,从而实现操作的原子性。
redis 事务主要由以下指令组成:
multi:标记事务开始。exec:执行所有事务命令。discard:放弃事务。watch:对一个或多个键设置监视,当其中任意键在事务执行前被修改,事务将被中断。watch(可选)对关键 key 进行乐观锁监控。multi 开启事务队列。exec 触发事务,redis 依次执行队列中的命令。exec 返回 null。示例操作 1:普通事务
multi set user:score 100 incrby user:score 50 get user:score exec
返回:
1) ok 2) (integer) 150 3) "150"
示例操作 2:使用 watch 实现乐观锁(模拟余额扣款)
客户端 a:
set balance 100
watch balance get balance # → "100" multi decrby balance 20 exec
如果此时客户端 b 修改了 balance:
客户端 b:
set balance 50
那么客户端 a 的 exec 将返回 nil,表示事务失败:
(nil)
这是因为监视的键 balance 在事务期间被其他客户端改动,redis 终止执行,以保证数据一致性。
注意:
| 特性 | 说明 |
|---|---|
| ✅ 原子性 | exec 中的命令会顺序执行,不会被打断 |
| ❌ 回滚能力 | redis 事务不支持回滚(没有 rollback) |
| ❌ 隔离级别 | 没有真正的隔离性,其他客户端仍可读写 |
| ✅ 并发控制 | 可使用 watch 模拟乐观锁 |
redis 本身只支持原子执行的命令,但不支持复杂逻辑控制(如条件、循环)。lua 脚本支持带来了以下优势:
eval script numkeys key [key ...] arg [arg ...]
示例 :只有在键不存在时才设置
eval "if redis.call('exists', keys[1]) == 0 then
redis.call('set', keys[1], argv[1])
return 'ok'
else
return 'exists'
end" 1 mykey myvalue解释:
keys[1] 为 "mykey",argv[1] 为 "myvalue"mykey 不存在,则设置为 "myvalue" 并返回 "ok""exists"示例 :批量删除匹配前缀的 key
eval "local keys = redis.call('keys', argv[1])
for i,k in ipairs(keys) do
redis.call('del', k)
end
return #keys" 0 "temp:*"说明:
"temp:*" 的 key#keys 返回删除的数量| 函数 | 参数 | 说明 | 使用示例 |
|---|---|---|---|
redis.call(command, ...) | command: redis 命令字符串;...args: 参数列表 | 用于执行 redis 命令,并返回结果 | lua<br>local result = redis.call('get', keys[1])<br>return result |
redis.pcall(command, ...) | command: redis 命令字符串;...args: 参数列表 | 类似 redis.call,但在错误时返回 nil | lua<br>local result = redis.pcall('get', keys[1])<br>if result then<br>return result<br>else<br>return "key not found"<br>end |
redis.sha1hex(string) | string: 需要计算 sha1 校验和的字符串 | 计算字符串的 sha1 校验和 | lua<br>local sha1 = redis.sha1hex('this is a test string')<br>return sha1 |
redis.evalsha(sha1, numkeys, ...) | sha1: 脚本的 sha1 校验和;numkeys: 键的数量;...: 键和参数列表 | 执行已加载的 lua 脚本(使用 sha1) | lua<br>local sha1 = redis.sha1hex('return redis.call("get", keys[1])')<br>redis.evalsha(sha1, 1, 'my_key') |
redis.log(level, message) | level: 日志级别("debug", "verbose", "notice", "warning" 等);message: 日志内容 | 记录日志消息 | lua<br>redis.log("notice", "this is a log message") |
redis.sleep(seconds) | seconds: 暂停的秒数(可以是小数) | 暂停脚本执行指定的时间 | lua<br>redis.sleep(2)<br>return "finished sleeping" |
redis.setex(key, seconds, value) | key: 键名;seconds: 过期时间(秒);value: 设置的值 | 设置一个带有过期时间的键 | lua<br>redis.setex("my_key", 300, "value")<br>return "key set with expiration" |
redis.bitcount(key) | key: 键名 | 计算指定键的位计数 | lua<br>redis.bitcount("my_bit_key") |
redis.getrange(key, start, end) | key: 键名;start: 起始位置;end: 结束位置 | 获取指定键的子字符串 | lua<br>redis.getrange("my_key", 0, 5) |
为了突破单机 redis 在容量与并发性能上的限制,redis 官方提供了原生的 redis cluster 机制,它通过数据的分片(sharding)与节点间的协作,实现了高可用、可扩展的分布式部署方式。
分片(sharding) 是将数据水平切分为多个部分,每个部分存储在不同 redis 节点上,从而分担负载、提升容量。redis cluster 采用的是哈希槽分片策略。
注意:redis cluster 使用多个主节点(master nodes)来实现分片,每个主节点负责一部分哈希槽(0 ~ 16383 之间的一段)。
哈希槽(hash slot) 是 redis cluster 的核心分片单位。redis 将整个 key 空间划分为 16384 个槽(编号 0 到 16383),每个键通过哈希函数映射到某个槽位,再由特定节点负责这个槽。
哈希槽计算方法:
hash_slot = crc16(key) mod 16384
也就是说,redis 使用 crc16 哈希算法对 key 计算哈希值,并将其对 16384 取模,结果即为槽编号。
示例:计算某个键属于哪个哈希槽
> cluster keyslot mykey (integer) 10285
节点类型
redis cluster 中的节点分为两类:
高可用机制
当某个主节点宕机且多数节点(>半数)发现异常后,会自动触发 故障转移(failover),其从节点会被提升为主节点。
假设有 6 个主节点(m1 ~ m6),如果 m1 宕机,要至少有一半以上的其他主节点(也就是至少 ceil(6/2) = 4 个)同时认为 m1 不可达(pfail 或 fail),才会触发 failover 流程。这些判断是在 redis cluster 的 gossip 协议中完成的,主节点之间会周期性地互相 ping/ack 探测是否“可达”。
典型拓扑结构
node a (master) --> node a1 (slave) node b (master) --> node b1 (slave) node c (master) --> node c1 (slave)
step 1:准备配置文件
创建 6 个 redis 实例配置文件,以下为示例配置重点:
redis.conf port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes
其他端口(7001 - 7005)依次修改端口号。
step 2:启动所有 redis 实例
redis-server ./7000/redis.conf redis-server ./7001/redis.conf ... redis-server ./7005/redis.conf
step 3:创建集群
使用 redis-cli 的 --cluster create 命令:
redis-cli --cluster create \ 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \ 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \ --cluster-replicas 1 --cluster-replicas 1,意味着:每个主节点都配一个从节点 16384 个哈希槽均匀分配给3个主节点 这些节点的主从角色是 redis-cli 在执行时自动决定的,而不是你手动指定谁是主谁是从。 如果你想手动决定哪些是主哪些是从,**就不能使用这个命令,而是得用更底层的命令逐个 cluster meet、cluster addslots 等来构建集群。
此命令会自动分配槽位,并为每个主节点分配一个从节点。
step 4:验证集群状态
redis-cli -c -p 7000 cluster info redis-cli -c -p 7000 cluster nodes
| 命令 | 说明 |
|---|---|
cluster info | 查看当前节点的集群信息 |
cluster nodes | 查看整个集群的所有节点 |
cluster slots | 查看槽分布情况 |
cluster keyslot <key> | 查询 key 属于哪个哈希槽 |
cluster forget <node-id> | 移除某个节点(强制) |
cluster meet <ip> <port> | 添加新节点到集群 |
cluster replicate <node-id> | 将当前节点设置为某主节点的从节点 |
cluster reset | 重置节点并清除其集群配置 |
示例:
查看集群信息
127.0.0.1:7000> cluster info
输出:
cluster_state:ok 表示集群正常。
cluster_slots_assigned:16384 表示总共分配了 16384 个槽位。
cluster_size:3 表示集群有 3 个主节点。
....
查看集群节点信息
127.0.0.1:7000> cluster nodes
07c37dfeb2352e56c38e8c801c0bb4a6b5fd64a6 127.0.0.1:7000 master - 0 1624567890 1 connected 0-5460
3c3f3f5c6b44c1a1beec77c57d56b983f56cb0a1 127.0.0.1:7003 slave 07c37dfeb2352e56c38e8c801c0bb4a6b5fd64a6 0 1624567891 2 connected
......
列出了集群中的所有节点。
每行展示一个节点的状态,包括节点 id、ip 地址、角色(master/slave)以及其负责的槽位范围。
查看哈希槽分配情况
127.0.0.1:7000> cluster slots
1) 1) (integer) 0
2) (integer) 5460
3) 1) "127.0.0.1"
2) (integer) 7000
3) "my-cluster-1"
2) 1) (integer) 5461
2) (integer) 10922
3) 1) "127.0.0.1"
2) (integer) 7001
3) "my-cluster-2"
3) 1) (integer) 10923
2) (integer) 16383
3) 1) "127.0.0.1"
2) (integer) 7002
3) "my-cluster-3"
显示了哈希槽(0-16383)的分配情况,列出了每个主节点及其负责的槽区间。
每个主节点对应的从节点会在后续的操作中自动关联。
查看某个键属于哪个哈希槽
127.0.0.1:7000> cluster keyslot mykey
(integer) 10285
mykey被分配到哈希槽10285中。
......到此这篇关于redis介绍与使用一文搞懂的文章就介绍到这了,更多相关redis介绍与使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论