Redis 教程:从零开始学 Redis
Redis 教程:从零开始学 Redis
在当今这个数据驱动的时代,高效地存储、检索和管理数据对于应用程序的性能至关重要。关系型数据库(如 MySQL、PostgreSQL)在许多场景下表现出色,但在面对高并发、低延迟的读写需求时,往往会遇到瓶颈。这时,内存数据库(In-Memory Database)应运而生,而 Redis 正是其中最耀眼的明星。
Redis(Remote Dictionary Server)是一个开源的、使用 ANSI C 语言编写的、支持网络、基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。它以其惊人的速度、丰富的数据结构、简单易用的特性以及广泛的应用场景,成为了现代 Web 开发、分布式系统、实时分析等领域不可或缺的组件。
本教程旨在引导初学者从零开始,系统地学习 Redis 的核心概念、基本操作、数据结构、常用功能以及典型应用场景,帮助你快速掌握并能在实际项目中应用 Redis。
一、 认识 Redis:它是什么?为什么选择它?
1. Redis 的核心特性:
- 基于内存存储: Redis 将绝大部分数据存储在内存中,这是其读写速度极快的主要原因。内存的访问速度远超磁盘 I/O,使得 Redis 能够轻松应对每秒数万甚至数十万次的请求。
- Key-Value 存储: Redis 的基本数据模型是键值对(Key-Value)。每个 Key 都是唯一的字符串,Value 则可以是多种不同的数据类型。
- 丰富的数据结构: 与只能存储字符串的 Memcached 不同,Redis 支持多种复杂的数据结构,包括:
- 字符串 (Strings): 最基本的数据类型,可以存储文本、序列化对象、二进制数据等,最大可达 512MB。
- 哈希 (Hashes): 类似于编程语言中的 Map 或 Dictionary,用于存储对象的字段和值。非常适合存储结构化数据。
- 列表 (Lists): 有序的字符串集合,按照插入顺序排序。可以快速地在列表头部或尾部添加/删除元素,适合实现消息队列、最新动态等。
- 集合 (Sets): 无序的、唯一的字符串集合。支持高效的成员检查、交集、并集、差集等操作。
- 有序集合 (Sorted Sets / ZSets): 类似于集合,但每个成员都关联一个 double 类型的分数(score)。Redis 根据分数对成员进行排序,可以快速地根据分数范围或排名获取成员。非常适合实现排行榜、带权重的任务队列等。
- HyperLogLog: 用于进行基数统计(估算集合中不重复元素的数量),占用空间极小。
- Bitmap: 位图,可以对位的级别进行操作,适合进行状态标记、用户签到等统计。
- Geospatial: 地理空间索引,用于存储地理位置信息并进行范围查询。
- 持久化支持: 虽然基于内存,但 Redis 提供了两种持久化机制,确保在服务器重启后数据不会丢失:
- RDB (Redis Database Backup): 按指定时间间隔将内存中的数据快照(snapshot)保存到磁盘。
- AOF (Append Only File): 将所有执行的写命令追加到文件末尾,恢复时重新执行这些命令。
- 高可用与扩展性: Redis 支持主从复制(Replication)、哨兵(Sentinel)机制实现高可用,以及集群(Cluster)模式实现分布式存储和负载均衡。
- 原子操作: Redis 的大部分命令都是原子性的,这意味着一个命令在执行过程中不会被其他命令打断,保证了数据的一致性。
- 发布/订阅 (Pub/Sub): 内置了消息发布和订阅功能,可以用于构建简单的实时消息系统。
- 事务支持: 可以将多个命令打包在一起原子性地执行(但与关系型数据库的事务有所不同)。
- Lua 脚本: 允许用户编写 Lua 脚本在服务端原子性地执行复杂逻辑,减少网络开销。
2. 为什么选择 Redis?
- 高性能: 读写速度极快,轻松应对高并发场景。
- 丰富的数据结构: 满足多样化的业务需求,简化开发。
- 简单易用: 命令简洁明了,学习曲线平缓。
- 功能全面: 持久化、主从、集群、事务、Pub/Sub 等功能完善。
- 社区活跃: 拥有庞大的用户群体和活跃的社区支持,生态完善。
- 应用广泛: 在缓存、会话管理、消息队列、排行榜、计数器、实时分析等领域都有成熟应用。
二、 安装与启动 Redis
在学习 Redis 之前,首先需要在你的环境中安装它。
1. Linux (Ubuntu/Debian):
```bash
sudo apt update
sudo apt install redis-server
启动 Redis 服务
sudo systemctl start redis-server
设置开机自启
sudo systemctl enable redis-server
检查服务状态
sudo systemctl status redis-server
```
2. Linux (CentOS/RHEL):
```bash
sudo yum install epel-release
sudo yum install redis
启动 Redis 服务
sudo systemctl start redis
设置开机自启
sudo systemctl enable redis
检查服务状态
sudo systemctl status redis
```
3. macOS:
推荐使用 Homebrew 安装:
```bash
brew install redis
启动 Redis 服务 (后台运行)
brew services start redis
或者前台运行 (方便查看日志)
redis-server /usr/local/etc/redis.conf
```
4. Docker:
如果你熟悉 Docker,这是最方便快捷的跨平台方式:
```bash
拉取官方 Redis 镜像
docker pull redis
运行 Redis 容器 (后台运行,端口映射到宿主机的 6379)
docker run --name my-redis -d -p 6379:6379 redis
如果需要持久化数据,可以挂载卷
docker run --name my-redis -d -p 6379:6379 -v redis_data:/data redis redis-server --appendonly yes
```
5. Windows:
Redis 官方不直接支持 Windows,但微软维护了一个 Windows 移植版本(较旧)或者推荐使用 WSL (Windows Subsystem for Linux) 来运行 Linux 版 Redis。也可以使用 Docker Desktop for Windows。
连接 Redis 客户端:
安装完成后,可以使用 Redis 自带的命令行客户端 redis-cli
连接到 Redis 服务器:
bash
redis-cli
如果 Redis 服务器运行在不同的主机或端口,可以指定:
bash
redis-cli -h <hostname> -p <port>
连接成功后,你会看到类似 127.0.0.1:6379>
的提示符。可以尝试发送一个 PING
命令,如果服务器正常,会返回 PONG
。
127.0.0.1:6379> PING
PONG
三、 Redis 核心概念:Keys 与 Values
Redis 的世界围绕着 键(Keys) 和 值(Values) 构建。
-
Keys:
- Keys 是二进制安全的字符串,你可以使用任何字符序列作为 Key,例如 "user:1001:profile"、"product:sku:12345" 甚至包含空格或特殊字符(但不推荐,可能导致管理困难)。
- Key 的最大长度是 512MB(实际中应远小于此)。
- 命名规范很重要: 为了便于管理和理解,建议采用有意义的、结构化的 Key 命名方式,例如
object-type:id:field
(如user:1001:name
)或使用冒号:
作为分隔符。 - 避免使用过长或过于简短(如 "a", "b")的 Key。
-
Values:
- Values 是与 Key 相关联的数据。
- Redis 的强大之处在于 Value 可以是多种不同的数据结构,而不仅仅是简单的字符串。我们将在下一节详细探讨这些数据结构。
四、 Redis 五大常用数据结构详解
这是 Redis 的核心内容,理解并掌握这些数据结构及其常用命令至关重要。
1. 字符串 (String)
- 描述: 最基础的类型,可以存储字符串、整数或浮点数。Redis 会根据内容自动进行内部编码优化。二进制安全,最大 512MB。
- 应用场景: 缓存(页面、对象序列化)、计数器、分布式锁、存储 Session 信息等。
- 常用命令:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
:设置 key 的值。EX
/PX
设置过期时间,NX
只在 key 不存在时设置,XX
只在 key 存在时设置。
redis
127.0.0.1:6379> SET mykey "Hello Redis"
OK
127.0.0.1:6379> SET counter 100 EX 60 # 设置 counter 为 100,60秒后过期
OKGET key
:获取 key 的值。如果 key 不存在,返回(nil)
。
redis
127.0.0.1:6379> GET mykey
"Hello Redis"GETSET key value
:设置新值并返回旧值。MSET key value [key value ...]
:同时设置多个 key-value 对。MGET key [key ...]
:同时获取多个 key 的值。INCR key
:将 key 存储的数字值增 1(如果 key 不存在,先初始化为 0 再执行)。DECR key
:将 key 存储的数字值减 1。INCRBY key increment
:将 key 存储的数字值增加指定的increment
。DECRBY key decrement
:将 key 存储的数字值减少指定的decrement
。APPEND key value
:将value
追加到 key 原有值的末尾。STRLEN key
:返回 key 所存储的字符串值的长度。
2. 哈希 (Hash)
- 描述: 一个键值对集合,可以看作是 String Key 和 String Value 的 Map。特别适合存储对象。
- 应用场景: 存储用户信息(用户名、密码、邮箱等)、商品信息、配置项等结构化数据。相比将对象序列化后存入 String,Hash 更节省内存,且可以方便地对单个字段进行读写。
- 常用命令:
HSET key field value [field value ...]
:设置哈希key
中一个或多个field
的值。
redis
127.0.0.1:6379> HSET user:1001 name "Alice" age 30 email "[email protected]"
(integer) 3HGET key field
:获取哈希key
中指定field
的值。
redis
127.0.0.1:6379> HGET user:1001 name
"Alice"HMSET key field value [field value ...]
:(已不推荐,建议使用HSET
)同时设置多个 field-value 对。HMGET key field [field ...]
:同时获取多个field
的值。HGETALL key
:获取哈希key
中所有的 field 和 value。HDEL key field [field ...]
:删除哈希key
中的一个或多个field
。HLEN key
:获取哈希key
中 field 的数量。HEXISTS key field
:检查哈希key
中是否存在指定的field
。HKEYS key
:获取哈希key
中所有的 field。HVALS key
:获取哈希key
中所有的 value。HINCRBY key field increment
:为哈希key
中指定field
的数值增加increment
。
3. 列表 (List)
- 描述: 字符串列表,按照插入顺序排序。可以在列表的头部(左边)或尾部(右边)添加元素。底层实现可能是双向链表或压缩列表(ziplist),插入和删除操作非常快。
- 应用场景: 消息队列(生产者 LPUSH,消费者 RPOP/BRPOP)、任务队列、最新动态列表(LPUSH + LTRIM)、文章/评论列表。
- 常用命令:
LPUSH key element [element ...]
:将一个或多个元素插入到列表key
的头部。RPUSH key element [element ...]
:将一个或多个元素插入到列表key
的尾部。
redis
127.0.0.1:6379> LPUSH tasks "task1" "task2" "task3" # 插入后顺序: task3, task2, task1
(integer) 3
127.0.0.1:6379> RPUSH tasks "task0" # 插入后顺序: task3, task2, task1, task0
(integer) 4LPOP key [count]
:移除并返回列表key
头部的count
个元素(默认为 1)。RPOP key [count]
:移除并返回列表key
尾部的count
个元素(默认为 1)。LRANGE key start stop
:获取列表key
中指定范围内的元素(start
和stop
是基于 0 的索引,支持负数表示倒数位置,如 -1 表示最后一个元素)。
redis
127.0.0.1:6379> LRANGE tasks 0 -1 # 获取所有元素
1) "task3"
2) "task2"
3) "task1"
4) "task0"LLEN key
:获取列表key
的长度。LINDEX key index
:获取列表key
中下标为index
的元素。LSET key index element
:将列表key
下标为index
的元素设置为element
。LTRIM key start stop
:只保留列表key
中指定范围内的元素,其他都删除。常用于保持列表固定长度。BLPOP key [key ...] timeout
:LPOP
的阻塞版本。如果列表为空,会阻塞等待timeout
秒,直到有元素可弹出或超时。BRPOP key [key ...] timeout
:RPOP
的阻塞版本。
4. 集合 (Set)
- 描述: 无序的、不重复的字符串集合。底层实现是哈希表,所以添加、删除、查找的时间复杂度都是 O(1)。
- 应用场景: 标签系统(一个用户/文章拥有多个标签)、共同好友/关注、抽奖(随机获取元素)、计算独立访客(IP 去重)等。
- 常用命令:
SADD key member [member ...]
:向集合key
添加一个或多个member
。如果member
已存在,则忽略。
redis
127.0.0.1:6379> SADD tags:post:1 "redis" "database" "nosql"
(integer) 3
127.0.0.1:6379> SADD tags:post:1 "redis" # 尝试添加已存在的 "redis"
(integer) 0SMEMBERS key
:返回集合key
中的所有成员。
redis
127.0.0.1:6379> SMEMBERS tags:post:1
1) "nosql"
2) "redis"
3) "database" (注意:顺序不固定)SISMEMBER key member
:判断member
是否是集合key
的成员。返回 1 表示是,0 表示不是。SCARD key
:获取集合key
的元素数量(基数)。SREM key member [member ...]
:从集合key
中移除一个或多个member
。SPOP key [count]
:随机移除并返回集合key
中的count
个成员(默认为 1)。SRANDMEMBER key [count]
:随机返回集合key
中的count
个成员,但不移除它们。- 集合运算:
SINTER key [key ...]
:返回给定所有集合的交集。SUNION key [key ...]
:返回给定所有集合的并集。SDIFF key [key ...]
:返回第一个集合与其他集合的差集。SINTERSTORE destination key [key ...]
:计算交集并将结果存入destination
集合。SUNIONSTORE destination key [key ...]
:计算并集并将结果存入destination
集合。SDIFFSTORE destination key [key ...]
:计算差集并将结果存入destination
集合。
5. 有序集合 (Sorted Set / ZSet)
- 描述: 类似于集合,每个成员(member)都是唯一的,但同时关联了一个 double 类型的分数(score)。Redis 通过分数来为集合中的成员进行从小到大的排序。成员是唯一的,但分数可以重复。
- 应用场景: 排行榜(游戏积分榜、商品销量榜)、带权重的任务队列、范围查找(如查找积分在某个区间的用户)。
- 常用命令:
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
:向有序集合key
添加一个或多个member
及其score
。NX
只添加新成员,XX
只更新已存在成员,CH
返回本次操作实际改变的成员数量,INCR
对已存在成员的 score 进行增加(此时 ZADD 行为类似 ZINCRBY)。
redis
127.0.0.1:6379> ZADD leaderboard 100 "player1" 85 "player2" 95 "player3"
(integer) 3
127.0.0.1:6379> ZADD leaderboard XX INCR 10 "player2" # 给 player2 加 10 分
"95" # 返回 player2 的新分数ZRANGE key start stop [WITHSCORES]
:按分数从小到大返回指定排名范围内的成员。start
和stop
是基于 0 的排名索引。WITHSCORES
同时返回成员和分数。ZREVRANGE key start stop [WITHSCORES]
:按分数从大到小返回指定排名范围内的成员。
redis
127.0.0.1:6379> ZRANGE leaderboard 0 -1 WITHSCORES # 获取所有成员,按分升序
1) "player3"
2) "95"
3) "player2"
4) "95"
5) "player1"
6) "100"
127.0.0.1:6379> ZREVRANGE leaderboard 0 1 WITHSCORES # 获取排名前 2 的成员
1) "player1"
2) "100"
3) "player3" # 分数相同,按字典序排
4) "95"ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
:按分数范围返回成员。min
和max
可以是-inf
、+inf
,或者使用(
表示不包含边界(如(80 100
表示 >80 且 <=100)。ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
:同上,但按分数从大到小返回。ZCARD key
:获取有序集合key
的成员数量。ZCOUNT key min max
:获取有序集合key
中,分数在min
和max
之间的成员数量。ZSCORE key member
:获取有序集合key
中member
的分数。ZRANK key member
:获取member
在有序集合key
中的排名(按分升序,从 0 开始)。ZREVRANK key member
:获取member
在有序集合key
中的排名(按分降序,从 0 开始)。ZREM key member [member ...]
:移除有序集合key
中的一个或多个member
。ZREMRANGEBYRANK key start stop
:移除指定排名范围内的成员。ZREMRANGEBYSCORE key min max
:移除指定分数范围内的成员。ZINCRBY key increment member
:为member
的分数增加increment
。
五、 通用 Key 操作命令
除了针对特定数据类型的命令,还有一些通用的操作 Key 的命令:
DEL key [key ...]
:删除一个或多个 Key 及其关联的值。
redis
127.0.0.1:6379> DEL mykey counter tasks leaderboard tags:post:1 user:1001
(integer) 6 # 返回成功删除的 Key 的数量EXISTS key [key ...]
:检查一个或多个 Key 是否存在。返回存在的 Key 的数量。KEYS pattern
:查找所有符合给定模式pattern
的 Key。警告: 在生产环境中,KEYS
是一个阻塞操作,当数据库很大时,执行KEYS *
会严重影响性能,甚至导致服务卡顿。应尽量避免使用,或在数据量可控的情况下使用。推荐使用SCAN
命令进行安全的遍历。
redis
127.0.0.1:6379> SET user:1:name "A"
OK
127.0.0.1:6379> SET user:2:name "B"
OK
127.0.0.1:6379> KEYS user:*:name
1) "user:1:name"
2) "user:2:name"SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
:基于游标的迭代器,用于安全地遍历 Key 空间。每次调用返回一部分 Key 和一个新的游标,直到游标返回 0 表示遍历完成。TYPE key
:返回 Key 存储的值的类型(string, hash, list, set, zset)。RENAME key newkey
:重命名 Key。如果newkey
已存在,其值会被覆盖。RENAMENX key newkey
:仅当newkey
不存在时才重命名 Key。EXPIRE key seconds
:为 Key 设置指定的过期时间(秒)。PEXPIRE key milliseconds
:为 Key 设置指定的过期时间(毫秒)。EXPIREAT key timestamp
:为 Key 设置一个 UNIX 时间戳作为过期时间点(秒)。PEXPIREAT key milliseconds-timestamp
:为 Key 设置一个 UNIX 时间戳作为过期时间点(毫秒)。TTL key
:返回 Key 的剩余生存时间(秒)。-1 表示永不过期,-2 表示 Key 不存在。PTTL key
:返回 Key 的剩余生存时间(毫秒)。PERSIST key
:移除 Key 的过期时间,使其永不过期。
六、 Redis 进阶主题简介
掌握了基础的数据结构和命令后,可以进一步了解 Redis 的一些高级特性:
-
持久化 (Persistence):
- RDB: 优点是恢复速度快,文件紧凑。缺点是如果发生故障,会丢失最后一次快照之后的数据。
- AOF: 优点是数据安全性更高(根据配置可丢失很少或不丢失数据)。缺点是文件体积通常比 RDB 大,恢复速度相对较慢。
- 可以同时开启 RDB 和 AOF。
-
事务 (Transactions):
- 使用
MULTI
开启事务,然后输入多个命令,最后使用EXEC
执行。DISCARD
用于取消事务。 - Redis 事务保证命令打包原子性执行,但不保证回滚。如果事务中的某个命令出错,其他命令依然会执行(除非是语法错误导致整个事务无法入队)。
WATCH key [key ...]
:乐观锁机制。如果在EXEC
执行前,被WATCH
的 Key 被其他客户端修改,则事务执行失败。
- 使用
-
发布/订阅 (Pub/Sub):
SUBSCRIBE channel [channel ...]
:订阅一个或多个频道。PUBLISH channel message
:向指定频道发布消息,所有订阅者都会收到。UNSUBSCRIBE [channel [channel ...]]
:取消订阅。- 适用于简单的实时消息通知、事件广播等。不保证消息可靠性,如果订阅者掉线,期间发布的消息会丢失。
-
Lua 脚本:
- 使用
EVAL script numkeys key [key ...] arg [arg ...]
或EVALSHA sha1 numkeys key [key ...] arg [arg ...]
执行 Lua 脚本。 - 脚本在 Redis 服务器端原子性执行,可以减少网络往返,实现更复杂的原子操作。
- 使用
-
主从复制 (Replication):
- 一个 Master 节点可以有多个 Slave 节点。Slave 会复制 Master 的数据。
- 用于读写分离(Master 写,Slave 读)和数据冗余备份。
-
哨兵 (Sentinel):
- 监控 Master 和 Slave 的状态,在 Master 故障时自动进行故障转移(Failover),选举新的 Master。
- 提供客户端服务发现。
-
集群 (Cluster):
- 将数据分片(Sharding)存储在多个 Redis 节点上,实现水平扩展和高可用。
- 去中心化架构,每个节点都知道集群状态和数据分布。
七、 Redis 典型应用场景
- 缓存: 最常见的用途。缓存数据库查询结果、API 响应、计算结果、渲染后的 HTML 片段等,大幅提升应用性能,降低后端负载。通常使用 String 或 Hash 结构。设置合理的过期时间(
EXPIRE
)是关键。 - 会话管理 (Session Store): 将用户的 Session 信息存储在 Redis 中,实现分布式 Session 共享,便于应用水平扩展。通常使用 String 结构存储序列化后的 Session 数据。
- 计数器/限流器: 利用
INCR
/INCRBY
的原子性实现各种计数功能(如网站 PV/UV、点赞数、库存数量)和接口访问频率限制。 - 排行榜: 利用 Sorted Set 的排序功能,轻松实现游戏积分榜、热销商品榜、热门帖子排行等。
- 消息队列/任务队列: 利用 List 的
LPUSH
/RPOP
(或阻塞版本BRPOP
)实现简单的先进先出队列,用于服务解耦、异步处理任务。 - 分布式锁: 利用
SET key value NX EX seconds
命令的原子性实现简单的分布式锁,防止并发场景下的资源竞争问题。 - 实时数据处理: 结合 Pub/Sub 或 List 实现实时数据流的发布、订阅和处理。
- 地理空间查询: 利用 Geospatial 数据结构存储位置信息,进行附近的人/地点查找。
- 位操作应用: 利用 Bitmap 实现用户签到统计、在线状态标记、布隆过滤器等。
八、 学习资源与后续步骤
- 官方文档:
redis.io
是最权威、最全面的学习资源。 redis-cli
内置帮助: 在redis-cli
中输入HELP @<group>
(如HELP @string
,HELP @list
)可以查看命令帮助。- 在线教程与书籍: 网络上有大量优秀的 Redis 教程和实战书籍。
- 实践: 最重要的学习方式是动手实践。安装 Redis,尝试各种命令,模拟不同的应用场景。
- 深入: 了解 Redis 的内部实现(数据结构、持久化原理、网络模型)、性能调优、高可用架构(Sentinel、Cluster)配置与管理。
结语
Redis 以其卓越的性能和丰富的功能,在现代技术栈中扮演着越来越重要的角色。通过本教程的学习,你应该对 Redis 的基本概念、核心数据结构、常用命令以及应用场景有了初步的了解。但这仅仅是一个开始,Redis 的世界远不止于此。持续学习,不断实践,深入探索其高级特性和内部原理,你将能够更加充分地发挥 Redis 的威力,为你的应用程序带来显著的性能提升和功能扩展。祝你在 Redis 的学习之路上不断进步!