AWS ElastiCache Redis

概述

Amazon ElastiCache 是托管式内存数据库服务,完全兼容 Redis 和 Memcached。本节聚焦 ElastiCache Redis 的集群配置、副本机制、安全设置和性能优化,适用于缓存、会话存储、实时排行榜、消息队列等场景。

核心应用场景:

  • 缓存层 — 加速数据库查询,降低 RDS 负载
  • 会话存储 — Web 应用分布式会话(Spring Session、PHP Session)
  • 实时数据 — 排行榜、计数器、实时分析
  • 消息队列 — Pub/Sub、Stream 异步通信
  • 分布式锁 — Redlock 实现的分布式互斥

架构与部署

部署模式对比

模式 说明 适用场景
单节点 无副本,故障即丢失 开发测试、缓存只读数据
集群模式(Cluster Mode) 分片集群,16384 slots 分布到多个节点组 大容量、高吞吐生产环境
副本(Cluster Mode Disabled) 1 主节点 + 1-5 只读副本 读多写少,需要高可用
副本(Cluster Mode Enabled) 每个分片 1 主 + 1-5 副本 写多读多,需要分片扩展

创建 Redis 集群(ElastiCache)


# 创建 Redis 集群(集群模式,3 分片,每分片 1 副本)
aws elasticache createReplication-group   --replication-group-id prod-redis-cluster   --replication-group-description "Production Redis Cluster"   --engine redis   --engine-version 7.1   --cache-node-type cache.r6g.large   --num-node-groups 3   --replicas-per-node-group 1   --cache-parameter-group-name default.redis7.cluster.on   --auto-failover-enabled   --multi-az-enabled   --network-type ipv4   --at-rest-encryption-enabled   --transit-encryption-enabled   --auth-token-enabled   --auth-token "YourSecureAuthToken123!"   --cache-subnet-group-name private-redis-subnet   --security-group-ids sg-0abcd1234efgh5678   --preferred-maintenance-window mon:04:00-mon:05:00   --notification-topic-arn arn:aws:sns:us-east-1:123456789012:redis-alerts   --output json

创建 Memcached 集群


# 创建 Memcached 集群(节点式,不支持副本)
aws elasticache create-cache-cluster   --cache-cluster-id prod-memcached   --cache-node-type cache.t4g.medium   --engine memcached   --engine-version 1.6.22   --num-cache-nodes 3   --cache-parameter-group-name default.memcached1.6   --cache-subnet-group-name private-memcached-subnet   --security-group-ids sg-0abcd1234efgh5678   --az-mode cross-az   --output json

连接与客户端

获取连接端点


# 查看集群端点
aws elasticache describe-replication-groups   --replication-group-id prod-redis-cluster   --output json

# 输出示例:
# Primary EndPoint: prod-redis-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com:6379
# Reader EndPoint: prod-redis-cluster-ro.xxxxx.ng.0001.use1.cache.amazonaws.com:6379

Redis 连接示例


import redis
from redis.cluster import RedisCluster

# 单节点/副本模式连接
r = redis.Redis(
    host='prod-redis-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com',
    port=6379,
    password='YourSecureAuthToken123!',
    ssl=True,
    ssl_cert_reqs='required',
    decode_responses=True,
    socket_connect_timeout=5,
    socket_timeout=5,
    retry_on_timeout=True,
    health_check_interval=30
)

# 集群模式连接
rc = RedisCluster(
    host='prod-redis-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com',
    port=6379,
    password='YourSecureAuthToken123!',
    ssl=True,
    decode_responses=True,
    skip_full_coverage_check=True
)

# 测试连接
r.ping()
rc.info()

连接池配置


import redis
from redis.connection import ConnectionPool

# 全局连接池(建议单例)
pool = redis.ConnectionPool(
    host='prod-redis-cluster.xxxxx.ng.0001.use1.cache.amazonaws.com',
    port=6379,
    password='YourSecureAuthToken123!',
    ssl=True,
    max_connections=50,
    decode_responses=True
)

