Skip to content

Redis 教程:从入门到精通

Redis 是一个开源的、基于内存的高性能键值数据库,被广泛应用于缓存、会话存储、消息队列等场景。本教程将帮助你全面了解 Redis 的核心概念和使用方法。

Redis 简介

什么是 Redis?

Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据类型,如字符串、哈希表、列表、集合、有序集合等,并且提供了丰富的操作命令。

Redis 的主要特点

  • 高性能:基于内存操作,读写速度极快
  • 丰富的数据类型:支持字符串、哈希、列表、集合、有序集合等
  • 原子操作:所有操作都是原子性的,支持事务
  • 持久化:支持数据持久化到磁盘(RDB 和 AOF)
  • 主从复制:支持主从复制和高可用
  • 分布式:支持集群模式,可水平扩展
  • Lua 脚本:支持 Lua 脚本执行复杂操作
  • 发布/订阅:支持消息的发布与订阅

Redis 与传统数据库的比较

特性Redis关系型数据库
数据模型键值存储表格关系模型
存储方式内存(可持久化)磁盘
查询语言简单命令SQL
事务支持基本支持完全支持
性能极高中等
扩展性主从复制、集群主从复制、分库分表
适用场景缓存、会话、计数器、排行榜复杂查询、事务处理

Redis 安装与配置

安装 Redis

在 Linux 上安装

bash
# Ubuntu/Debian
sudo apt update
sudo apt install redis-server

# CentOS/RHEL
sudo yum install epel-release
sudo yum install redis

在 macOS 上安装

bash
brew install redis

在 Windows 上安装

Windows 不是 Redis 的官方支持平台,但可以通过以下方式使用:

  1. 使用 WSL(Windows Subsystem for Linux)
  2. 使用 Docker 容器
  3. 使用非官方的 Windows 版本:Microsoft Redis

使用 Docker 安装

bash
docker pull redis
docker run --name my-redis -p 6379:6379 -d redis

基本配置

Redis 的配置文件通常位于 /etc/redis/redis.conf(Linux)或 /usr/local/etc/redis.conf(macOS)。以下是一些重要的配置项:

# 绑定地址
bind 127.0.0.1

# 端口
port 6379

# 密码保护
requirepass yourpassword

# 最大内存
maxmemory 100mb

# 内存策略
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1
save 300 10
save 60 10000

启动与停止 Redis

bash
# 启动 Redis 服务
sudo systemctl start redis  # Linux
brew services start redis   # macOS

# 停止 Redis 服务
sudo systemctl stop redis   # Linux
brew services stop redis    # macOS

# 重启 Redis 服务
sudo systemctl restart redis  # Linux
brew services restart redis   # macOS

Redis 数据类型与命令

Redis 支持多种数据类型,每种类型都有其特定的使用场景和操作命令。

连接到 Redis

使用 Redis CLI 连接到 Redis 服务器:

bash
redis-cli
# 如果设置了密码
redis-cli -a yourpassword
# 连接到远程服务器
redis-cli -h host -p port -a password

字符串(String)

字符串是 Redis 最基本的数据类型,可以存储文本、整数或二进制数据。

基本命令

bash
# 设置键值
SET key value
# 获取键值
GET key
# 设置键值并指定过期时间(秒)
SETEX key seconds value
# 设置键值并指定过期时间(毫秒)
PSETEX key milliseconds value
# 只在键不存在时设置值
SETNX key value
# 获取值的长度
STRLEN key
# 一次设置多个键值
MSET key1 value1 key2 value2
# 一次获取多个键值
MGET key1 key2
# 删除键
DEL key
# 检查键是否存在
EXISTS key
# 设置过期时间(秒)
EXPIRE key seconds
# 查看剩余过期时间(秒)
TTL key

数值操作

bash
# 将值递增1
INCR key
# 将值递增指定整数
INCRBY key increment
# 将值递增指定浮点数
INCRBYFLOAT key increment
# 将值递减1
DECR key
# 将值递减指定整数
DECRBY key decrement

应用场景

  • 缓存:存储页面、API 响应等
  • 计数器:如访问次数、点赞数
  • 分布式锁:使用 SETNX 实现
  • 会话存储:存储用户会话信息

哈希(Hash)

哈希类型是字段和值的映射表,适合存储对象。

基本命令

bash
# 设置哈希表字段的值
HSET key field value
# 获取哈希表字段的值
HGET key field
# 设置多个哈希表字段的值
HMSET key field1 value1 field2 value2
# 获取多个哈希表字段的值
HMGET key field1 field2
# 获取哈希表中所有字段和值
HGETALL key
# 获取哈希表中所有字段
HKEYS key
# 获取哈希表中所有值
HVALS key
# 检查哈希表中是否存在指定字段
HEXISTS key field
# 删除哈希表中的一个或多个字段
HDEL key field1 [field2]
# 获取哈希表中字段的数量
HLEN key
# 为哈希表中的字段值加上增量
HINCRBY key field increment
# 为哈希表中的字段值加上浮点数增量
HINCRBYFLOAT key field increment

应用场景

  • 用户信息存储:每个用户 ID 对应一个哈希表,字段为用户属性
  • 购物车:用户 ID 作为键,商品 ID 为字段,数量为值
  • 配置信息:应用配置、系统参数等
  • 缓存对象:缓存数据库查询结果

