01-Redis基础

4 阅读11分钟

Redis 基础知识

Redis 入门必备,掌握核心数据类型和基本操作

1. Redis 简介

1.1 什么是 Redis?

Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,可以用作:

  • 数据库:持久化的 NoSQL 数据库
  • 缓存:高性能的缓存系统
  • 消息队列:基于 List、Stream 的消息队列

1.2 Redis 特点

  • 高性能:读写速度极快(10万+ QPS)
  • 丰富的数据类型:String、Hash、List、Set、Sorted Set 等
  • 持久化:RDB、AOF 两种持久化方式
  • 原子性:所有操作都是原子性的
  • 高可用:主从复制、哨兵、集群
  • 简单易用:命令简单,容易上手

1.3 为什么 Redis 快?

  1. 纯内存操作:数据存储在内存中
  2. 单线程模型:避免线程切换和锁竞争
  3. IO 多路复用:epoll/kqueue 高效处理网络 IO
  4. 高效的数据结构:底层使用优化的数据结构

1.4 应用场景

  • 缓存:热点数据缓存、页面缓存
  • 会话管理:Session、Token 存储
  • 计数器:点赞数、浏览量、库存
  • 排行榜:游戏排行、热搜排行
  • 消息队列:任务队列、延时队列
  • 分布式锁:防止重复提交
  • 限流:接口限流、防刷

2. 安装和配置

2.1 Docker 安装(推荐)

# 拉取镜像
docker pull redis:latest

# 运行 Redis
docker run -d \
  --name redis \
  -p 6379:6379 \
  -v redis-data:/data \
  redis:latest \
  redis-server --appendonly yes

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

2.2 Linux 安装

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

# CentOS/RHEL
sudo yum install redis

# 启动服务
sudo systemctl start redis
sudo systemctl enable redis

# 连接
redis-cli

2.3 配置文件

# redis.conf 主要配置项

# 绑定地址(生产环境不要绑定 0.0.0.0)
bind 127.0.0.1

# 端口
port 6379

# 密码
requirepass your-password

# 最大内存
maxmemory 1gb

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

# 持久化
save 900 1      # 900 秒内至少 1 次修改则保存
save 300 10     # 300 秒内至少 10 次修改则保存
save 60 10000   # 60 秒内至少 10000 次修改则保存

appendonly yes  # 启用 AOF

3. 五种基本数据类型

3.1 String(字符串)

基本操作
# SET/GET
SET name "Redis"
GET name

# 设置并带过期时间
SETEX session:123 3600 "user_data"

# 不存在时设置
SETNX lock:order:1 "1"

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

# 追加
APPEND name " Cache"
GET name  # "Redis Cache"

# 获取旧值并设置新值
GETSET name "New Redis"
数值操作
# 递增/递减
SET counter 10
INCR counter        # 11
INCRBY counter 5    # 16
DECR counter        # 15
DECRBY counter 3    # 12

# 浮点数操作
SET score 10.5
INCRBYFLOAT score 2.5  # 13.0
位操作
# SETBIT/GETBIT(用于签到统计等)
SETBIT user:sign:2024:10 1 1   # 10月1日签到
SETBIT user:sign:2024:10 2 1   # 10月2日签到
GETBIT user:sign:2024:10 1     # 查询10月1日是否签到

# BITCOUNT(统计签到天数)
BITCOUNT user:sign:2024:10
应用场景
  • 缓存:热点数据、配置信息
  • 计数器:点赞数、浏览量、库存
  • 分布式锁:SETNX 实现
  • 限流:INCR + EXPIRE
  • Session:用户会话信息

3.2 Hash(哈希)

基本操作
# HSET/HGET
HSET user:1 name "Alice"
HSET user:1 age 25
HGET user:1 name

# HMSET/HMGET(批量操作)
HMSET user:2 name "Bob" age 30 email "bob@example.com"
HMGET user:2 name age

# HGETALL(获取所有字段)
HGETALL user:1

# HDEL(删除字段)
HDEL user:1 email

# HEXISTS(字段是否存在)
HEXISTS user:1 name  # 1

# HLEN(字段数量)
HLEN user:1