def get_redis():
    return redis.Redis(connection_pool=pool)

# 使用
client = get_redis()
client.set('key', 'value', ex=3600)

数据结构操作

String(字符串)


r = get_redis()

# 基础操作
r.set('user:1000:session', 'sess_data_xxx', ex=1800)  # 30分钟过期
r.get('user:1000:session')
r.setnx('lock:job:123', 'worker-1')  # 分布式锁(需设过期时间)
r.incr('counter:pageviews:20240115')
r.incrbyfloat('metrics:latency:avg', 0.5)

Hash(哈希)


# 用户信息缓存
r.hset('user:1000', mapping={
    'name': '张三',
    'email': 'zhang@example.com',
    'tier': 'premium',
    'created_at': '2023-01-15'
})
r.hgetall('user:1000')
r.hget('user:1000', 'email')
r.hincrby('user:1000', 'login_count', 1)

List(列表)


# 消息队列 / 任务队列
r.lpush('queue:tasks', '{"job":"email","id":100}')
r.rpop('queue:tasks')
r.brpop('queue:tasks', timeout=5)  # 阻塞读取

# 实时列表
r.lpush('feed:user:1000', json.dumps({'msg':'hello','ts':now}))
r.ltrim('feed:user:1000', 0, 99)  # 保留最新100条

Set / Sorted Set


# 标签/去重
r.sadd('article:1000:tags', 'redis', 'cache', 'aws')
r.smembers('article:1000:tags')
r.sismember('article:1000:tags', 'redis')

# 排行榜
r.zadd('leaderboard:2024', {'player1': 9500, 'player2': 8800, 'player3': 8200})
r.zrevrange('leaderboard:2024', 0, 9, withscores=True)  # Top 10
r.zrevrank('leaderboard:2024', 'player2')  # 查询排名

Stream(流)


# 事件流(Kafka-lite)
r.xadd('events:orders', {'order_id': '12345', 'amount': '199.00'}, maxlen=10000, approximate=True)
r.xread({'events:orders': '0'})
r.xread({'events:orders': '$'}, count=10, block=5000)  # 阻塞等待新消息

# 消费者组
r.xgroup_create('events:orders', 'processors', id='0', mkstream=True)
r.xreadgroup('processors', 'worker-1', {'events:orders': '>'}, count=10, block=5000)
r.xack('events:orders', 'processors', '1705312345677-0')

高可用与故障切换

自动故障切换机制