列表(List)

列表是简单的字符串列表,按照插入顺序排序,可以从头部或尾部添加元素。

基本命令

bash
# 将一个或多个值插入到列表头部
LPUSH key value1 [value2]
# 将一个或多个值插入到列表尾部
RPUSH key value1 [value2]
# 移除并返回列表的第一个元素
LPOP key
# 移除并返回列表的最后一个元素
RPOP key
# 获取列表指定范围内的元素
LRANGE key start stop
# 获取列表长度
LLEN key
# 通过索引获取列表中的元素
LINDEX key index
# 在列表的元素前或后插入元素
LINSERT key BEFORE|AFTER pivot value
# 设置列表指定索引位置的值
LSET key index value
# 移除列表中与参数 value 相等的元素
LREM key count value
# 对一个列表进行修剪,只保留指定区间内的元素
LTRIM key start stop

应用场景

  • 消息队列:生产者使用 RPUSH,消费者使用 LPOP
  • 最新动态:如社交网络的时间线
  • 任务队列:待处理的任务列表
  • 最近浏览记录:保存用户最近浏览的商品

集合(Set)

集合是字符串类型的无序集合,集合成员是唯一的。

基本命令

bash
# 添加一个或多个成员到集合
SADD key member1 [member2]
# 获取集合的所有成员
SMEMBERS key
# 判断成员是否是集合的成员
SISMEMBER key member
# 获取集合的成员数
SCARD key
# 移除集合中一个或多个成员
SREM key member1 [member2]
# 随机返回集合中的一个成员
SRANDMEMBER key [count]
# 随机移除并返回集合中的一个成员
SPOP key [count]
# 返回给定所有集合的交集
SINTER key1 [key2]
# 返回给定所有集合的并集
SUNION key1 [key2]
# 返回给定所有集合的差集
SDIFF key1 [key2]
# 将给定集合的交集存储在目标集合中
SINTERSTORE destination key1 [key2]
# 将给定集合的并集存储在目标集合中
SUNIONSTORE destination key1 [key2]
# 将给定集合的差集存储在目标集合中
SDIFFSTORE destination key1 [key2]

应用场景

  • 用户标签:存储用户的兴趣爱好、技能等
  • 好友关系:存储用户的好友、关注者
  • 唯一性检查:如邮箱地址、用户名的唯一性
  • 黑名单/白名单:IP 地址、用户 ID 等

有序集合(Sorted Set)

有序集合与集合类似,但每个成员关联一个分数,用于排序。

基本命令

bash
# 添加一个或多个成员到有序集合,或更新已存在成员的分数
ZADD key score1 member1 [score2 member2]
# 获取有序集合的成员数
ZCARD key
# 计算有序集合中指定分数范围的成员数
ZCOUNT key min max
# 获取有序集合中指定成员的分数
ZSCORE key member
# 获取有序集合中指定成员的排名(按分数从小到大)
ZRANK key member
# 获取有序集合中指定成员的排名(按分数从大到小)
ZREVRANK key member
# 获取有序集合中指定范围的成员(按分数从小到大)
ZRANGE key start stop [WITHSCORES]
# 获取有序集合中指定范围的成员(按分数从大到小)
ZREVRANGE key start stop [WITHSCORES]
# 获取有序集合中指定分数范围的成员
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
# 移除有序集合中的一个或多个成员
ZREM key member1 [member2]
# 移除有序集合中指定排名范围的所有成员
ZREMRANGEBYRANK key start stop
# 移除有序集合中指定分数范围的所有成员
ZREMRANGEBYSCORE key min max
# 为有序集合中的成员增加分数
ZINCRBY key increment member

应用场景

  • 排行榜:如游戏积分榜、热门文章
  • 优先级队列:按优先级处理任务
  • 延迟队列:按时间戳排序的任务
  • 权重搜索:按相关性排序的搜索结果

Redis 高级特性

事务

Redis 事务允许在一个步骤中执行一组命令,保证所有命令要么全部执行,要么全部不执行。

bash
# 标记一个事务块的开始
MULTI
# 执行所有事务块内的命令
EXEC
# 取消事务,放弃执行事务块内的所有命令
DISCARD
# 监视一个或多个键,如果在事务执行之前这些键被修改,那么事务将被打断
WATCH key1 [key2]
# 取消对所有键的监视
UNWATCH

注意:Redis 的事务不支持回滚操作,如果事务中的某个命令执行失败,其他命令仍会被执行。

发布/订阅

Redis 的发布/订阅功能允许客户端订阅频道,当有消息发布到这些频道时,所有订阅者都会收到消息。

bash
# 订阅一个或多个频道
SUBSCRIBE channel1 [channel2]
# 退订一个或多个频道
UNSUBSCRIBE [channel1 [channel2]]
# 订阅一个或多个符合给定模式的频道
PSUBSCRIBE pattern1 [pattern2]
# 退订一个或多个符合给定模式的频道
PUNSUBSCRIBE [pattern1 [pattern2]]
# 将信息发送到指定的频道
PUBLISH channel message
# 查看订阅与发布系统状态
PUBSUB subcommand [argument [argument ...]]

Lua 脚本

Redis 支持使用 Lua 脚本执行复杂的操作,脚本在 Redis 中是原子性的。

