跳转到内容

Redis 内存数据结构存储

20 道题
分类
中间件
题目数
20 道
已阅读 0 / 20 题
1 Redis Cluster 的分片机制与 16384 个 Slot 分配原理是什么?

答案:

Redis Cluster 采用 Hash Slot 机制实现数据分片,将键空间划分为 16384 个 Slot

Slot 分配原理

  • 每个键通过 CRC16(key) % 16384 计算所属 Slot
  • Slot 分布在多个主节点之间,每个主节点负责一段 Slot 范围
  • 每个 Slot 可包含多个键,主节点负责其 Slot 范围内的所有读写操作
# 查看集群 Slot 分布
redis-cli cluster slots

# 手动分配 Slot
redis-cli --cluster add-node new-node:6379 existing-node:6379
redis-cli --cluster reshard <target-node>:6379

为什么是 16384?

维度16384(16K)65536(64K)
心跳消息大小约 2KB(bitmap)约 8KB
网络带宽占用低(Gossip 协议 PING/PONG)
节点数上限建议 ≤ 1000理论上更多
Redis 设计权衡足够用且消息体紧凑带宽浪费

16384 是在心跳消息大小与节点扩展性之间的折中:16K 个 Slot 的 bitmap 仅需 2KB,在 Gossip 消息中传输效率高,且足以支撑 1000 个节点的集群规模。

2 Redis Cluster 的 Gossip 协议如何工作?

答案:

Redis Cluster 各节点通过 Gossip 协议Cluster Bus(端口 16379,即 data_port + 10000)上交换集群元信息。

Gossip 通信机制

  1. 每个节点每秒随机选取 cluster-node-timeout / 2 个节点发送 PING 消息
  2. 收到 PING 的节点回复 PONG
  3. PING / PONG 消息携带:
    • 发送者自身信息(node ID、IP、port、flags)
    • 发送者已知的其他节点信息(Gossip 段)
    • 当前纪元(currentEpoch)和配置纪元(configEpoch)
  4. 节点通过 Gossip 消息发现新节点,标记疑似故障节点(PFAIL -> FAIL)

关键参数

参数默认值说明
cluster-node-timeout15000ms节点超时阈值,影响 PFAIL 判定
cluster-slave-validity-factor10从节点故障转移有效性因子
cluster-migration-barrier1从节点迁移屏障

K8s 场景注意事项

  • Cluster Bus 端口需在 Service 和 NetworkPolicy 中额外暴露
  • Headless Service 需确保 Pod DNS 解析后 Cluster Bus 通信可达
  • cluster-announce-ipcluster-announce-port 需正确配置
3 Redis Cluster 节点扩缩容与 Slot 迁移如何执行?

答案:

扩容流程(添加新主节点):

# 1. 新节点加入集群
redis-cli --cluster add-node <new-node-ip>:6379 <existing-node-ip>:6379

# 2. 重新分配 Slot(在线迁移)
redis-cli --cluster reshard <target-node-ip>:6379 \
  --cluster-from <source-node-id> \
  --cluster-to <target-node-id> \
  --cluster-slots <slot-count>

Slot 迁移内部流程

  1. 目标节点执行 CLUSTER SETSLOT <slot> IMPORTING <source-node-id>
  2. 源节点执行 CLUSTER SETSLOT <slot> MIGRATING <target-node-id>
  3. 源节点执行 MIGRATE 命令逐键迁移数据
  4. 迁移完成后通知集群所有节点更新 Slot 归属
  5. 源节点删除已迁移的键
# 添加从节点
redis-cli --cluster add-node <new-node-ip>:6379 <existing-node-ip>:6379 \
  --cluster-slave --cluster-master-id <master-node-id>

# 删除节点
redis-cli --cluster del-node <node-ip>:6379 <node-id>

