𝑻𝒆𝒏𝑪𝒍𝒂𝒘正在头脑风暴···
𝑻𝒆𝒏𝑲𝒊𝑺𝒆𝒀𝒂の𝑨𝒈𝒆𝒏𝒕助手
𝑻𝒆𝒏-𝒇𝒍𝒂𝒔𝒉

Redis 缓存数据库完全指南

Redis 是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息中间件。本文将全面介绍 Redis 的核心概念、数据结构、常用命令和实战应用。

一、Redis 简介

1.1 什么是 Redis?

Redis 是一个基于内存的键值对存储系统,支持多种数据结构,提供高性能的数据读写操作。它通常用于缓存、会话存储、排行榜等场景。

1.2 Redis 的特点

  1. 高性能:数据存储在内存中,读写速度极快
  2. 丰富的数据结构:支持字符串、列表、集合、有序集合等
  3. 持久化:支持 RDB 和 AOF 两种持久化方式
  4. 高可用:支持主从复制和集群模式
  5. 原子操作:支持多种原子操作命令

1.3 Redis 的应用场景

  • 缓存:加速数据访问
  • 会话存储:管理用户会话
  • 排行榜:实时排行榜功能
  • 消息队列:基于 Pub/Sub 和 List 的消息队列
  • 计数器:计数功能
  • 限流:防止恶意请求

二、安装和配置

2.1 安装 Redis

Linux 安装

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

# CentOS/RHEL
sudo yum install redis

# 启动 Redis
sudo systemctl start redis
sudo systemctl enable redis

# 查看状态
redis-cli ping
# 输出: PONG

Docker 安装

# 拉取 Redis 镜像
docker pull redis:latest

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

# 连接 Redis
docker exec -it redis redis-cli

2.2 基础配置

修改 redis.conf 文件:

# 绑定地址
bind 127.0.0.1

# 端口
port 6379

# 密码认证
requirepass yourpassword

# 数据库数量
databases 16

# 持久化
save 900 1 # 900秒内至少1个key变化
save 300 10 # 300秒内至少10个key变化
save 60 10000 # 60秒内至少10000个key变化

三、数据结构

3.1 String(字符串)

基础操作

# 设置键值对
SET name "张三"
SET age "25"

# 获取值
GET name
GET age

# 设置过期时间
SETEX session:1 3600 "value" # 1小时后过期
SET user:1:token abc123 EX 3600 # 1小时后过期

# 递增和递减
INCR counter
DECR counter
INCRBY counter 10
DECRBY counter 5

# 获取当前值并递增
GETSET counter 0

# 批量操作
MSET key1 value1 key2 value2
MGET key1 key2 key3

# 追加字符串
APPEND message " world"
GET message # 输出: "Hello world"

# 子串操作
GETRANGE key 0 4 # 获取前5个字符
SETRANGE key 0 "X" # 替换前1个字符

应用场景

  • 缓存数据
  • 计数器
  • 分布式锁

3.2 Hash(哈希)

基础操作

# 设置哈希字段
HSET user:1 name "张三"
HSET user:1 age "25"
HSET user:1 email "zhangsan@example.com"

# 批量设置
HMSET user:2 name "李四" age "30" email "lisi@example.com"

# 获取字段
HGET user:1 name # 获取单个字段
HGETALL user:1 # 获取所有字段和值
HGETALL user:2

# 获取所有字段名
HKEYS user:1
# 输出: ["name", "age", "email"]

# 获取所有字段值
HVALS user:1
# 输出: ["张三", "25", "zhangsan@example.com"]

# 获取字段数量
HLEN user:1
# 输出: 3

# 修改字段
HSET user:1 name "王五"

# 删除字段
HDEL user:1 age

# 判断字段是否存在
HEXISTS user:1 email
# 输出: 1 (true)

# 增加数字
HINCRBY user:1 age 1
# age 从 25 变为 26

# 获取字段类型
HTYPE user:1
# 输出: hash

