一、Redis 核心原理

1.1 什么是 Redis

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

  • 数据库(Database)
  • 缓存(Cache)
  • 消息队列(Message Broker)

1.2 核心架构设计

┌─────────────────────────────────────────┐
│           Redis Server                  │
├─────────────────────────────────────────┤
│  网络层 → 命令解析 → 命令执行 → 返回结果    │
├─────────────────────────────────────────┤
│  数据存储层:                            │
│  • 内存存储(主存储)                     │
│  • 持久化(RDB/AOF)                     │
├─────────────────────────────────────────┤
│  数据结构层:                            │
│  String / Hash / List / Set / ZSet      │
│  Bitmap / HyperLogLog / Geo / Stream    │
└─────────────────────────────────────────┘

1.3 单线程模型(核心特性)

Redis 使用单线程事件循环处理所有命令,但这并不意味着它慢:

特性

说明

单线程优势

无锁竞争、无上下文切换、原子性操作

IO多路复用

基于 epoll/kqueue/select 处理并发连接

性能瓶颈

内存带宽和网络延迟,而非 CPU

💡 为什么快? 所有操作都在内存中完成,单线程避免了锁开销,配合高效的 C 语言实现。

1.4 持久化机制

方式

原理

优点

缺点

适用场景

RDB

定时快照

文件紧凑、恢复快

可能丢数据

备份、灾难恢复

AOF

记录写命令

数据安全、可读

文件大、恢复慢

数据可靠性要求高

混合

RDB+AOF

兼顾两者

配置复杂

生产环境推荐


二、数据类型详解

2.1 基础类型速查表

类型

存储结构

适用场景

时间复杂度

String

字符串/整数/浮点

缓存、计数器、Session

O(1)

Hash

键值对集合

对象存储、用户信息

O(1)

List

双向链表

消息队列、时间线

O(1)头尾/O(n)中间

Set

无序唯一集合

标签、共同好友、去重

O(1)

ZSet

有序集合(Skip List)

排行榜、延迟队列

O(log N)

2.2 String(字符串)

最基础类型,最大 512MB

# 基础操作
SET user:1001 "Alice"          # 设置键值
GET user:1001                  # 获取值
SET counter 100                # 设置计数器
INCR counter                   # 原子+1(101)
INCRBY counter 10              # 原子+10(111)
DECR counter                   # 原子-1

# 批量操作(减少网络往返)
MSET user:1001 "Alice" user:1002 "Bob"
MGET user:1001 user:1002

# 设置过期(NX=不存在才设置,XX=存在才设置)
SET temp_key "value" EX 60 NX  # 60秒后过期,仅当不存在

实战场景

# 1. 分布式锁(简单版)
SET lock:order:123 "owner_id" EX 30 NX

# 2. 限流计数(每分钟最多100次)
INCR rate_limit:user:1001
EXPIRE rate_limit:user:1001 60

# 3. 存储对象(JSON序列化)
SET user:profile:1001 '{"name":"Alice","age":25}'

2.3 Hash(哈希)

存储对象的最佳选择,比 String 更省内存:

# 用户对象存储
HSET user:1001 name "Alice" age 25 city "Beijing"
HGET user:1001 name           # 获取单个字段
HGETALL user:1001             # 获取所有字段
HMGET user:1001 name age      # 获取多个字段

# 原子操作
HINCRBY user:1001 age 1       # 年龄+1
HDEL user:1001 city           # 删除字段
HLEN user:1001                # 字段数量
HKEYS user:1001               # 所有字段名
HVALS user:1001               # 所有字段值

String vs Hash 存储对比

方式

存储结构

内存占用

灵活性

SET user:1001 '{...}'

一个 String

高(JSON冗余)

低(需全量更新)

HSET user:1001 ...

一个 Hash

低(ziplist优化)

高(单字段更新)

2.4 List(列表)

双向链表,支持两端操作:

# 队列操作(FIFO)
LPUSH queue:tasks "task1"     # 左侧插入
RPUSH queue:tasks "task2"     # 右侧插入
RPOP queue:tasks              # 右侧弹出(消费)
BLPOP queue:tasks 30          # 阻塞弹出(30秒超时)

# 栈操作(LIFO)
LPUSH stack:ops "op1"
LPOP stack:ops

# 范围查询(适合时间线)
LRANGE timeline:user:1001 0 9  # 获取前10条
LTRIM timeline:user:1001 0 99  # 只保留100条

经典应用:消息队列

# 生产者
LPUSH mq:orders '{"order_id":"123","amount":100}'

# 消费者(阻塞式,优雅处理空队列)
BRPOP mq:orders 0              # 0表示永久阻塞