缩容流程

  1. 将待下线节点的 Slot 迁移至其他节点(--cluster reshard
  2. 确认 Slot 全部迁出后执行 --cluster del-node

K8s 上扩容:先 kubectl scale statefulset redis-cluster --replicas=N,再执行 redis-cli --cluster reshard 手动均衡 Slot。自动化方案依赖 Operator。

4 Redis 监控指标体系如何构建?

答案:

监控体系以 redis_exporter 为核心,通过 Prometheus 采集指标,Grafana 展示。

架构

Redis Pod(sidecar: redis_exporter)
  └── Prometheus(ServiceMonitor / PodMonitor)
        └── Grafana Dashboard
              └── AlertManager(告警规则)

核心指标分类

类别关键指标阈值建议
连接redis_connected_clientsredis_rejected_connections连接数 > 80% maxclients
内存redis_memory_used_bytesredis_memory_max_bytesused > 80% maxmemory
命中率redis_keyspace_hits_total / (hits + misses)命中率 < 90%
命令延迟redis_commands_duration_secondsP99 > 10ms
持久化redis_rdb_last_save_time_seconds最后保存 > 配置间隔
复制redis_master_repl_offset - redis_slave_repl_offset复制延迟 > 10MB
集群redis_cluster_slots_ok / redis_cluster_slots_total不可用 Slot > 0
键过期redis_expired_keys_totalredis_evicted_keys_total驱逐率持续增长

Prometheus 告警规则示例

groups:
- name: redis
  rules:
  - alert: RedisMemoryHigh
    expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.85
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Redis 内存使用率超过 85%"

  - alert: RedisDown
    expr: redis_up == 0
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "Redis 实例 {{ $labels.instance }} 不可达"

  - alert: RedisReplicationLag
    expr: (redis_master_repl_offset - redis_slave_repl_offset) > 10485760
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Redis 主从复制延迟超过 10MB"
5 Redis 慢查询日志与性能诊断如何进行?

答案:

慢查询日志记录执行时间超过阈值的命令。

# 配置慢查询
CONFIG SET slowlog-log-slower-than 10000   # 超过 10ms 记录
CONFIG SET slowlog-max-len 128             # 最多保留 128 条

# 查看慢查询
SLOWLOG GET 10    # 最近 10 条
SLOWLOG LEN       # 总数
SLOWLOG RESET     # 清空

性能诊断方法

方法用途示例
SLOWLOG GET定位慢命令识别 KEYS *、O(N) 命令
INFO commandstats命令调用统计分析命令分布与耗时
redis-cli --latency网络延迟采样判断网络瓶颈
redis-cli --latency-history延迟时间序列检测延迟波动
redis-cli --bigkeys大 Key 扫描发现内存热点
redis-cli --memkeys内存消耗排序定位内存占用
MEMORY STATS内存使用详情分析碎片率
redis-benchmark性能压测基线测试

K8s 场景性能诊断清单

  1. 检查 CPU Throttling(container_cpu_cfs_throttled_seconds_total
  2. 检查内存是否触及 Limit 导致 OOM Kill
  3. 检查磁盘 IOPS 是否满足 AOF appendfsync 需求
  4. 检查网络延迟(redis-cli --latency 从应用 Pod 测试)
  5. 检查 NUMA 亲和性与 CPU 绑定(taskset
6 Redis 内存管理策略有哪些?

答案:

maxmemory 与逐出策略

maxmemory 4gb
maxmemory-policy allkeys-lru
逐出策略行为适用场景
noeviction不逐出,写操作返回错误数据不允许丢失
volatile-lru从设置了 TTL 的键中 LRU 逐出缓存 + 持久键混合
allkeys-lru所有键中 LRU 逐出纯缓存场景
volatile-lfu设置了 TTL 的键中 LFU 逐出热点数据保护
allkeys-lfu所有键中 LFU 逐出访问频率敏感
volatile-random随机逐出设置了 TTL 的键缓存淘汰均匀
allkeys-random随机逐出所有键所有键同等重要
volatile-ttl优先逐出 TTL 短的键按过期时间淘汰

内存碎片整理

# 查看碎片率
INFO memory   # mem_fragmentation_ratio

# 自动碎片整理(Redis 4.0+)
CONFIG SET activedefrag yes
CONFIG SET active-defrag-ignore-bytes 100mb
CONFIG SET active-defrag-threshold-lower 10   # 碎片率 > 1.1

mem_fragmentation_ratio = used_memory_rss / used_memory,大于 1.5 表示碎片严重。

K8s 内存管理注意

  • resources.limits.memory 需大于 maxmemory,预留 fork RDB 和系统开销
  • 建议比例:limits.memory >= maxmemory * 1.3 + 500MB
  • 开启 oom-score-adj 避免 OOM Killer 误杀
7 Redis Pipeline 与 Batch 操作有什么不同?

答案:

维度PipelineBatch(MGET/MSET)事务(MULTI/EXEC)
实现方式客户端缓存多条命令一次性发送单条命令操作多个 Key将多条命令打包原子执行
原子性不保证单个命令本身原子保证(EXEC 前不被打断)
网络往返1 次 RTT(N 条命令)1 次 RTT(1 条命令)1 次 RTT(N 条命令)
执行顺序按发送顺序执行N/A按添加顺序执行
错误处理某命令失败不影响其他整体成功或失败某命令语法错误时全部不执行

Pipeline 使用示例(Go)

pipe := rdb.Pipeline()
incr := pipe.Incr(ctx, "pipeline_counter")
pipe.Expire(ctx, "pipeline_counter", time.Hour)
cmds, err := pipe.Exec(ctx)

注意事项

  • Pipeline 内命令数量不宜过大,建议单次 ≤ 100 条
  • Pipeline 不保证原子性,中间可能插入其他客户端的命令
  • Redis Cluster 下 Pipeline 要求所有 Key 在同一个 Slot(可用 {} hash tag 控制)
8 Redis Pub/Sub 与 Stream 有什么区别?

答案:

维度Pub/SubStream
消息持久化不持久,消费者不在线即丢失持久化至内存/RDB/AOF
消费者组不支持支持(XGROUP),可负载均衡
消息回溯不支持支持(按 ID 范围读取)
消息确认支持(XACK
适用场景实时通知、聊天事件溯源、消息队列、日志收集
内存管理不堆积需设置 MAXLEN 限制长度

Stream 基本操作

# 写入
XADD mystream * field1 value1 field2 value2

# 读取(阻塞)
XREAD BLOCK 0 STREAMS mystream 0

# 消费者组
XGROUP CREATE mystream mygroup $ MKSTREAM
XREADGROUP GROUP mygroup consumer1 BLOCK 0 STREAMS mystream >

# 确认
XACK mystream mygroup <message-id>

# 限制长度
XADD mystream MAXLEN ~ 10000 * field value

K8s Stream 注意事项

  • Stream 数据存储在内存中,需注意 maxmemory 限制
  • 消费者组信息存储在 Redis 内存中,故障转移后需重建或持久化消费偏移
9 Redis 分布式锁方案有哪些?

答案:

方案原理安全性适用场景
SET NX + EXSET key value NX EX <ttl>单实例安全单机 Redis,低可靠性要求
Redisson(RedLock)多数节点加锁成功视为获得锁高(防脑裂)多节点 Redis,金融级场景
SET + Lua 释放Lua 脚本原子校验 value 后删除防误删单实例需防锁被他人释放

SET NX 正确实现

# 加锁
SET lock:order:123 unique-client-id NX EX 30

# 释放(Lua 脚本保证原子性)
EVAL "
  if redis.call('GET', KEYS[1]) == ARGV[1] then
    return redis.call('DEL', KEYS[1])
  else
    return 0
  end
" 1 lock:order:123 unique-client-id

Redisson RedLock 原理

  1. 客户端向 N 个独立 Redis 实例依次请求加锁
  2. 设置锁超时远小于 TTL(如 TTL=30s,超时=5ms)
  3. 当 ≥ N/2+1 个实例加锁成功,且总耗时 < TTL,锁获取成功
  4. 实际有效时间 = TTL - 获取耗时
  5. 释放时向所有实例发送释放命令

K8s 场景注意:RedLock 要求 Redis 实例彼此独立(不同节点、不同可用区),K8s 上需配合 podAntiAffinity 部署。

10 缓存穿透、击穿、雪崩如何防护?

答案:

问题定义防护方案
缓存穿透查询不存在的数据,请求直达数据库布隆过滤器、空值缓存(短 TTL)、参数校验
缓存击穿热点 Key 过期瞬间高并发直达数据库互斥锁(SET NX)、逻辑过期 + 异步刷新、永不过期
缓存雪崩大量 Key 同时过期或 Redis 宕机TTL 随机化、多级缓存、限流降级、Redis 高可用

布隆过滤器(RedisBloom 模块)

# 添加元素
BF.ADD cache-filter "key:12345"
BF.EXISTS cache-filter "key:12345"

# 大规模导入
BF.RESERVE large-filter 0.01 1000000   # 错误率 1%,100 万容量
BF.MADD large-filter key1 key2 key3

热点 Key 互斥锁方案(伪代码)

func GetData(key string) (string, error) {
    val, err := rdb.Get(ctx, key).Result()
    if err == redis.Nil {
        // 缓存未命中,使用互斥锁
        lockKey := "lock:" + key
        locked, _ := rdb.SetNX(ctx, lockKey, "1", 10*time.Second).Result()
        if locked {
            defer rdb.Del(ctx, lockKey)
            val = queryDB(key)
            rdb.Set(ctx, key, val, 30*time.Minute)
        } else {
            time.Sleep(100 * time.Millisecond)
            return GetData(key) // 重试
        }
    }
    return val, err
}

TTL 随机化EXPIRE key <base_ttl + random(0, base_ttl * 0.3)>,避免集中过期。

11 大 Key 与热 Key 如何检测和处理?

答案:

检测手段

工具用途命令
redis-cli --bigkeys扫描最大 Keyredis-cli -h <host> --bigkeys
redis-cli --hotkeys扫描热 Key(需 maxmemory-policy 为 LFU)redis-cli -h <host> --hotkeys
MEMORY USAGE <key>精确计算 Key 内存占用MEMORY USAGE user:10001
OBJECT FREQ <key>LFU 访问频率OBJECT FREQ user:10001
redis-rdb-tools离线分析 RDB 文件rdb -c memory dump.rdb
SCAN + DEBUG OBJECT渐进式扫描SCAN 0 MATCH * COUNT 1000

大 Key 定义

数据类型阈值
String> 10MB
List / Set / ZSet / Hash元素数量 > 10000
Stream消息数 > 100000 或总大小 > 50MB

处理策略

  1. 拆分:Hash 大 Key 按业务维度拆分为多个小 Hash
  2. 压缩:String 大 Key 先压缩再存储(snappy/gzip)
  3. 删除:分批渐进式删除,避免阻塞
   # Hash 分批删除字段
   HSCAN key 0 COUNT 100 → HDEL key field1 field2 ...
  1. 迁移:使用 MIGRATE 将单个大 Key 迁移至独立实例
  2. 架构调整:热 Key 前置本地缓存(如 Caffeine、BigCache)
12 Redis 客户端连接池如何配置?

答案:

连接池关键参数(以 go-redis 为例)

参数说明建议值
PoolSize最大连接数CPU 核数 × 4 ~ 10
MinIdleConns最小空闲连接PoolSize × 0.2
MaxIdleConns最大空闲连接PoolSize
PoolTimeout等待连接超时5s ~ 10s
IdleTimeout空闲连接回收时间5min
IdleCheckFrequency空闲检查频率1min
ConnMaxLifetime连接最大生命周期30min ~ 1h

go-redis 配置示例

rdb := redis.NewClient(&redis.Options{
    Addr:         "redis-headless:6379",
    Password:     os.Getenv("REDIS_PASSWORD"),
    DB:           0,
    PoolSize:     50,
    MinIdleConns: 10,
    MaxIdleConns: 50,
    PoolTimeout:  5 * time.Second,
    IdleTimeout:  5 * time.Minute,
    DialTimeout:  5 * time.Second,
    ReadTimeout:  3 * time.Second,
    WriteTimeout: 3 * time.Second,
})

Redis 服务端连接参数

maxclients 10000
timeout 300          # 空闲连接超时秒数
tcp-keepalive 60     # TCP keepalive 间隔
tcp-backlog 511      # TCP 完成队列大小

K8s 场景注意

  • 连接池大小需配合 Pod 副本数计算总连接数,不超过 maxclients
  • Service Mesh(如 Istio)的 sidecar 可能增加连接,需留余量
  • IdleTimeout 应小于 Service/负载均衡的空闲超时,避免半开连接
13 Redis SSL/TLS 加密与 ACL 权限如何控制?

答案:

TLS 配置

# redis.conf
tls-port 6380
port 0                          # 禁用非 TLS 端口
tls-cert-file /etc/tls/tls.crt
tls-key-file /etc/tls/tls.key
tls-ca-cert-file /etc/tls/ca.crt
tls-auth-clients yes            # 要求客户端证书
tls-protocols "TLSv1.2 TLSv1.3"
tls-ciphers DEFAULT:!MEDIUM

K8s cert-manager 集成

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: redis-tls
spec:
  secretName: redis-tls-secret
  duration: 2160h
  renewBefore: 360h
  dnsNames:
  - "redis-0.redis-headless.redis.svc.cluster.local"
  - "*.redis-headless.redis.svc.cluster.local"
  issuerRef:
    name: ca-issuer
    kind: ClusterIssuer

ACL 权限控制(Redis 6.0+)

# 创建用户
ACL SETUSER reader on >password ~* +@read -@write -@dangerous
ACL SETUSER writer on >password ~* +@all -@dangerous
ACL SETUSER appuser on >password ~prefix:* +@all

# 查看用户
ACL LIST
ACL GETUSER reader

# 配置文件持久化
aclfile /etc/redis/users.acl

ACL 权限规则

规则含义
on / off启用/禁用用户
>password设置密码
~pattern可访问的键模式(~* 表示所有键)
+@category授权命令类别(+@read 只读)
-command禁用特定命令(-FLUSHALL
+command授权特定命令
14 Redis Read-Only Replica 读写分离如何实现?

答案:

配置从节点可读

# 从节点配置
replica-read-only yes        # 从节点只读(默认)
# 或
replica-read-only no         # 允许写入(数据会被主节点覆盖)

客户端读写分离策略

策略原理一致性
应用层路由客户端维护主从连接,写操作用主连接,读操作用从连接最终一致(存在复制延迟)
Proxy 层Proxy 解析命令类型自动路由(如 Twemproxy、Codis)最终一致
一致性读写后紧接的读强制走主节点强一致

go-redis 读写分离示例

// 主节点(写入)
master := redis.NewClient(&redis.Options{
    Addr: "redis-master:6379",
})
// 从节点(读取)
slaves := redis.NewRing(&redis.RingOptions{
    Addrs: map[string]string{
        "slave0": "redis-slave-0.redis-headless:6379",
        "slave1": "redis-slave-1.redis-headless:6379",
    },
})

// 业务代码
master.Set(ctx, "key", "value", 0)
slaves.Get(ctx, "key")

一致性边界:Redis 主从复制是异步的,读从可能读到旧数据。需要强一致性的读操作必须走主节点。可通过 WAIT 命令将异步复制变为半同步:

SET key value
WAIT 1 1000    # 等待至少 1 个从节点确认,超时 1000ms
15 Redis 在线迁移方案有哪些?

答案:

方案原理停机时间适用场景
Redis-Shake解析 RDB + AOF,全量 + 增量同步秒级(切换瞬间)跨集群迁移、云上云下迁移
主从复制切换新实例 REPLICAOF 旧主,同步后切换秒级同版本升级、迁移
RDB 导入BGSAVE → 拷贝 RDB → 新实例加载分钟级停机维护窗口
MIGRATE单 Key 原子迁移无(逐 Key)集群 Slot 迁移
SCAN + DUMP/RESTORE分批序列化传输无(逐批)选择性数据迁移

Redis-Shake 迁移流程

# Redis-Shake K8s Job
apiVersion: batch/v1
kind: Job
metadata:
  name: redis-shake-migration
spec:
  template:
    spec:
      containers:
      - name: redis-shake
        image: apsaradb/redis-shake:latest
        command:
        - redis-shake.linux
        args:
        - -type=sync            # sync / restore / scan
        - -conf=/etc/shake.toml
        volumeMounts:
        - name: config
          mountPath: /etc
      volumes:
      - name: config
        configMap:
          name: redis-shake-config
      restartPolicy: Never

shak.toml 配置

[sync_reader]
address = "source-redis:6379"
password = "source-pwd"

[redis_writer]
address = "target-redis:6379"
password = "target-pwd"

迁移步骤

  1. 部署 Redis-Shake 同步任务
  2. 等待全量 + 增量追平(延迟 < 1ms)
  3. 停止源端写入
  4. 确认数据一致后切换客户端连接至目标
  5. 停止 Redis-Shake,清理源实例
16 Redis 拓扑感知调度如何通过 Pod Anti-Affinity 实现?

答案:

Pod Anti-Affinity 确保 Redis 实例分散在不同节点 / 可用区,避免单点故障。

三层调度策略

策略级别topologyKey效果
节点级反亲和kubernetes.io/hostname同节点不部署多个 Redis Pod
可用区级反亲和topology.kubernetes.io/zone同可用区最多一个副本
软反亲和preferredDuringScheduling优先分散,资源不足时可堆叠

完整配置

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app
          operator: In
          values: ["redis"]
      topologyKey: kubernetes.io/hostname
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: node-role.kubernetes.io/redis
          operator: Exists

TopologySpreadConstraints(替代 Anti-Affinity)

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone
  whenUnsatisfiable: DoNotSchedule
  labelSelector:
    matchLabels:
      app: redis
- maxSkew: 1
  topologyKey: kubernetes.io/hostname
  whenUnsatisfiable: ScheduleAnyway
  labelSelector:
    matchLabels:
      app: redis

Node Selector / Taint-Toleration:Redis Pod 专属节点池,通过 taint 隔离其他工作负载:

tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "redis"
  effect: "NoSchedule"
nodeSelector:
  node-group: redis
17 Redis Lua 脚本与事务有什么区别?

答案:

维度Lua 脚本MULTI/EXEC 事务WATCH 乐观锁
原子性完全原子,执行期间不可中断命令打包,但不回滚不保证原子性
条件逻辑支持(if/else/循环)不支持(命令固定)支持 CAS
网络往返1 次1 次多次
错误处理脚本执行失败不回滚已执行部分语法错误全部不执行,运行时错误不回滚竞争失败需重试

Lua 脚本示例

-- 分布式限流:令牌桶
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local tokens = tonumber(redis.call('HGET', key, 'tokens')) or capacity
local last_time = tonumber(redis.call('HGET', key, 'last_time')) or now

local delta = math.max(0, now - last_time)
local new_tokens = math.min(capacity, tokens + delta * rate)

if new_tokens >= 1 then
    redis.call('HSET', key, 'tokens', new_tokens - 1)
    redis.call('HSET', key, 'last_time', now)
    return 1
else
    redis.call('HSET', key, 'tokens', new_tokens)
    redis.call('HSET', key, 'last_time', now)
    return 0
end
EVAL "<script>" 1 "rate_limit:user:123" 10 0.5 <current_timestamp>

WATCH 乐观锁

WATCH balance:user:100
val = GET balance:user:100
MULTI
SET balance:user:100 <val - amount>
EXEC   # 如果 key 被修改,EXEC 返回 nil
18 RedisJSON、RedisSearch、RedisTimeSeries 模块有何用途?

答案:

模块用途核心命令K8s 部署方式
RedisJSONJSON 文档存储与查询JSON.SETJSON.GETJSON.ARRAPPENDredislabs/rejson 镜像
RedisSearch全文搜索、向量搜索FT.CREATEFT.SEARCHFT.AGGREGATEredislabs/redisearch 镜像
RedisTimeSeries时序数据存储与聚合TS.CREATETS.ADDTS.RANGEredislabs/redistimeseries 镜像
RedisBloom布隆过滤器、计数、布谷鸟BF.ADDCF.ADDCMS.INCRBYredislabs/rebloom 镜像
RedisGraph图数据库GRAPH.QUERYredislabs/redisgraph 镜像

模块加载方式

# redis.conf
loadmodule /usr/lib/redis/modules/redisearch.so
loadmodule /usr/lib/redis/modules/rejson.so
loadmodule /usr/lib/redis/modules/redistimeseries.so

Redis Stack 镜像(一站式)

containers:
- name: redis
  image: redis/redis-stack-server:7.2.0-v10
  # 已内置 RedisJSON、RedisSearch、RedisTimeSeries、RedisBloom、RedisGraph

RedisSearch 全文搜索

FT.CREATE idx:articles ON JSON PREFIX 1 article: SCHEMA \
  $.title AS title TEXT SORTABLE \
  $.content AS content TEXT \
  $.tags.* AS tags TAG

FT.SEARCH idx:articles "@title:kubernetes @tags:{redis}" RETURN 2 title tags

RedisTimeSeries 时序聚合

TS.CREATE ts:sensor:temp RETENTION 86400000 LABELS sensor_id 1
TS.ADD ts:sensor:temp * 23.5
TS.RANGE ts:sensor:temp <start> <end> AGGREGATION avg 60000   # 1 分钟均值
19 PodDisruptionBudget 如何保障 Redis 在节点维护时的高可用?

答案:

PodDisruptionBudget(PDB) 限制同时不可用的 Pod 数量,防止节点维护或集群自动缩放时批量驱逐 Redis Pod。

PDB 配置

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: redis-pdb
spec:
  maxUnavailable: 1        # Sentinel:最多 1 个 Pod 不可用
  selector:
    matchLabels:
      app: redis

# Cluster 模式:每个 StatefulSet 至少保留 N-1 个可用
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: redis-cluster-pdb
spec:
  minAvailable: 5          # 6 节点集群至少保持 5 个可用
  selector:
    matchLabels:
      app: redis-cluster

PDB 与故障转移联动

  1. kubectl drain <node> 触发 Pod 驱逐
  2. PDB 限制同时驱逐数量
  3. 驱逐的 Pod 如果是主节点,Sentinel 触发故障转移
  4. 从节点提升为新主后,流量切换到新主
  5. 被驱逐的 Pod 在新节点重新调度

多重保障策略

保障手段作用
PDB限制驱逐数量,防止集群大规模不可用
Pod Anti-Affinity分散在不同节点,降低同时被驱逐风险
Pod PriorityRedis Pod 优先级高于普通 Pod,避免被优先驱逐
terminationGracePeriodSeconds足够时间(≥ 60s)完成 BGSAVE 持久化
20 Redis vs KeyDB vs Dragonfly 对比

答案:

维度Redis 7.2KeyDBDragonfly
架构单线程事件循环(I/O 多线程)多线程(真正的并行处理)多线程(无共享架构)
线程模型1 个主线程 + I/O 线程(6.0+)N 个工作线程并行执行命令分片 + 事务引擎
性能~100K QPS(单核)~500K QPS(多核)~1M+ QPS(多核)
兼容性Redis 原生协议Redis 协议完全兼容Redis 协议兼容(部分命令不支持)
内存效率基准与 Redis 相当比 Redis 节省 30%+ 内存(DashTable)
持久化RDB + AOFRDB + AOF自定义快照格式
集群Redis Cluster(原生)Active Replication(多主)1.0+ 支持集群
Lua 脚本完全支持完全支持有限支持(无 EVAL
模块RedisJSON/Search/TS/Bloom/Graph部分支持不支持原生模块
K8s 部署成熟(多个 Operator)社区支持官方 Helm Chart
许可证RSALv2 / SSPLv1BSD 3-ClauseBSL(Business Source License)
适用场景通用缓存/队列/会话多核高吞吐缓存大内存成本敏感场景

选型建议

  • Redis:生态最成熟,模块丰富,企业级支持,K8s Operator 完善
  • KeyDB:需要多线程并行处理的纯缓存场景,Redis 协议无缝迁移
  • Dragonfly:内存成本敏感,不需要 Redis 模块,追求极致吞吐

参考资料:Redis 官方文档(redis.io/documentation)、Redis Cluster Spec