应用场景

  • 存储对象
  • 用户信息
  • 商品信息

3.3 List(列表)

基础操作

# 左侧插入
LPUSH tasks "任务1"
LPUSH tasks "任务2"
LPUSH tasks "任务3"

# 右侧插入
RPUSH messages "消息1"
RPUSH messages "消息2"

# 获取列表(从左到右)
LRANGE tasks 0 -1
# 输出: ["任务3", "任务2", "任务1"]

# 获取指定范围
LRANGE tasks 0 1 # 前2个元素
LRANGE tasks 1 -1 # 从第2个到最后

# 获取列表长度
LLEN tasks
# 输出: 3

# 获取左端元素(不移除)
LINDEX tasks 0
# 输出: "任务3"

# 获取右端元素(不移除)
RPOP tasks
# 输出: "任务1"

# 从左侧弹出(移除并返回)
LPOP tasks
# 输出: "任务3"(从左侧移除)

# 从右侧弹出(移除并返回)
RPOP tasks
# 输出: "任务1"(从右侧移除)

# 修剪列表(保留指定范围)
LTRIM tasks 0 1
# 只保留前2个元素

# 替换列表元素
LSET tasks 0 "新任务"

# 批量插入
LPUSHX tasks "新任务1" # 只有当tasks存在时才插入
RPUSHX tasks "新任务2"

# 从列表右侧弹入并推送到另一个列表
RPOPLPUSH tasks tasks_backup

应用场景

  • 队列
  • 消息列表
  • 时间线

3.4 Set(集合)

基础操作

# 添加元素
SADD tags "编程" "JavaScript" "Python" "Go"

# 获取所有元素
SMEMBERS tags
# 输出: ["Python", "Go", "JavaScript", "编程"]

# 检查元素是否存在
SISMEMBER tags "Python"
# 输出: 1 (true)

# 获取集合大小
SCARD tags
# 输出: 4

# 移除元素
SREM tags "JavaScript"
SMEMBERS tags
# 输出: ["Python", "Go", "编程"]

# 随机获取元素
SRANDMEMBER tags # 获取1个随机元素
SRANDMEMBER tags 2 # 获取2个随机元素

# 移除并返回随机元素
SPOP tags
# 输出: 随机元素

# 删除整个集合
DEL tags

集合操作

# 并集
SADD users:1 "张三"
SADD users:2 "李四"
SADD users:3 "王五"
SUNION users:1 users:2 users:3

# 交集
SINTER users:1 users:2

# 差集
SDIFF users:1 users:2

# 差集(A - B)
SDIFF users:1 users:2

# 差集(B - A)
SDIFF users:2 users:1

# 差集存储
SDIFFSTORE diff users:1 users:2

应用场景

  • 标签
  • 关注关系
  • 去重
  • 共同好友

3.5 Sorted Set(有序集合)

基础操作

# 添加成员
ZADD leaderboard 100 "player1"
ZADD leaderboard 200 "player2"
ZADD leaderboard 150 "player3"

# 获取所有成员(按分数排序)
ZRANGE leaderboard 0 -1 WITHSCORES
# 输出:
# 1) "player1"
# 2) "100"
# 3) "player3"
# 4) "150"
# 5) "player2"
# 6) "200"

# 获取指定范围(从低到高)
ZRANGE leaderboard 0 1 # 前2个
ZRANGE leaderboard 1 2 # 第2-3个

# 获取指定范围(从高到低)
ZREVRANGE leaderboard 0 1 # 前2个(最高分)

# 获取指定分数范围
ZRANGEBYSCORE leaderboard 0 200
ZRANGEBYSCORE leaderboard 0 100 WITHSCORES

# 获取指定分数成员
ZRANGEBYSCORE leaderboard 100 200 WITHSCORES

# 获取排名
ZRANK leaderboard "player1" # 从低到高排名
ZREVRANK leaderboard "player1" # 从高到低排名

# 增加分数
ZINCRBY leaderboard 50 "player1"