bash
# 执行 Lua 脚本
EVAL script numkeys key1 [key2 ...] arg1 [arg2 ...]
# 执行已缓存的 Lua 脚本
EVALSHA sha1 numkeys key1 [key2 ...] arg1 [arg2 ...]
# 将脚本加入脚本缓存
SCRIPT LOAD script
# 查看脚本是否已被缓存
SCRIPT EXISTS sha1 [sha2 ...]
# 清除所有脚本缓存
SCRIPT FLUSH
# 杀死当前正在运行的脚本
SCRIPT KILL

位图操作

Redis 的位图操作允许对字符串值进行位级操作,适用于需要处理位级数据的场景。

bash
# 对 key 所储存的字符串值,设置或清除指定偏移量上的位
SETBIT key offset value
# 获取 key 所储存的字符串值,获取指定偏移量上的位
GETBIT key offset
# 计算给定字符串中,被设置为 1 的比特位的数量
BITCOUNT key [start end]
# 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
BITOP operation destkey key1 [key2 ...]
# 返回字符串里面第一个被设置为 1 或 0 的 bit 位
BITPOS key bit [start] [end]

Redis 持久化

Redis 提供了多种持久化选项,以确保数据在服务器重启后不会丢失。

RDB(Redis Database)

RDB 持久化通过创建数据库快照(snapshot)来保存数据。

配置选项

# 900秒(15分钟)内有1个更改
save 900 1
# 300秒(5分钟)内有10个更改
save 300 10
# 60秒内有10000个更改
save 60 10000

# 文件名称
dbfilename dump.rdb

# 是否压缩
rdbcompression yes

# 导出 RDB 文件时是否进行校验和检验
rdbchecksum yes

# 工作目录
dir ./

手动触发

bash
# 创建 RDB 快照
SAVE
# 异步创建 RDB 快照
BGSAVE

优缺点

优点

  • 适合备份和灾难恢复
  • 单个紧凑的文件,方便传输
  • 性能影响小,fork 子进程执行
  • 恢复速度快

缺点

  • 可能会丢失最后一次快照之后的数据
  • fork 进程时可能会导致服务短暂停顿

AOF(Append Only File)

AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时重新执行这些命令来恢复数据。

配置选项

# 是否开启 AOF
appendonly yes

# 文件名称
appendfilename "appendonly.aof"

# 同步策略
# always:每个写命令都同步
# everysec:每秒同步一次(默认)
# no:由操作系统决定何时同步
appendfsync everysec

# 重写时是否同步
no-appendfsync-on-rewrite no

# 自动重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

手动触发重写

bash
# 手动触发 AOF 重写
BGREWRITEAOF

优缺点

优点

  • 更好的持久性,支持不同的同步策略
  • 文件以追加方式记录,不会因为断电而损坏
  • 当文件过大时,会自动在后台重写

缺点

  • AOF 文件通常比 RDB 文件大
  • 根据同步策略的不同,AOF 可能比 RDB 慢
  • 恢复数据时相对较慢

混合持久化

Redis 4.0 引入了混合持久化,结合了 RDB 和 AOF 的优点。

# 开启混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes

在这种模式下,AOF 重写时会先以 RDB 格式写入数据,然后再将重写期间的增量命令以 AOF 格式追加到文件末尾。这样既保证了恢复速度,又尽可能保证了数据安全性。

Redis 复制与高可用

主从复制

Redis 支持主从复制功能,可以让多个 Redis 服务器拥有相同的数据副本。

配置主从复制

在从服务器的配置文件中添加:

# 指定主服务器的 IP 和端口
replicaof <masterip> <masterport>

# 如果主服务器设置了密码,需要配置密码
masterauth <master-password>

# 是否允许从服务器在复制过程中响应读请求
replica-serve-stale-data yes

# 从服务器是否只读
replica-read-only yes

或者在运行时使用命令:

bash
REPLICAOF <masterip> <masterport>
# 取消复制,使从服务器变为主服务器
REPLICAOF NO ONE

复制原理

  1. 全量复制:从服务器连接主服务器时,主服务器会创建 RDB 文件并发送给从服务器
  2. 部分复制:在断线重连后,主服务器只发送断线期间的写命令
  3. 异步复制:主服务器不会等待从服务器确认,可能导致数据不一致

Sentinel(哨兵)

Sentinel 是 Redis 的高可用解决方案,用于监控、通知和自动故障转移。

配置 Sentinel

创建 sentinel.conf 文件:

# 监控名为 mymaster 的主服务器,至少需要 2 个 Sentinel 同意才能进行故障转移
sentinel monitor mymaster 127.0.0.1 6379 2

# 主服务器或从服务器多长时间无响应视为下线(毫秒)
sentinel down-after-milliseconds mymaster 30000

# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 180000

# 同时进行故障转移的从服务器数量
sentinel parallel-syncs mymaster 1

# 如果主服务器设置了密码
sentinel auth-pass mymaster password

启动 Sentinel:

bash
redis-sentinel /path/to/sentinel.conf
# 或者
redis-server /path/to/sentinel.conf --sentinel

Sentinel 工作原理

  1. 监控:定期检查主从服务器是否正常运行
  2. 通知:当被监控的服务器出现问题时,通过 API 通知系统管理员
  3. 自动故障转移:当主服务器不可用时,选择一个从服务器升级为主服务器
  4. 配置提供者:客户端连接 Sentinel 获取当前主服务器地址