# HKEYS/HVALS(获取所有键/值)
HKEYS user:1
HVALS user:1
数值操作
# HINCRBY(递增字段)
HSET user:1 score 100
HINCRBY user:1 score 50   # 150
HINCRBYFLOAT user:1 score 10.5  # 160.5
应用场景
  • 用户信息:用户属性(name、age、email)
  • 商品信息:商品详情(price、stock、description)
  • 购物车:商品 ID 为 field,数量为 value
  • 统计数据:各种维度的计数
# 购物车示例
HSET cart:user:1 product:101 2   # 商品 101 数量 2
HSET cart:user:1 product:102 1   # 商品 102 数量 1
HGETALL cart:user:1

3.3 List(列表)

基本操作
# LPUSH/RPUSH(左/右插入)
LPUSH tasks "task1"
RPUSH tasks "task2" "task3"

# LPOP/RPOP(左/右弹出)
LPOP tasks
RPOP tasks

# LRANGE(范围查询)
LRANGE tasks 0 -1    # 获取所有
LRANGE tasks 0 9     # 获取前 10 个

# LLEN(长度)
LLEN tasks

# LINDEX(获取指定位置)
LINDEX tasks 0

# LSET(设置指定位置)
LSET tasks 0 "new_task"

# LTRIM(修剪列表,保留指定范围)
LTRIM tasks 0 99   # 保留前 100 个

# LINSERT(在指定元素前/后插入)
LINSERT tasks BEFORE "task2" "task1.5"
阻塞操作
# BLPOP/BRPOP(阻塞弹出,用于消息队列)
BLPOP queue 5    # 阻塞 5 秒等待
BRPOP queue 0    # 永久阻塞
应用场景
  • 消息队列:LPUSH + BRPOP 实现生产者-消费者
  • 时间线:微博、朋友圈时间线
  • :LPUSH + LPOP
  • 队列:LPUSH + RPOP
  • 最新列表:最新文章、最新评论
# 消息队列示例
# 生产者
LPUSH queue:email "email1"
LPUSH queue:email "email2"

# 消费者
BRPOP queue:email 0  # 阻塞等待消息

3.4 Set(集合)

基本操作
# SADD(添加成员)
SADD tags "redis" "cache" "nosql"

# SMEMBERS(获取所有成员)
SMEMBERS tags

# SISMEMBER(成员是否存在)
SISMEMBER tags "redis"  # 1

# SREM(删除成员)
SREM tags "nosql"

# SCARD(集合大小)
SCARD tags

# SPOP(随机弹出)
SPOP tags

# SRANDMEMBER(随机获取,不删除)
SRANDMEMBER tags
SRANDMEMBER tags 2  # 随机获取 2 个
集合运算
# 创建两个集合
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"

# SUNION(并集)
SUNION set1 set2  # a, b, c, d, e, f

# SINTER(交集)
SINTER set1 set2  # c, d

# SDIFF(差集)
SDIFF set1 set2   # a, b

# 存储运算结果
SUNIONSTORE result set1 set2
SINTERSTORE result set1 set2
SDIFFSTORE result set1 set2
应用场景
  • 标签系统:文章标签、用户兴趣
  • 共同好友:集合交集
  • 推荐系统:基于标签推荐
  • 去重:自动去重特性
  • 抽奖系统:SPOP 随机抽取
# 共同好友示例
SADD user:1:friends "user2" "user3" "user4"
SADD user:2:friends "user1" "user3" "user5"
SINTER user:1:friends user:2:friends  # user3(共同好友)

3.5 Sorted Set(有序集合)

基本操作
# ZADD(添加成员)
ZADD leaderboard 100 "player1"
ZADD leaderboard 90 "player2" 85 "player3"

# ZRANGE(按分数排序,升序)
ZRANGE leaderboard 0 -1           # 所有成员
ZRANGE leaderboard 0 -1 WITHSCORES  # 带分数

# ZREVRANGE(降序)
ZREVRANGE leaderboard 0 9         # 前 10 名
ZREVRANGE leaderboard 0 9 WITHSCORES

# ZRANGEBYSCORE(按分数范围)
ZRANGEBYSCORE leaderboard 80 100
ZRANGEBYSCORE leaderboard 80 100 WITHSCORES LIMIT 0 10

# ZINCRBY(增加分数)
ZINCRBY leaderboard 10 "player1"