2.5 Set(集合)

无序唯一集合,支持集合运算:

# 基础操作
SADD tags:article:1001 "redis" "database" "cache"
SMEMBERS tags:article:1001     # 获取所有成员
SISMEMBER tags:article:1001 "redis"  # 判断是否包含
SREM tags:article:1001 "cache" # 移除成员
SCARD tags:article:1001        # 成员数量

# 集合运算(社交场景)
SADD followers:user:1001 2001 2002 2003
SADD followers:user:1002 2001 2002 2004

SINTER followers:user:1001 followers:user:1002   # 交集:共同关注
SUNION followers:user:1001 followers:user:1002   # 并集:所有关注
SDIFF followers:user:1001 followers:user:1002    # 差集:1001独有的

实战:抽奖系统

# 初始化奖池
SADD lottery:pool:user:1001 "prize1" "prize2" "prize3" "prize4"

# 随机抽取3个不重复奖品(不删除)
SRANDMEMBER lottery:pool:user:1001 3

# 随机抽取并移除(确保不重复中奖)
SPOP lottery:pool:user:1001 1

2.6 ZSet(有序集合)

Skip List + Hash Table 实现,支持按分数排序:

# 排行榜
ZADD leaderboard:game1 1000 "player:A" 950 "player:B" 1200 "player:C"
ZREVRANGE leaderboard:game1 0 2 WITHSCORES  # 前三名(降序)
ZRANGE leaderboard:game1 0 2 WITHSCORES     # 后三名(升序)

# 范围查询
ZRANGEBYSCORE leaderboard:game1 1000 2000   # 分数在1000-2000之间
ZREMRANGEBYRANK leaderboard:game1 0 0       # 删除第一名
ZREMRANGEBYSCORE leaderboard:game1 0 500    # 删除500分以下的

# 排名相关
ZRANK leaderboard:game1 "player:A"          # 获取排名(升序,从0开始)
ZREVRANK leaderboard:game1 "player:A"       # 获取排名(降序)
ZSCORE leaderboard:game1 "player:A"         # 获取分数
ZINCRBY leaderboard:game1 50 "player:A"     # 增加分数

实战:延迟队列

# 任务执行时间作为score(时间戳)
ZADD delay_queue 1672531200 "task:send_email:123"
ZADD delay_queue 1672534800 "task:push_notify:456"

# 轮询待执行任务(当前时间戳)
ZRANGEBYSCORE delay_queue 0 1672533000 LIMIT 0 1
# 执行后删除
ZREM delay_queue "task:send_email:123"

2.7 高级类型

类型

用途

关键命令

Bitmap

位图统计(签到、在线状态)

SETBIT, BITCOUNT, BITOP

HyperLogLog

基数统计(UV计算)

PFADD, PFCOUNT, PFMERGE

Geo

地理位置(附近的人)

GEOADD, GEORADIUS, GEODIST

Stream

日志型消息队列

XADD, XREAD, XGROUP


三、性能优化与最佳实践

3.1 性能指标

Redis 基准测试(redis-benchmark):
• 单机 QPS:100,000+(简单命令)
• 延迟:亚毫秒级(P99 < 1ms)
• 内存操作:100万键值对 ≈ 100MB

3.2 关键优化策略

1. 避免 Big Key
# 检测 Big Key
redis-cli --bigkeys
redis-cli --mem-keys "user:*"

# 优化方案:
# String > 10KB → 拆分为 Hash 或分片
# Hash/Set/ZSet > 5000 成员 → 拆分为多个 Key
# List > 10000 元素 → 分片或使用 Stream
2. 批量操作与 Pipeline
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.1.0</version>
</dependency>
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.JedisPool;

public class RedisBatchExample {

    // 错误:N次网络往返
    public void wrongWay(Jedis jedis, String value) {
        for (int i = 0; i < 1000; i++) {
            jedis.set("key:" + i, value);  // 每次循环都发起一次网络请求
        }
    }

    // 正确:Pipeline 合并请求(1次往返)
    public void correctPipeline(Jedis jedis, String value) {
        Pipeline pipe = jedis.pipelined();
        for (int i = 0; i < 1000; i++) {
            pipe.set("key:" + i, value);  // 命令先缓冲在本地
        }
        pipe.sync();  // 一次性发送所有命令,减少网络往返
    }

    // Lua 脚本(原子性批量操作)
    public void luaScript(Jedis jedis) {
        String luaScript = 
        "local sum = 0 " +
        "for i=1,#KEYS do " +
        "    sum = sum + redis.call('GET', KEYS[i]) " +
        "end " +
        "return sum";

        // 执行 Lua 脚本,传入 3 个 key
        Object result = jedis.eval(luaScript, 3, "key1", "key2", "key3");
        System.out.println("Sum: " + result);
    }