Redis Cluster

Redis Cluster 是 Redis 的分布式解决方案,支持数据自动分片和高可用性。

配置 Redis Cluster

在每个节点的配置文件中添加:

# 开启集群模式
cluster-enabled yes

# 集群配置文件(自动生成)
cluster-config-file nodes-6379.conf

# 节点超时时间(毫秒)
cluster-node-timeout 15000

# 是否需要所有槽都分配后集群才能上线
cluster-require-full-coverage yes

创建集群:

bash
# Redis 5.0+ 版本
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

Redis Cluster 工作原理

  1. 数据分片:使用哈希槽(hash slot)机制,共 16384 个槽
  2. 节点通信:使用 Gossip 协议进行节点间通信
  3. 故障检测:节点间互相监控,当主节点故障时,从节点会被提升为主节点
  4. 请求重定向:当客户端访问的键不在当前节点时,会返回 MOVED 或 ASK 错误进行重定向

Redis 性能优化

内存优化

  1. 合理设置 maxmemory:根据服务器可用内存设置 Redis 最大内存使用量

    maxmemory 2gb
  2. 选择合适的内存淘汰策略

    # 当内存达到上限时的淘汰策略
    maxmemory-policy allkeys-lru  # 所有键基于LRU算法淘汰
    # 其他选项:
    # volatile-lru:从设置了过期时间的键中选择最久未使用的键淘汰
    # allkeys-lru:从所有键中选择最久未使用的键淘汰
    # volatile-lfu:从设置了过期时间的键中选择最少使用的键淘汰
    # allkeys-lfu:从所有键中选择最少使用的键淘汰
    # volatile-random:从设置了过期时间的键中随机选择键淘汰
    # allkeys-random:从所有键中随机选择键淘汰
    # volatile-ttl:从设置了过期时间的键中选择将要过期的键淘汰
    # noeviction:不淘汰键,写入操作会报错
  3. 使用 Redis 数据结构压缩

    # 启用列表压缩
    list-compress-depth 1
    
    # 启用哈希压缩
    hash-max-ziplist-entries 512
    hash-max-ziplist-value 64

持久化优化

  1. 调整 RDB 保存频率

    # 减少保存频率,降低磁盘 I/O
    save 900 1
    save 300 10
    save 60 10000
  2. AOF 重写优化

    # 增加重写触发阈值
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
  3. 选择合适的 AOF 同步策略

    # 每秒同步一次,平衡性能和数据安全
    appendfsync everysec

连接优化

  1. 设置合理的连接数上限

    # 最大客户端连接数
    maxclients 10000
  2. 启用 TCP keepalive

    # 检测死连接
    tcp-keepalive 300
  3. 调整 TCP 缓冲区大小

    # 客户端输出缓冲区限制
    client-output-buffer-limit normal 0 0 0
    client-output-buffer-limit slave 256mb 64mb 60
    client-output-buffer-limit pubsub 32mb 8mb 60

命令优化

  1. 使用批量操作:使用 MSET、MGET 等批量命令代替多次单个操作
  2. 使用 Pipeline:将多个命令打包一次发送,减少网络往返
  3. 使用 Lua 脚本:将复杂操作封装在 Lua 脚本中,减少网络交互
  4. 避免使用高耗时命令:如 KEYS、SORT、LRANGE 等

Redis 安全最佳实践

  1. 设置强密码

    requirepass complex_password_here
  2. 禁用危险命令

    rename-command FLUSHALL ""
    rename-command FLUSHDB ""
    rename-command CONFIG ""
  3. 绑定特定 IP

    bind 127.0.0.1 192.168.1.100
  4. 启用 TLS 加密(Redis 6.0+):

    tls-port 6379
    tls-cert-file /path/to/cert.pem
    tls-key-file /path/to/key.pem
    tls-ca-cert-file /path/to/ca.pem
  5. 设置访问控制列表(Redis 6.0+):

    # 创建用户
    ACL SETUSER alice on >password ~* +@all -@dangerous

Redis 常见问题与解决方案

内存占用过高

  1. 分析内存使用情况

    bash
    # 查看内存使用情况
    INFO memory
    # 分析键的内存占用
    MEMORY USAGE key
  2. 解决方案

    • 设置合理的过期时间
    • 使用更紧凑的数据结构
    • 增加内存或分片数据

性能下降

  1. 分析慢查询

    bash
    # 查看慢查询日志
    SLOWLOG GET 10
  2. 解决方案

    • 优化数据结构和命令
    • 使用 Pipeline 减少网络往返
    • 考虑使用 Redis Cluster 分担负载

持久化问题

  1. RDB 保存失败

    • 检查磁盘空间
    • 调整保存频率
    • 监控 fork 时间
  2. AOF 文件过大

    • 定期执行 BGREWRITEAOF
    • 调整自动重写参数

总结

Redis 是一个功能强大、高性能的内存数据库,广泛应用于缓存、会话管理、消息队列等场景。通过本教程,我们学习了 Redis 的基本概念、数据类型、高级特性、持久化、复制、集群以及性能优化等内容。

希望这份教程能帮助你更好地理解和使用 Redis,充分发挥其在应用开发中的价值。

参考资源