# ZRANK/ZREVRANK(排名,从 0 开始)
ZRANK leaderboard "player1"      # 升序排名
ZREVRANK leaderboard "player1"   # 降序排名

# ZSCORE(获取分数)
ZSCORE leaderboard "player1"

# ZREM(删除成员)
ZREM leaderboard "player3"

# ZCARD(成员数量)
ZCARD leaderboard

# ZCOUNT(分数范围内的成员数量)
ZCOUNT leaderboard 80 100

# ZREMRANGEBYRANK(删除排名范围内的成员)
ZREMRANGEBYRANK leaderboard 0 2  # 删除前 3 名

# ZREMRANGEBYSCORE(删除分数范围内的成员)
ZREMRANGEBYSCORE leaderboard 0 50
应用场景
  • 排行榜:游戏排行、成绩排名
  • 热搜榜:按热度排序
  • 延时队列:按时间戳排序
  • 权重排序:按权重值排序
  • 时间线:按时间排序的事件
# 排行榜示例
ZADD game:score 1000 "player1"
ZADD game:score 950 "player2"
ZADD game:score 900 "player3"

# 获取前 10 名
ZREVRANGE game:score 0 9 WITHSCORES

# 获取我的排名(从 0 开始,所以要 +1)
ZREVRANK game:score "player1"

# 延时队列示例
ZADD delay:queue 1698048000 "task1"  # 时间戳作为分数
ZADD delay:queue 1698049000 "task2"

# 获取到期的任务
ZRANGEBYSCORE delay:queue 0 1698048000

4. 通用命令

4.1 键操作

# EXISTS(键是否存在)
EXISTS key

# DEL(删除键)
DEL key

# TYPE(键的类型)
TYPE key

# RENAME(重命名)
RENAME oldkey newkey

# KEYS(查找键,生产环境慎用)
KEYS pattern
KEYS user:*

# SCAN(游标迭代,推荐)
SCAN 0 MATCH user:* COUNT 10

4.2 过期时间

# EXPIRE(设置过期时间,秒)
EXPIRE key 3600

# EXPIREAT(设置过期时间戳)
EXPIREAT key 1698048000

# PEXPIRE(毫秒)
PEXPIRE key 60000

# TTL(查看剩余时间,秒)
TTL key

# PTTL(毫秒)
PTTL key

# PERSIST(移除过期时间)
PERSIST key

4.3 数据库切换

# SELECT(切换数据库,0-15)
SELECT 1

# DBSIZE(当前数据库键数量)
DBSIZE

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

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

5. 持久化

5.1 RDB(快照)

原理
  • 定期将内存数据快照保存到磁盘
  • 生成 dump.rdb 文件
  • 适合备份和灾难恢复
配置
# redis.conf
save 900 1       # 900 秒内至少 1 次修改
save 300 10      # 300 秒内至少 10 次修改
save 60 10000    # 60 秒内至少 10000 次修改

dbfilename dump.rdb
dir /var/lib/redis
手动触发
SAVE      # 同步保存(阻塞)
BGSAVE    # 异步保存(fork 子进程)
优缺点

优点

  • 文件小,恢复快
  • 适合备份

缺点

  • 可能丢失最后一次快照之后的数据
  • fork 子进程耗时

5.2 AOF(追加文件)

原理
  • 记录每个写命令
  • 追加到 appendonly.aof 文件
  • 重启时重新执行命令恢复数据
配置
# redis.conf
appendonly yes
appendfilename "appendonly.aof"

# 同步策略
appendfsync always    # 每个命令都同步(慢但安全)
appendfsync everysec  # 每秒同步(推荐)
appendfsync no        # 由操作系统决定(快但可能丢数据)
AOF 重写
# 手动触发
BGREWRITEAOF

# 自动触发配置
auto-aof-rewrite-percentage 100  # AOF 文件增长 100% 时重写
auto-aof-rewrite-min-size 64mb   # AOF 文件至少 64MB 时重写
优缺点

优点

  • 数据更安全(最多丢 1 秒数据)
  • 文件可读,易于修复

缺点

  • 文件大
  • 恢复慢

5.3 混合持久化(Redis 4.0+)

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

# 原理:AOF 重写时,先写入 RDB 格式,再追加增量命令
# 优势:恢复快 + 数据安全

6. 事务

6.1 基本使用