ElastiCache Redis 自动检测主节点故障并在 95 秒内完成切换(Cluster Mode Disabled)。切换期间:

  • 写入请求短暂中断(约 30-60 秒)
  • 读取请求由副本承接(如果启用了 PreferReplicaMode
  • 切换后 DNS 自动更新,客户端无需修改连接配置

手动故障注入测试


# 模拟主节点故障(生产环境慎用!)
aws elasticache test-failover   --replication-group-id prod-redis-cluster   --node-group-id 0001

Global Datastore(跨区域复制)


# 创建全局复制组(跨区域灾备)
aws elasticache create-global-replication-group   --global-replication-group-id prod-redis-global   --primary-replication-group-id prod-redis-cluster-use1   --secondary-replication-group-id prod-redis-cluster-usw2   --at-rest-encryption-enabled

安全配置

IAM 身份验证(Redis 7.0+)


# 启用 IAM 认证
aws elasticache modify-replication-group   --replication-group-id prod-redis-cluster   --auth-token-enabled   --auth-token-secure-transport-enabled   --apply-immediately

VPC 安全组规则

方向 协议 端口 来源
入站 TCP 6379 应用服务器安全组
入站 TCP 6379 堡垒机(运维)
出站 TCP 443 S3(如果使用 ElastiCache Valkey)

静态加密


# 创建带 KMS 加密的集群
aws elasticache create-replication-group   # ... 其他参数 ...
  --at-rest-encryption-enabled   --kms-key-id arn:aws:kms:us-east-1:123456789012:key/xxxxx

监控指标

CloudWatch 关键指标

指标 说明 告警阈值建议
CPUUtilization CPU 使用率 > 70% 警告
EngineCPUUtilization Redis 进程 CPU > 70% 警告
DatabaseMemoryUsagePercentage 内存使用率 > 75% 警告,> 90% 严重
CurrConnections 当前连接数 突增 > 2x 基准警告
ReplicationLag 复制延迟 > 1 秒警告
CacheHitRate 缓存命中率 < 80% 警告
EvalBasedCmds Lua 脚本执行次数 频繁需优化
ClusterCoordinator 集群协调状态 非 1 需关注

# 设置 CPU 告警
aws cloudwatch put-metric-alarm   --alarm-name prod-redis-cpu-high   --alarm-description "ElastiCache Redis CPU 使用率超过 70%"   --metric-name EngineCPUUtilization   --namespace AWS/ElastiCache   --statistic Maximum   --period 300   --evaluation-periods 2   --threshold 70   --comparison-operator GreaterThanThreshold   --dimensions "Name=ReplicationGroupId,Value=prod-redis-cluster"   --alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts

内存碎片处理


# 通过 ElastiCache 控制台或 CLI 查看
aws elasticache describe-replication-groups   --replication-group-id prod-redis-cluster   --output json | jq '.ReplicationGroups[0].MemberClusters'

# 内存碎片率高时重启节点(最后一个手段)
aws elasticache reboot-cache-cluster   --cache-cluster-id prod-redis-cluster-0001-001   --cache-node-ids-to-reboot "0001"

性能优化

键值设计原则


# 命名规范:用途:实体ID:属性
user:1000:profile      # Hash,用户档案
session:abc123         # String,会话数据
queue:tasks            # List,任务队列
rate:ip:192.168.1.100  # String,限流计数器
lock:order:12345       # String,分布式锁

大 Key 处理


# 避免大 String(单个 value 建议 < 10KB)
# 超过时使用 Hash 分片存储
for i in range(10000):
    r.hset('bighash', f'field:{i}', f'value:{i}')

# 扫描大 Key(生产环境先在从节点执行)
r.scan_iter(match='*', count=100)

管道与批量操作


# 使用 Pipeline 减少 RTT
pipe = r.pipeline()
for i in range(1000):
    pipe.set(f'key:{i}', f'value:{i}')
    pipe.expire(f'key:{i}', 3600)
pipe.execute()  # 1 次网络往返完成 1000 次操作

备份与恢复


# 创建手动快照
aws elasticache create-snapshot   --replication-group-id prod-redis-cluster   --snapshot-name prod-redis-backup-20240115

# 自动快照(每日)
aws elasticache modify-replication-group   --replication-group-id prod-redis-cluster   --automatic-backup-retention-period 7

# 从快照恢复
aws elasticache restore-from-snapshot   --replication-group-id prod-redis-restored   --snapshot-name prod-redis-backup-20240115   --cache-node-type cache.r6g.large

常见问题

Q: 连接数突增导致 OOM?

A: 1) 检查客户端是否正确关闭连接(连接池泄漏);2) 设置 timeout 参数限制空闲连接;3) 确认没有大量 DEBUG SEGFAULT 等高消耗命令;4) 升级节点规格。

Q: 缓存雪崩?

A: 1) 对过期时间加随机偏移( TTL = base + rand(0, 300));2) 使用 SETEX 时不设置统一过期时间;3) 高可用架构 + 熔断降级。

Q: 数据持久化影响性能?

A: ElastiCache RDB 快照在后台执行,AOF 追加写对性能影响极小(< 5%)。如对延迟极敏感,可关闭持久化(纯缓存场景),但需接受故障数据丢失风险。