本文档将持续更新,如有问题请通过 GitHub Issues 反馈。

安装与配置

在不同平台上安装 Redis

Linux (Ubuntu/Debian)

bash
# 更新包列表
sudo apt update

# 安装 Redis
sudo apt install redis-server

# 启动 Redis 服务
sudo systemctl start redis-server

# 设置开机自启
sudo systemctl enable redis-server

# 检查 Redis 状态
sudo systemctl status redis-server

macOS

使用 Homebrew 安装:

bash
# 安装 Homebrew(如果尚未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安装 Redis
brew install redis

# 启动 Redis 服务
brew services start redis

# 检查 Redis 状态
brew services info redis

Windows

Windows 不是 Redis 的官方支持平台,但可以通过以下方式使用:

  1. 使用 WSL(Windows Subsystem for Linux)安装 Linux 版本的 Redis
  2. 使用 Microsoft 的 Redis 分支
  3. 使用 Docker 运行 Redis 容器

Docker

bash
# 拉取 Redis 镜像
docker pull redis:latest

# 运行 Redis 容器
docker run --name my-redis -p 6379:6379 -d redis

# 连接到 Redis 容器
docker exec -it my-redis redis-cli

基本配置

Redis 的配置文件通常位于 /etc/redis/redis.conf(Linux)或 /usr/local/etc/redis.conf(macOS)。以下是一些重要的配置项:

conf
# 绑定地址(默认只允许本地连接)
bind 127.0.0.1

# 端口
port 6379

# 密码认证
requirepass yourpassword

# 最大内存限制
maxmemory 100mb

# 内存淘汰策略
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1      # 900秒内至少有1个key变化,则触发保存
save 300 10     # 300秒内至少有10个key变化,则触发保存
save 60 10000   # 60秒内至少有10000个key变化,则触发保存

# AOF 持久化
appendonly yes
appendfilename "appendonly.aof"

连接到 Redis

bash
# 本地连接
redis-cli

# 远程连接
redis-cli -h host -p port -a password

# 使用密码连接
redis-cli
> AUTH yourpassword

Redis 数据类型

字符串(String)

字符串是 Redis 最基本的数据类型,可以存储文本、整数或二进制数据。

bash
# 设置字符串
SET key value
SET name "John Doe"
SET counter 100

# 获取字符串
GET key
GET name  # 返回 "John Doe"

# 设置过期时间(秒)
SETEX key seconds value
SETEX session 3600 "user123"

# 原子递增/递减
INCR counter    # 将 counter 加 1
INCRBY counter 10  # 将 counter 加 10
DECR counter    # 将 counter 减 1
DECRBY counter 5   # 将 counter 减 5

# 同时设置/获取多个值
MSET key1 value1 key2 value2
MGET key1 key2

哈希(Hash)

哈希是字段和值的映射,适合存储对象。

bash
# 设置哈希字段
HSET key field value
HSET user:1000 name "John Doe"
HSET user:1000 email "john@example.com"
HSET user:1000 age 30

# 获取哈希字段
HGET key field
HGET user:1000 name  # 返回 "John Doe"

# 获取所有字段和值
HGETALL key
HGETALL user:1000

# 检查字段是否存在
HEXISTS key field
HEXISTS user:1000 name  # 返回 1(存在)

# 删除字段
HDEL key field [field ...]
HDEL user:1000 age

# 增加数字
HINCRBY key field increment
HINCRBY user:1000 age 5  # 将 age 增加 5

列表(List)

列表是简单的字符串列表,按照插入顺序排序。

bash
# 从左侧插入元素
LPUSH key value [value ...]
LPUSH mylist "world"
LPUSH mylist "hello"

# 从右侧插入元素
RPUSH key value [value ...]
RPUSH mylist "!"

# 获取列表范围
LRANGE key start stop
LRANGE mylist 0 -1  # 获取所有元素,返回 ["hello", "world", "!"]

# 从左侧弹出元素
LPOP key
LPOP mylist  # 返回 "hello"

# 从右侧弹出元素
RPOP key
RPOP mylist  # 返回 "!"

# 获取列表长度
LLEN key
LLEN mylist  # 返回 1

# 根据索引获取元素
LINDEX key index
LINDEX mylist 0  # 返回 "world"

集合(Set)

集合是字符串的无序集合,不允许重复成员。

bash
# 添加成员
SADD key member [member ...]
SADD myset "apple"
SADD myset "banana" "orange"

# 获取所有成员
SMEMBERS key
SMEMBERS myset  # 返回 ["apple", "banana", "orange"]

# 判断成员是否存在
SISMEMBER key member
SISMEMBER myset "apple"  # 返回 1(存在)

# 获取集合成员数
SCARD key
SCARD myset  # 返回 3

# 删除成员
SREM key member [member ...]
SREM myset "banana"

# 集合操作
SUNION key [key ...]  # 并集
SINTER key [key ...]  # 交集
SDIFF key [key ...]   # 差集

有序集合(Sorted Set)

有序集合类似于集合,但每个成员关联一个分数,用于排序。

bash
# 添加成员和分数
ZADD key score member [score member ...]
ZADD leaderboard 100 "user1"
ZADD leaderboard 85 "user2" 95 "user3"

# 获取成员排名(从小到大)
ZRANK key member
ZRANK leaderboard "user1"  # 返回 2

