Redis架构及部署优化

Redis架构

1.单线程模型

客户端请求 → TCP连接 → 命令入队 → 单线程执行 → 结果返回
                  ↑
            epoll 非阻塞IO

单线程快的原因:

  • 纯内存操作,无磁盘IO
  • 非阻塞IO(epoll)
  • 避免线程切换和竞态消耗

需要拒绝的慢命令: KEYS *FLUSHALLFLUSHDB、慢Lua脚本、大集合操作

Redis 6.0 起引入网络IO多线程,但命令执行仍是单线程。


2.五大数据结构

类型 数据结构 核心命令 典型场景
String 简单字符串 SET/GET/INCR/MSET/APPEND Session、计数器、缓存
List 双向链表 LPUSH/RPUSH/LPOP/RPOP/LRANGE 消息队列、最新消息
Set 无序集合 SADD/SINTER/SUNION/SDIFF 标签、共同好友、抽奖
Sorted Set 跳表+哈希 ZADD/ZRANGE/ZRANK/ZSCORE 排行榜、优先级队列
Hash 哈希表 HSET/HGET/HGETALL/HDEL 用户对象、部分更新

3.持久化架构

┌─────────────────────────────────────────────────────┐
│                    写入请求                          |
└────────────────────┬────────────────────────────────┘
                     │
          ┌──────────┴──────────┐
          ▼                     ▼
    ┌──────────┐          ┌──────────┐
    │   RDB    │          │   AOF    │
    │  快照备份 │          |  追加日志 |
    └────┬─────┘          └────┬─────┘
         │                     │
         ▼                     ▼
    fork子进程写临时文件     每秒fsync到磁盘
    替换原dump.rdb          重写(rewrite)压缩
特性 RDB AOF
安全性 可能丢几分钟数据 最多丢1秒
恢复速度
文件大小
性能影响 fork时短暂阻塞 everysec策略较友好
适用场景 备份、灾难恢复 高可靠性要求

RDB触发规则:

save 900 1    # 900秒内至少1个key变更
save 300 10   # 300秒内至少10个key变更
save 60 10000 # 60秒内至少10000个key变更

AOF同步策略:

策略 安全性 性能 说明
always 最高 最差 每次写都fsync
everysec 中等 每秒fsync一次(推荐)
no 最低 最好 由OS决定fsync时机

混合持久化(Redis 4.0+): aof-use-rdb-preamble yes,AOF重写时包含RDB前缀,兼顾速度与安全。


4.高可用架构演进

单机 → 主从复制 → 哨兵(Sentinel) → Redis Cluster
  │         │            │              │
  │         │            │        16384个槽位分片
  │         │            │        无中心架构
  │         │            │        自动故障转移
  └─────────┴────────────┴────────────────