    // 使用连接池的完整示例
    public static void main(String[] args) {
        try (JedisPool pool = new JedisPool("localhost", 6379);
             Jedis jedis = pool.getResource()) {

            RedisBatchExample example = new RedisBatchExample();

            // 测试 Pipeline
            long start = System.currentTimeMillis();
            example.correctPipeline(jedis, "value");
            System.out.println("Pipeline 耗时: " + (System.currentTimeMillis() - start) + "ms");

            // 测试 Lua 脚本
            jedis.set("key1", "10");
            jedis.set("key2", "20");
            jedis.set("key3", "30");
            example.luaScript(jedis);  // 输出: Sum: 60
        }
    }
}
3. 内存优化技巧

策略

说明

配置

哈希压缩

ziplist 编码小 Hash

hash-max-ziplist-entries 512

整数集合

intset 编码小 Set

set-max-intset-entries 512

内存淘汰

控制最大内存

maxmemory 4gb + maxmemory-policy allkeys-lru

# 内存淘汰策略(maxmemory-policy)
volatile-lru    # 从过期Key中淘汰最近最少使用(默认)
allkeys-lru     # 从所有Key中淘汰LRU(推荐)
volatile-ttl    # 淘汰即将过期的Key
allkeys-random  # 随机淘汰
noeviction      # 不淘汰,直接报错(写保护)

3.3 高可用架构

单机 → 主从复制 → 哨兵模式 → 集群模式

┌─────────────┐      ┌─────────────┐      ┌─────────────┐
│   Master    │◄────►│   Slave 1   │      │   Slave 2   │
│  (读写)      │      │  (只读/备份) │      │  (只读/备份) │
└─────────────┘      └─────────────┘      └─────────────┘
       ▲
       │  哨兵监控(Sentinel)
       ▼
┌─────────────────────────────────────────────────────┐
│  Sentinel ×3:故障自动转移、服务发现                    │
└─────────────────────────────────────────────────────┘

集群模式(Redis Cluster):
┌─────────┐     ┌─────────┐     ┌─────────┐
│ Master A│◄───►│ Master B│◄───►│ Master C│
│(0-5460) │     │(5461-10922)   │(10923-16383)
└────┬────┘     └────┬────┘     └────┬────┘
     │               │               │
└────┴────┘     └────┴────┘     └────┴────┘
Slave A1,A2     Slave B1,B2     Slave C1,C2

四、监控与运维

5.1 关键监控指标

# INFO 命令查看状态
redis-cli INFO

# 关键指标
connected_clients: 50          # 当前连接数
used_memory: 1048576           # 已用内存(字节)
used_memory_rss: 2097152       # 系统分配内存
mem_fragmentation_ratio: 2.0   # 内存碎片率(>1.5需关注)
instantaneous_ops_per_sec: 1000 # 实时QPS
keyspace_hits: 9000            # 命中次数
keyspace_misses: 1000          # 未命中次数
hit_rate: 90%                  # 命中率(需>95%)

# 慢查询监控
SLOWLOG GET 10                 # 获取前10条慢查询
slowlog-log-slower-than 10000  # 配置:超过10ms记录

5.2 配置文件核心项

# redis.conf 关键配置
bind 0.0.0.0                    # 监听地址
port 6379                       # 端口
requirepass your_password       # 密码
maxmemory 4gb                   # 最大内存
maxmemory-policy allkeys-lru    # 淘汰策略

# 持久化
save 900 1                      # 900秒内有1次修改则RDB
save 300 10                     # 300秒内有10次修改则RDB
appendonly yes                  # 开启AOF
appendfsync everysec            # 每秒刷盘(折中方案)

# 安全
rename-command FLUSHALL ""      # 禁用危险命令
rename-command CONFIG "CONFIG_abc123"  # 重命名命令

六、总结速查

场景

推荐方案

关键命令

Session 存储

String + TTL

SETEX, GET

商品详情页

String/Hash + 缓存策略

MGET, HMGET

购物车

Hash

HSET, HGETALL

消息队列

List/Stream

LPUSH/BRPOP, XADD/XREAD

排行榜

ZSet

ZADD, ZREVRANGE

社交网络

Set

SADD, SINTER, SUNION

附近的人

Geo

GEOADD, GEORADIUS

统计UV

HyperLogLog

PFADD, PFCOUNT

分布式锁

String + Lua

SET NX EX

限流

ZSet/令牌桶

ZREMRANGEBYSCORE


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