# 获取成员排名(从大到小)
ZREVRANK key member
ZREVRANK leaderboard "user1"  # 返回 0

# 获取指定排名范围的成员
ZRANGE key start stop [WITHSCORES]
ZRANGE leaderboard 0 -1  # 返回 ["user2", "user3", "user1"]
ZRANGE leaderboard 0 -1 WITHSCORES  # 返回 ["user2", "85", "user3", "95", "user1", "100"]

# 获取指定分数范围的成员
ZRANGEBYSCORE key min max [WITHSCORES]
ZRANGEBYSCORE leaderboard 90 100  # 返回 ["user3", "user1"]

# 增加成员分数
ZINCRBY key increment member
ZINCRBY leaderboard 10 "user2"  # 将 user2 的分数增加 10

# 获取成员数量
ZCARD key
ZCARD leaderboard  # 返回 3

# 获取成员分数
ZSCORE key member
ZSCORE leaderboard "user1"  # 返回 "100"

位图(Bitmap)

位图不是独立的数据类型,而是基于字符串的位操作。

bash
# 设置位
SETBIT key offset value
SETBIT users:active 123 1  # 将用户ID为123的用户标记为活跃

# 获取位
GETBIT key offset
GETBIT users:active 123  # 返回 1

# 统计位图中值为1的位数
BITCOUNT key [start end]
BITCOUNT users:active  # 返回活跃用户数

# 位操作
BITOP operation destkey key [key ...]
BITOP AND result users:active:week1 users:active:week2  # 两周都活跃的用户

HyperLogLog

HyperLogLog 用于估计集合中不重复元素的数量,占用空间极小。

bash
# 添加元素
PFADD key element [element ...]
PFADD visitors user1 user2 user3

# 获取基数估计
PFCOUNT key [key ...]
PFCOUNT visitors  # 返回 3

# 合并多个 HyperLogLog
PFMERGE destkey sourcekey [sourcekey ...]
PFMERGE total_visitors daily_visitors weekly_visitors

地理空间(Geo)

地理空间用于存储地理位置信息。

bash
# 添加地理位置
GEOADD key longitude latitude member [longitude latitude member ...]
GEOADD locations 116.40 39.90 "Beijing" 121.47 31.23 "Shanghai"

# 计算两地距离
GEODIST key member1 member2 [unit]
GEODIST locations "Beijing" "Shanghai" km  # 返回两地距离(千米)

# 获取坐标
GEOPOS key member [member ...]
GEOPOS locations "Beijing"  # 返回北京的经纬度

# 查找指定范围内的位置
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
GEORADIUS locations 116.40 39.90 1000 km  # 返回北京1000公里范围内的城市

流(Stream)

流是 Redis 5.0 引入的新数据类型,用于消息队列。

bash
# 添加消息
XADD key ID field value [field value ...]
XADD mystream * sensor-id 1234 temperature 19.8

# 读取消息
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XREAD COUNT 2 STREAMS mystream 0  # 从头开始读取最多2条消息

# 创建消费者组
XGROUP CREATE key groupname ID
XGROUP CREATE mystream mygroup $  # $ 表示从最新消息开始

# 消费者组读取
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
XREADGROUP GROUP mygroup consumer1 STREAMS mystream >  # > 表示未被组内消费的消息

Redis 高级特性

事务

Redis 事务允许在一个步骤中执行一组命令。

bash
# 开始事务
MULTI

# 命令入队
SET user:1:name "John"
SET user:1:email "john@example.com"
INCR visitors

# 执行事务
EXEC

# 取消事务
DISCARD

发布/订阅

Redis 提供了发布/订阅功能,用于消息通信。

bash
# 订阅频道
SUBSCRIBE channel [channel ...]
SUBSCRIBE news

# 发布消息
PUBLISH channel message
PUBLISH news "Breaking news!"

# 模式订阅
PSUBSCRIBE pattern [pattern ...]
PSUBSCRIBE news.*

# 取消订阅
UNSUBSCRIBE [channel [channel ...]]
PUNSUBSCRIBE [pattern [pattern ...]]

Lua 脚本

Redis 支持使用 Lua 脚本执行复杂操作。

bash
# 执行 Lua 脚本
EVAL script numkeys key [key ...] arg [arg ...]

# 示例:原子计数器
EVAL "local current = redis.call('get', KEYS[1]) or 0; \
       local new = tonumber(current) + tonumber(ARGV[1]); \
       redis.call('set', KEYS[1], new); \
       return new;" 1 counter 5

# 加载脚本到缓存
SCRIPT LOAD "return redis.call('get', KEYS[1])"
# 返回 SHA1 校验和,如 "a42059b356c875f0717db19a51f6aaca9ae659ea"

# 使用缓存的脚本
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
EVALSHA "a42059b356c875f0717db19a51f6aaca9ae659ea" 1 mykey

管道(Pipeline)

管道允许一次性发送多个命令,减少网络往返时间。

bash
# 使用 redis-cli 的管道模式
echo -e "SET key1 value1\nSET key2 value2\nGET key1\nGET key2" | redis-cli --pipe

在编程语言中使用管道:

python
# Python 示例
import redis
r = redis.Redis()
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.get('key1')
pipe.get('key2')
results = pipe.execute()

Redis 持久化

RDB(Redis Database)