主从复制:

  • 单向数据流:Master → Slave
  • 一个Master可有多个Slave,一个Slave只能有一个Master
  • Slave默认只读(replica-read-only yes
  • 全量同步:BGSAVE → RDB文件传输 → Slave加载
  • 增量同步:repl-backlog-buffer缓冲区补发

哨兵(Sentinel):

Sentinel节点1  ─┐
Sentinel节点2  ─┼─  选举Leader → 判定ODOWN → QUNOWN → 故障转移
Sentinel节点3  ─┘
       ↓
  将最优Slave提升为新Master
  其他Slave指向新Master

三个定时任务:定期检测、向Master汇报、协商选举

Redis Cluster:

  • 16384个哈希槽,Key通过 CRC16(key) % 16384 路由
  • 无中心架构,节点间 PING/PONG 互通
  • 过半数节点判定失效才算真正下线
  • 每个Master平均承担 16384/N 个槽位
  • 槽位全不覆盖时,cluster-require-full-coverage no 可继续服务(但部分数据查不到)

Redis部署方案

1.安装方式对比

方式 CentOS 7 CentOS 8 特点
yum安装 epel源 系统源 版本旧,操作简单
编译安装 推荐 推荐 版本新,可定制
Windows 非官方 非官方 不推荐生产使用

编译安装关键步骤:

1
2
3
4
5
6
yum -y install gcc jemalloc-devel
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
tar xf redis-5.0.7.tar.gz
cd redis-5.0.7 && make -j 4 PREFIX=/apps/redis install
mkdir /apps/redis/{etc,log,data,run}
cp redis.conf /apps/redis/etc/

2.启动三个警告修复

1
2
3
4
5
6
7
8
9
10
11
# 1. tcp-backlog:全连接队列长度
echo 'net.core.somaxconn = 1024' >> /etc/sysctl.conf

# 2. overcommit_memory:避免bgsave时OOM
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf

# 3. THP透明大页:造成延迟和内存问题
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local

sysctl -p

3.systemd 服务配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target

生产环境优化配置

1.核心配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 网络
bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300

# 内存
maxmemory 4294967296 # 设为物理内存的50%,如8G内存设为4G
maxmemory-policy allkeys-lru # 内存满时的淘汰策略

# 持久化
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error no # 生产建议no
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data/redis

# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # 生产推荐
no-appendfsync-on-rewrite yes # 避免阻塞
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes # 混合持久化
aof-load-truncated yes

# 主从复制
replica-read-only yes
replica-serve-stale-data yes
repl-diskless-sync no # 有足够磁盘I/O时用硬盘同步
repl-backlog-size 512mb # 增大回滚缓冲区

# 安全
requirepass your_strong_password
rename-command FLUSHALL "" # 禁用危险命令

# 慢查询日志
slowlog-log-slower-than 10000 # 10ms,生产建议1-10ms
slowlog-max-len 1024 # 生产建议1000以上

# 集群
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-require-full-coverage no # 生产建议no

2.内存淘汰策略选择

策略 说明
noeviction 不淘汰,内存满时返回错误(默认)
allkeys-lru 所有key中淘汰最久未使用的(推荐)
volatile-lru 有过期时间的key中淘汰最久未使用的
allkeys-random 随机淘汰
volatile-ttl 淘汰即将过期的key

3.多实例部署

同一台服务器可运行多个Redis实例(不同端口),每个实例独立配置文件:

1
2
3
4
5
# 复制配置并修改端口
cp redis.conf redis_6380.conf
sed -i 's/6379/6380/g' redis_6380.conf
# 分别创建systemd服务
systemctl enable --now redis6379 redis6380 redis6381

4.集群部署(Redis 5.x)

1
2
3
4
5
# 所有节点开启cluster功能后,一键创建
redis-cli --cluster create \
10.0.0.8:6379 10.0.0.18:6379 10.0.0.28:6379 \
10.0.0.38:6379 10.0.0.48:6379 10.0.0.58:6379 \
--cluster-replicas 1

槽位分配: 3主3从,每个Master约5461个槽位

5.客户端连接方式

1
2
3
4
5
6
7
8
9
10
11
12
13
# 单机
import redis
r = redis.Redis(host='10.0.0.8', port=6379, password='xxx')

# 哨兵
from redis.sentinel import Sentinel
sentinel = Sentinel([('host1', 26379), ('host2', 26379)])
master = sentinel.master_for('mymaster', password='xxx')

# 集群
from rediscluster import RedisCluster
nodes = [{"host":"10.0.0.8","port":6379}, ...]
rc = RedisCluster(startup_nodes=nodes, password='xxx')

6.关键注意事项

项目 建议
maxmemory 设为物理内存50%,留空间给OS和子进程
keys命令 严禁生产使用,用SCAN替代
大Value 不建议超过2MB,性能受影响
密码设置 必须设置,禁用危险命令
AOF开启 首次开启AOF前需有RDB备份,否则数据丢失
主从切换 切换后master_replid变化,所有Slave全量同步