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秒后过期
      OK
    • GET 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) 3
    • HGET 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) 4
    • LPOP key [count]:移除并返回列表 key 头部的 count 个元素(默认为 1)。
    • RPOP key [count]:移除并返回列表 key 尾部的 count 个元素(默认为 1)。
    • LRANGE key start stop:获取列表 key 中指定范围内的元素(startstop 是基于 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 ...] timeoutLPOP 的阻塞版本。如果列表为空,会阻塞等待 timeout 秒,直到有元素可弹出或超时。
    • BRPOP key [key ...] timeoutRPOP 的阻塞版本。

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) 0
    • SMEMBERS 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 及其 scoreNX 只添加新成员,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]:按分数从小到大返回指定排名范围内的成员。startstop 是基于 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]:按分数范围返回成员。minmax 可以是 -inf+inf,或者使用 ( 表示不包含边界(如 (80 100 表示 >80 且 <=100)。
    • ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]:同上,但按分数从大到小返回。
    • ZCARD key:获取有序集合 key 的成员数量。
    • ZCOUNT key min max:获取有序集合 key 中,分数在 minmax 之间的成员数量。
    • ZSCORE key member:获取有序集合 keymember 的分数。
    • 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 的学习之路上不断进步!


THE END