RDB 通过创建数据快照实现持久化。

conf
# redis.conf 配置
save 900 1      # 900秒内至少有1个key变化,则触发保存
save 300 10     # 300秒内至少有10个key变化,则触发保存
save 60 10000   # 60秒内至少有10000个key变化,则触发保存

dbfilename dump.rdb  # RDB 文件名
dir ./               # RDB 文件存储路径

手动触发 RDB:

bash
# 同步保存
SAVE

# 异步保存
BGSAVE

AOF(Append Only File)

AOF 通过记录所有写操作命令实现持久化。

conf
# redis.conf 配置
appendonly yes
appendfilename "appendonly.aof"

# 同步策略
appendfsync always  # 每个写命令都同步,最安全,最慢
appendfsync everysec  # 每秒同步一次,平衡安全和性能
appendfsync no  # 由操作系统决定何时同步,最快,最不安全

AOF 重写(压缩 AOF 文件):

bash
# 手动触发 AOF 重写
BGREWRITEAOF

混合持久化

Redis 4.0 引入了混合持久化,结合了 RDB 和 AOF 的优点。

conf
# redis.conf 配置
aof-use-rdb-preamble yes

Redis 复制与高可用

主从复制

主从复制允许从服务器复制主服务器的数据。

conf
# 在从服务器的 redis.conf 中配置
replicaof <masterip> <masterport>
# 或者使用旧版命令
# slaveof <masterip> <masterport>

# 如果主服务器有密码
masterauth <master-password>

在运行时配置复制:

bash
# 在从服务器上执行
REPLICAOF masterip masterport
# 或者使用旧版命令
# SLAVEOF masterip masterport

# 停止复制,成为主服务器
REPLICAOF NO ONE

哨兵(Sentinel)

哨兵用于监控和自动故障转移。

创建 sentinel.conf 文件:

conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

启动哨兵:

bash
redis-sentinel sentinel.conf
# 或者
redis-server sentinel.conf --sentinel

Redis 集群

Redis 集群提供数据分片和高可用性。

conf
# redis.conf 集群配置
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000

创建集群:

bash
# 使用 redis-cli 创建集群
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

集群操作:

bash
# 连接到集群
redis-cli -c -p 7000

# 查看集群信息
CLUSTER INFO

# 查看集群节点
CLUSTER NODES

Redis 安全

设置密码

conf
# redis.conf 配置
requirepass yourpassword

或者在运行时设置:

bash
CONFIG SET requirepass "yourpassword"

连接时使用密码:

bash
redis-cli -a yourpassword
# 或者
redis-cli
> AUTH yourpassword

禁用危险命令

conf
# redis.conf 配置
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""

网络安全

conf
# redis.conf 配置
bind 127.0.0.1  # 只监听本地连接
protected-mode yes  # 保护模式

访问控制列表(ACL)

Redis 6.0 引入了 ACL:

bash
# 创建用户
ACL SETUSER myuser on >password ~* +@all -@dangerous

# 查看用户
ACL LIST

# 使用用户认证
AUTH myuser password

Redis 性能优化

内存优化

conf
# redis.conf 配置
maxmemory 1gb
maxmemory-policy allkeys-lru  # 内存不足时的淘汰策略

内存淘汰策略:

  • noeviction:不淘汰,写入操作报错
  • allkeys-lru:淘汰最近最少使用的键
  • volatile-lru:淘汰设置了过期时间的键中最近最少使用的
  • allkeys-random:随机淘汰
  • volatile-random:随机淘汰设置了过期时间的键
  • volatile-ttl:淘汰即将过期的键

使用 pipelining 减少网络开销

python
# Python 示例
import redis
r = redis.Redis()
pipe = r.pipeline()
for i in range(10000):
    pipe.set(f'key:{i}', f'value:{i}')
pipe.execute()

合理使用数据结构

  • 对于简单键值对,使用 String
  • 对于对象,使用 Hash
  • 对于列表数据,使用 List
  • 对于唯一性集合,使用 Set
  • 对于需要排序的集合,使用 Sorted Set

使用 Redis 模块扩展功能

  • RedisJSON:原生 JSON 支持
  • RediSearch:全文搜索引擎
  • RedisTimeSeries:时间序列数据库
  • RedisGraph:图数据库
  • RedisBloom:概率数据结构

Redis 应用场景

缓存

python
# Python 示例:缓存模式
import redis
import json

r = redis.Redis()

def get_user(user_id):
    # 尝试从缓存获取
    user_json = r.get(f'user:{user_id}')
    if user_json:
        return json.loads(user_json)
    
    # 缓存未命中,从数据库获取
    user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
    
    # 存入缓存(设置过期时间)
    r.setex(f'user:{user_id}', 3600, json.dumps(user))
    
    return user

会话存储

python
# Python 示例:会话存储
import redis
import json
import uuid

r = redis.Redis()

def create_session(user_id):
    session_id = str(uuid.uuid4())
    session_data = {
        'user_id': user_id,
        'login_time': datetime.now().isoformat(),
        'data': {}
    }
    
    # 存储会话(30分钟过期)
    r.setex(f'session:{session_id}', 1800, json.dumps(session_data))
    
    return session_id

def get_session(session_id):
    session_json = r.get(f'session:{session_id}')
    if not session_json:
        return None
    
    # 刷新过期时间
    r.expire(f'session:{session_id}', 1800)
    
    return json.loads(session_json)