# MULTI(开始事务)
MULTI

# 命令入队
SET key1 "value1"
SET key2 "value2"
INCR counter

# EXEC(执行事务)
EXEC

# DISCARD(取消事务)
DISCARD

6.2 WATCH(乐观锁)

# 监视键
WATCH key

# 获取值
GET key

# 开始事务
MULTI
SET key "new_value"
EXEC  # 如果 key 被其他客户端修改,返回 nil

6.3 Redis 事务特点

  • 原子性:要么全执行,要么全不执行
  • 隔离性:串行执行,不会被其他命令打断
  • 无回滚:命令错误不会回滚已执行的命令

7. Pipeline(管道)

7.1 原理

将多个命令打包一次性发送,减少网络往返。

7.2 使用示例

# Python 示例
import redis

r = redis.Redis()

# 普通方式(3 次网络往返)
r.set('key1', 'value1')
r.set('key2', 'value2')
r.set('key3', 'value3')

# Pipeline 方式(1 次网络往返)
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.set('key3', 'value3')
results = pipe.execute()

7.3 注意事项

  • Pipeline 不保证原子性
  • 一次性发送的命令不宜过多(占用内存)

8. 过期策略和内存淘汰

8.1 过期删除策略

惰性删除
  • 访问键时检查是否过期
  • 节省 CPU,但占用内存
定期删除
  • 每秒 10 次随机检查过期键
  • 平衡 CPU 和内存
主动删除
  • 内存不足时触发内存淘汰策略

8.2 内存淘汰策略

# redis.conf
maxmemory 1gb
maxmemory-policy allkeys-lru

# 淘汰策略
noeviction        # 不淘汰,返回错误(默认)
allkeys-lru       # 从所有键中淘汰最近最少使用(推荐)
allkeys-lfu       # 从所有键中淘汰最不经常使用
allkeys-random    # 从所有键中随机淘汰
volatile-lru      # 从设置过期时间的键中淘汰 LRU
volatile-lfu      # 从设置过期时间的键中淘汰 LFU
volatile-random   # 从设置过期时间的键中随机淘汰
volatile-ttl      # 淘汰即将过期的键

9. 常用命令总结

9.1 String 命令

SETGET、SETEX、SETNX、MSET、MGET
INCR、INCRBY、DECR、DECRBY
APPEND、GETSET

9.2 Hash 命令

HSET、HGET、HMSET、HMGET、HGETALL
HDEL、HEXISTS、HLEN
HKEYS、HVALS
HINCRBY

9.3 List 命令

LPUSH、RPUSH、LPOP、RPOP
LRANGE、LLEN、LINDEX、LSET
LTRIM、BLPOP、BRPOP

9.4 Set 命令

SADD、SMEMBERS、SISMEMBER、SREM
SCARD、SPOP、SRANDMEMBER
SUNION、SINTER、SDIFF

9.5 Sorted Set 命令

ZADD、ZRANGE、ZREVRANGE、ZRANGEBYSCORE
ZINCRBY、ZRANK、ZREVRANK、ZSCORE
ZREM、ZCARD、ZCOUNT

10. 高频问题

Q1: Redis 为什么快?

答案

  1. 纯内存操作
  2. 单线程模型(避免锁竞争)
  3. IO 多路复用(epoll)
  4. 高效的数据结构

Q2: Redis 的数据类型有哪些?

答案

  • String:字符串
  • Hash:哈希表
  • List:列表
  • Set:集合
  • Sorted Set:有序集合

Q3: RDB 和 AOF 的区别?

答案

  • RDB:快照,文件小,恢复快,可能丢数据
  • AOF:追加日志,数据安全,文件大,恢复慢

Q4: Redis 过期键删除策略?

答案

  • 惰性删除:访问时检查
  • 定期删除:每秒 10 次随机检查

Q5: Redis 内存淘汰策略?

答案: 常用的是 allkeys-lru:从所有键中淘汰最近最少使用的键


总结

Redis 基础核心:

  1. ✅ 五种数据类型及应用场景
  2. ✅ 持久化机制(RDB、AOF)
  3. ✅ 过期策略和内存淘汰
  4. ✅ 事务和 Pipeline
  5. ✅ 常用命令

下一步:学习 Redis 进阶特性和实战应用!