# 获取指定排名的成员
ZRANGE leaderboard 0 0 # 第1名
ZREVRANGE leaderboard 0 0 # 第1名(最高分)

# 获取指定成员的分数
ZSCORE leaderboard "player1"

# 移除成员
ZREM leaderboard "player1"

应用场景

  • 排行榜
  • 延时队列
  • 带权重的优先队列

四、高级功能

4.1 发布订阅

# 发布消息
PUBLISH topic:news "这是新闻"
PUBLISH topic:news "这是最新的新闻"

# 订阅频道
SUBSCRIBE topic:news
# 输出:
# 1) "message"
# 2) "topic:news"
# 3) "这是新闻"

# 订阅多个频道
SUBSCRIBE topic:news topic:sports topic:tech

# 订阅频道
SUBSCRIBE #news #sports #tech

# 取消订阅
UNSUBSCRIBE topic:news

# 查看活跃频道
PUBSUB NUMSUB topic:news topic:sports

4.2 事务

# 开始事务
MULTI

# 执行命令(不立即执行)
SET key1 "value1"
SET key2 "value2"
INCR counter

# 执行事务
EXEC
# 输出:
# 1) "OK"
# 2) "OK"
# 3) "1"

# 取消事务
MULTI
SET key1 "value1"
SET key2 "value2"
DISCARD
# 输出: "OK"

4.3 过期时间

# 设置过期时间
SETEX session:1 3600 "value" # 1小时后过期

# 设置过期时间(秒)
EXPIRE key 300 # 5分钟后过期

# 设置过期时间(毫秒)
PEXPIRE key 300000 # 5分钟后过期

# 查看过期时间(秒)
TTL key
# 输出: 299 (秒后过期)

# 查看过期时间(毫秒)
PTTL key
# 输出: 299000 (毫秒后过期)

# 查看过期时间(永不过期)
TTL key
# 输出: -1 (永不过期)

# 设置为永不过期
PERSIST key

# 查看剩余生存时间(秒)
TTL key
# 输出: 299

# 查看剩余生存时间(毫秒)
PTTL key
# 输出: 299000

# 删除过期时间
PERSIST key

4.4 Lua 脚本

# 创建脚本文件
# redis_script.lua
local key = KEYS[1]
local value = ARGV[1]
redis.call('SET', key, value)
return redis.call('GET', key)

# 在 Redis CLI 中执行
redis-cli --eval redis_script.lua, key, value

# 或者使用 EVAL 命令
redis-cli EVAL "$(cat redis_script.lua)" 1 key value

4.5 服务器信息

# 获取服务器信息
INFO

# 获取特定信息
INFO server
INFO clients
INFO memory
INFO stats
INFO replication

# 查看客户端连接
CLIENT LIST

# 关闭客户端
CLIENT KILL ip:port

# 设置客户端名称
CLIENT SETNAME my_app

# 查看数据库信息
DBSIZE # 数据库中键的总数
DBSIZE
# 输出: 123

# 清空当前数据库
FLUSHDB # 清空当前数据库

# 清空所有数据库
FLUSHALL # 清空所有数据库

五、持久化

5.1 RDB 持久化

RDB(Redis Database)是 Redis 默认的持久化方式。

配置

# 在 redis.conf 中配置
save 900 1 # 15分钟内至少1个key变化
save 300 10 # 5分钟内至少10个key变化
save 60 10000 # 60秒内至少10000个key变化

# 停止 RDB
save ""

# 生成 RDB 文件
BGSAVE

# RDB 文件位置
dir /var/lib/redis
dbfilename dump.rdb

工作原理

  1. 根据配置的规则定期保存
  2. RDBSAVE 命令手动保存
  3. RDBAFTER 命令 fork 子进程保存

5.2 AOF 持久化

AOF(Append Only File)记录所有写操作。

配置

# 在 redis.conf 中配置
appendonly yes

# 持久化策略
appendfsync everysec # 每秒同步一次(推荐)
appendfsync always # 每次写都同步
appendfsync no # 依赖操作系统缓存