排行榜

python
# Python 示例:游戏排行榜
import redis

r = redis.Redis()

def update_score(user_id, score):
    # 更新用户分数
    r.zadd('leaderboard', {user_id: score})

def get_top_players(count=10):
    # 获取前N名玩家
    return r.zrevrange('leaderboard', 0, count-1, withscores=True)

def get_user_rank(user_id):
    # 获取用户排名(从0开始)
    rank = r.zrevrank('leaderboard', user_id)
    return rank + 1 if rank is not None else None

限流器

python
# Python 示例:简单限流器
import redis
import time

r = redis.Redis()

def is_rate_limited(user_id, limit=10, period=60):
    # 键名
    key = f'ratelimit:{user_id}'
    
    # 当前时间
    now = int(time.time())
    
    # 管道操作
    pipe = r.pipeline()
    
    # 添加当前时间戳到有序集合
    pipe.zadd(key, {now: now})
    
    # 移除过期的时间戳
    pipe.zremrangebyscore(key, 0, now - period)
    
    # 设置过期时间
    pipe.expire(key, period)
    
    # 获取集合大小
    pipe.zcard(key)
    
    # 执行
    _, _, _, count = pipe.execute()
    
    # 检查是否超过限制
    return count > limit

消息队列

python
# Python 示例:简单消息队列
import redis
import json

r = redis.Redis()

def publish_message(queue_name, message):
    # 将消息添加到列表末尾
    r.rpush(queue_name, json.dumps(message))

def consume_message(queue_name, timeout=0):
    # 从列表左侧弹出消息(阻塞操作)
    result = r.blpop(queue_name, timeout)
    if result:
        _, message_json = result
        return json.loads(message_json)
    return None

使用 Stream 实现更可靠的消息队列:

python
# Python 示例:使用 Stream 的消息队列
import redis
import json

r = redis.Redis()

def publish_message(stream_name, message):
    # 添加消息到流
    return r.xadd(stream_name, message)

def create_consumer_group(stream_name, group_name):
    try:
        # 创建消费者组,从最新消息开始
        r.xgroup_create(stream_name, group_name, id='$', mkstream=True)
    except redis.exceptions.ResponseError as e:
        # 组已存在
        if 'BUSYGROUP' not in str(e):
            raise

def consume_messages(stream_name, group_name, consumer_name, count=1):
    # 读取未被组内消费的消息
    messages = r.xreadgroup(group_name, consumer_name, {stream_name: '>'}, count=count)
    
    if not messages:
        return []
    
    stream_messages = messages[0][1]
    result = []
    
    for message_id, message in stream_messages:
        # 处理消息
        result.append((message_id, message))
        
        # 确认消息已处理
        r.xack(stream_name, group_name, message_id)
    
    return result

分布式锁

python
# Python 示例:分布式锁
import redis
import uuid
import time

r = redis.Redis()

def acquire_lock(lock_name, timeout=10):
    # 生成唯一标识符
    identifier = str(uuid.uuid4())
    
    # 获取锁(NX: 只在键不存在时设置,EX:
---
title: "Redis 教程:从入门到精通"
description: "全面学习 Redis 数据库,掌握数据类型、持久化、事务、集群等核心功能,提升应用性能与可扩展性"
head:
  - - meta
    - name: keywords
      content: "Redis,缓存,NoSQL,数据库,键值存储,持久化,事务,集群,高可用,性能优化"
  - - meta
    - property: og:title
      content: "Redis 教程:从入门到精通 - 技术文档"
  - - meta
    - property: og:description
      content: "全面学习 Redis 数据库,掌握数据类型、持久化、事务、集群等核心功能,提升应用性能与可扩展性"
outline: deep
lastUpdated: true
---

# Redis 教程:从入门到精通

Redis 是一个开源的、基于内存的高性能键值数据库,被广泛应用于缓存、会话存储、消息队列等场景。本教程将帮助你全面了解 Redis 的核心概念和使用方法。

## Redis 简介

### 什么是 Redis?

Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种数据类型,如字符串、哈希表、列表、集合、有序集合等,并且提供了丰富的操作命令。

### Redis 的主要特点

- **高性能**:基于内存操作,读写速度极快
- **丰富的数据类型**:支持字符串、哈希、列表、集合、有序集合等
- **原子操作**:所有操作都是原子性的,支持事务
- **持久化**:支持数据持久化到磁盘(RDBAOF
- **主从复制**:支持主从复制和高可用
- **分布式**:支持集群模式,可水平扩展
- **Lua 脚本**:支持 Lua 脚本执行复杂操作
- **发布/订阅**:支持消息的发布与订阅

### Redis 与传统数据库的比较

| 特性 | Redis | 关系型数据库 |
|------|-------|------------|
| 数据模型 | 键值存储 | 表格关系模型 |
| 存储方式 | 内存(可持久化) | 磁盘 |
| 查询语言 | 简单命令 | SQL |
| 事务支持 | 基本支持 | 完全支持 |
| 性能 | 极高 | 中等 |
| 扩展性 | 主从复制、集群 | 主从复制、分库分表 |
| 适用场景 | 缓存、会话、计数器、排行榜 | 复杂查询、事务处理 |

vitepress开发指南