# 文件名
appendfilename "appendonly.aof"

# 重写策略
auto-aof-rewrite-percentage 100 # AOF 文件大小增长100%时重写
auto-aof-rewrite-min-size 64mb # AOF 文件至少64MB时重写

工作原理

  1. 记录所有写操作到 AOF 文件
  2. 定期重写 AOF 文件(压缩)

命令

# 启用 AOF
CONFIG SET appendonly yes

# 禁用 AOF
CONFIG SET appendonly no

# 手动重写 AOF
BGREWRITEAOF

# 查看 AOF 状态
INFO persistence

六、性能优化

6.1 内存优化

# 查看内存使用情况
INFO memory

# 使用 Hash 结构优化
# 优化前:多个 String
SET user:1:name "张三"
SET user:1:age "25"
SET user:1:email "zhang@example.com"

# 优化后:单个 Hash
HSET user:1 name "张三" age "25" email "zhang@example.com"

# 设置最大内存
CONFIG SET maxmemory 2gb

6.2 网络优化

# 减少网络往返
PIPELINE
MSET key1 value1 key2 value2
MGET key1 key2

# 使用 Pipeline
redis-cli --pipe < commands.txt

6.3 连接优化

# 设置最大连接数
CONFIG SET maxclients 10000

# 设置超时时间
CONFIG SET timeout 300

七、实战应用

7.1 缓存实现

import redis

# 创建 Redis 连接
r = redis.Redis(host='localhost', port=6379, db=0)

# 设置缓存
r.setex('user:1:info', 3600, '{"name":"张三","age":25}')

# 获取缓存
data = r.get('user:1:info')
print(data) # b'{"name":"张三","age":25}'

# 检查缓存是否存在
if r.exists('user:1:info'):
data = r.get('user:1:info')
else:
# 从数据库获取
data = get_user_from_db(1)
# 设置缓存
r.setex('user:1:info', 3600, data)

7.2 排行榜

import redis

r = redis.Redis(host='localhost', port=6379, db=0)

# 增加分数
r.zincrby('scoreboard', 10, 'player1')

# 获取排行榜
scores = r.zrevrange('scoreboard', 0, 9, withscores=True)
for rank, (player, score) in enumerate(scores, 1):
print(f"{rank}. {player}: {score}")

7.3 限流

import redis

r = redis.Redis(host='localhost', port=6379, db=0)

def check_rate_limit(key, limit, window):
"""检查是否超过限流"""
current = r.incr(key)
if current == 1:
r.expire(key, window)

return current <= limit

# 每分钟最多100次请求
if check_rate_limit('rate_limit:api', 100, 60):
# 执行业务逻辑
pass
else:
print("请求过于频繁,请稍后再试")

八、最佳实践

8.1 命名规范

# 使用冒号分隔
user:1:profile
user:2:profile
cache:user:1

# 使用连字符
api-endpoint
request-id

8.2 错误处理

try:
r.set('key', 'value')
except redis.RedisError as e:
print(f"Redis 错误: {e}")

8.3 安全建议

  1. 启用密码认证
  2. 限制访问 IP
  3. 使用 SSL 连接
  4. 定期备份数据
  5. 监控 Redis 状态

九、总结

Redis 的核心优势:

  1. 高性能:内存存储,读写速度快
  2. 丰富的数据结构:支持多种数据结构
  3. 持久化:支持 RDB 和 AOF 两种持久化
  4. 高可用:支持主从复制和集群

常用命令:

# 基础命令
SET key value
GET key
DEL key

# String 命令
INCR key
DECR key
SETEX key seconds value

# Hash 命令
HSET key field value
HGET key field
HGETALL key

# List 命令
LPUSH key value
RPOP key
LRANGE key start stop

# Set 命令
SADD key member
SMEMBERS key
SISMEMBER key member

# Sorted Set 命令
ZADD key score member
ZRANGE key start stop
ZINCRBY key increment member

掌握 Redis,可以构建高性能的应用程序!