redis-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Redis Best Practices

Redis开发最佳实践

Core Principles

核心原则

  • Use Redis for caching, session storage, real-time analytics, and message queuing
  • Choose appropriate data structures for your use case
  • Implement proper key naming conventions and expiration policies
  • Design for high availability and persistence requirements
  • Monitor memory usage and optimize for performance
  • 将Redis用于缓存、会话存储、实时分析和消息队列
  • 根据使用场景选择合适的数据结构
  • 实施规范的键命名约定和过期策略
  • 针对高可用性和持久化需求进行设计
  • 监控内存使用情况并优化性能

Key Naming Conventions

键命名规范

  • Use colons as namespace separators
  • Include object type and identifier in key names
  • Keep keys short but descriptive
  • Use consistent naming patterns across your application
undefined
  • 使用冒号作为命名空间分隔符
  • 在键名中包含对象类型和标识符
  • 保持键名简短但具有描述性
  • 在整个应用中使用一致的命名模式
undefined

Good key naming examples

良好的键命名示例

user:1234:profile user:1234:sessions order:5678:items cache:api:products:list queue:email:pending session:abc123def456 rate_limit:api:user:1234
undefined
user:1234:profile user:1234:sessions order:5678:items cache:api:products:list queue:email:pending session:abc123def456 rate_limit:api:user:1234
undefined

Data Structures

数据结构

Strings

字符串

  • Use for simple key-value storage, counters, and caching
  • Consider using MGET/MSET for batch operations
redis
undefined
  • 用于简单键值存储、计数器和缓存
  • 考虑使用MGET/MSET进行批量操作
redis
undefined

Simple caching

简单缓存

SET cache:user:1234 '{"name":"John","email":"john@example.com"}' EX 3600
SET cache:user:1234 '{"name":"John","email":"john@example.com"}' EX 3600

Counters

计数器

INCR stats:pageviews:homepage INCRBY stats:downloads:file123 5
INCR stats:pageviews:homepage INCRBY stats:downloads:file123 5

Atomic operations

原子操作

SETNX lock:resource:456 "owner:abc" EX 30
undefined
SETNX lock:resource:456 "owner:abc" EX 30
undefined

Hashes

哈希表

  • Use for objects with multiple fields
  • More memory-efficient than multiple string keys
  • Supports partial updates
redis
undefined
  • 用于包含多个字段的对象存储
  • 比多个字符串键更节省内存
  • 支持部分更新
redis
undefined

Store user profile

存储用户资料

HSET user:1234 name "John Doe" email "john@example.com" created_at "2024-01-15"
HSET user:1234 name "John Doe" email "john@example.com" created_at "2024-01-15"

Get specific fields

获取指定字段

HGET user:1234 email HMGET user:1234 name email
HGET user:1234 email HMGET user:1234 name email

Increment numeric fields

递增数值字段

HINCRBY user:1234 login_count 1
HINCRBY user:1234 login_count 1

Get all fields

获取所有字段

HGETALL user:1234
undefined
HGETALL user:1234
undefined

Lists

列表

  • Use for queues, recent items, and activity feeds
  • Consider blocking operations for queue consumers
redis
undefined
  • 用于队列、最近项和活动信息流
  • 队列消费者可考虑使用阻塞操作
redis
undefined

Message queue

消息队列

LPUSH queue:emails '{"to":"user@example.com","subject":"Welcome"}' RPOP queue:emails
LPUSH queue:emails '{"to":"user@example.com","subject":"Welcome"}' RPOP queue:emails

Blocking pop for workers

工作进程使用阻塞弹出

BRPOP queue:emails 30
BRPOP queue:emails 30

Recent activity (keep last 100)

最近活动(保留最后100条)

LPUSH user:1234:activity "viewed product 567" LTRIM user:1234:activity 0 99
LPUSH user:1234:activity "浏览了商品567" LTRIM user:1234:activity 0 99

Get recent items

获取最近项

LRANGE user:1234:activity 0 9
undefined
LRANGE user:1234:activity 0 9
undefined

Sets

集合

  • Use for unique collections, tags, and relationships
  • Supports set operations (union, intersection, difference)
redis
undefined
  • 用于唯一集合、标签和关系存储
  • 支持集合操作(并集、交集、差集)
redis
undefined

User tags/interests

用户标签/兴趣

SADD user:1234:interests "technology" "music" "travel"
SADD user:1234:interests "technology" "music" "travel"

Check membership

检查成员资格

SISMEMBER user:1234:interests "music"
SISMEMBER user:1234:interests "music"

Find common interests

查找共同兴趣

SINTER user:1234:interests user:5678:interests
SINTER user:1234:interests user:5678:interests

Online users tracking

在线用户追踪

SADD online:users "user:1234" SREM online:users "user:1234" SMEMBERS online:users
undefined
SADD online:users "user:1234" SREM online:users "user:1234" SMEMBERS online:users
undefined

Sorted Sets

有序集合

  • Use for leaderboards, priority queues, and time-series data
  • Elements sorted by score
redis
undefined
  • 用于排行榜、优先级队列和时间序列数据
  • 元素按分数排序
redis
undefined

Leaderboard

游戏排行榜

ZADD leaderboard:game1 1500 "player:123" 2000 "player:456" 1800 "player:789"
ZADD leaderboard:game1 1500 "player:123" 2000 "player:456" 1800 "player:789"

Get top 10

获取前10名

ZREVRANGE leaderboard:game1 0 9 WITHSCORES
ZREVRANGE leaderboard:game1 0 9 WITHSCORES

Get player rank

获取玩家排名

ZREVRANK leaderboard:game1 "player:123"
ZREVRANK leaderboard:game1 "player:123"

Time-based data (score = timestamp)

基于时间的数据(分数=时间戳)

ZADD events:user:1234 1705329600 "login" 1705330000 "purchase"
ZADD events:user:1234 1705329600 "登录" 1705330000 "购买"

Get events in time range

获取时间范围内的事件

ZRANGEBYSCORE events:user:1234 1705329600 1705333200
undefined
ZRANGEBYSCORE events:user:1234 1705329600 1705333200
undefined

Streams

  • Use for event streaming and log data
  • Supports consumer groups for distributed processing
redis
undefined
  • 用于事件流和日志数据
  • 支持消费者组进行分布式处理
redis
undefined

Add events to stream

向流中添加事件

XADD events:orders * customer_id 1234 product_id 567 amount 99.99
XADD events:orders * customer_id 1234 product_id 567 amount 99.99

Read from stream

从流中读取数据

XREAD COUNT 10 STREAMS events:orders 0
XREAD COUNT 10 STREAMS events:orders 0

Consumer groups

消费者组配置

XGROUP CREATE events:orders order-processors $ MKSTREAM XREADGROUP GROUP order-processors worker1 COUNT 10 STREAMS events:orders >
XGROUP CREATE events:orders order-processors $ MKSTREAM XREADGROUP GROUP order-processors worker1 COUNT 10 STREAMS events:orders >

Acknowledge processed messages

确认已处理的消息

XACK events:orders order-processors 1234567890-0
undefined
XACK events:orders order-processors 1234567890-0
undefined

Caching Patterns

缓存模式

Cache-Aside Pattern

旁路缓存模式

python
undefined
python
undefined

Pseudo-code for cache-aside

旁路缓存伪代码

def get_user(user_id): # Try cache first cached = redis.get(f"cache:user:{user_id}") if cached: return json.loads(cached)
# Cache miss - fetch from database
user = database.get_user(user_id)

# Store in cache with expiration
redis.setex(f"cache:user:{user_id}", 3600, json.dumps(user))

return user
undefined
def get_user(user_id): # 先尝试从缓存获取 cached = redis.get(f"cache:user:{user_id}") if cached: return json.loads(cached)
# 缓存未命中 - 从数据库获取
user = database.get_user(user_id)

# 存入缓存并设置过期时间
redis.setex(f"cache:user:{user_id}", 3600, json.dumps(user))

return user
undefined

Write-Through Pattern

写穿缓存模式

python
def update_user(user_id, data):
    # Update database
    database.update_user(user_id, data)

    # Update cache
    redis.setex(f"cache:user:{user_id}", 3600, json.dumps(data))
python
def update_user(user_id, data):
    # 更新数据库
    database.update_user(user_id, data)

    # 更新缓存
    redis.setex(f"cache:user:{user_id}", 3600, json.dumps(data))

Cache Invalidation

缓存失效

redis
undefined
redis
undefined

Delete specific cache

删除指定缓存

DEL cache:user:1234
DEL cache:user:1234

Delete by pattern (use with caution in production)

按模式删除(生产环境谨慎使用)

Use SCAN instead of KEYS for large datasets

大数据集下使用SCAN替代KEYS

SCAN 0 MATCH cache:user:* COUNT 100
SCAN 0 MATCH cache:user:* COUNT 100

Tag-based invalidation using sets

使用集合实现基于标签的失效

SADD cache:tags:user:1234 "cache:user:1234:profile" "cache:user:1234:orders"
SADD cache:tags:user:1234 "cache:user:1234:profile" "cache:user:1234:orders"

Invalidate all related caches

失效所有相关缓存

SMEMBERS cache:tags:user:1234
SMEMBERS cache:tags:user:1234

Then delete each key

然后逐个删除键

undefined
undefined

Expiration and Memory Management

过期策略与内存管理

TTL Best Practices

TTL最佳实践

  • Always set TTL on cache keys
  • Use jitter to prevent thundering herd
  • Consider sliding expiration for session data
redis
undefined
  • 始终为缓存键设置TTL
  • 使用抖动避免缓存雪崩
  • 会话数据可考虑使用滑动过期
redis
undefined

Set with expiration

设置键并指定过期时间

SET cache:data:123 "value" EX 3600
SET cache:data:123 "value" EX 3600

Set expiration on existing key

为已存在的键设置过期时间

EXPIRE cache:data:123 3600
EXPIRE cache:data:123 3600

Check TTL

查看键的剩余TTL

TTL cache:data:123
TTL cache:data:123

Persist key (remove expiration)

持久化键(移除过期时间)

PERSIST cache:data:123
undefined
PERSIST cache:data:123
undefined

Memory Management

内存管理

redis
undefined
redis
undefined

Check memory usage

查看内存使用情况

INFO memory
INFO memory

Get key memory usage

获取单个键的内存占用

MEMORY USAGE cache:large:object
MEMORY USAGE cache:large:object

Configure max memory policy

配置最大内存策略

CONFIG SET maxmemory 2gb CONFIG SET maxmemory-policy allkeys-lru
undefined
CONFIG SET maxmemory 2gb CONFIG SET maxmemory-policy allkeys-lru
undefined

Transactions and Atomicity

事务与原子性

MULTI/EXEC Transactions

MULTI/EXEC事务

redis
undefined
redis
undefined

Transaction block

事务块

MULTI INCR stats:views LPUSH recent:views "page:123" EXEC
MULTI INCR stats:views LPUSH recent:views "page:123" EXEC

Watch for optimistic locking

使用WATCH实现乐观锁

WATCH user:1234:balance balance = GET user:1234:balance MULTI SET user:1234:balance (balance - 100) EXEC
undefined
WATCH user:1234:balance balance = GET user:1234:balance MULTI SET user:1234:balance (balance - 100) EXEC
undefined

Lua Scripts

Lua脚本

  • Use for complex atomic operations
  • Scripts execute atomically
lua
-- Rate limiting script
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])

local current = tonumber(redis.call('GET', key) or '0')

if current >= limit then
    return 0
end

redis.call('INCR', key)
if current == 0 then
    redis.call('EXPIRE', key, window)
end

return 1
redis
undefined
  • 用于复杂原子操作
  • 脚本执行具有原子性
lua
-- 限流脚本
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])

local current = tonumber(redis.call('GET', key) or '0')

if current >= limit then
    return 0
end

redis.call('INCR', key)
if current == 0 then
    redis.call('EXPIRE', key, window)
end

return 1
redis
undefined

Execute Lua script

执行Lua脚本

EVAL "return redis.call('GET', KEYS[1])" 1 mykey
undefined
EVAL "return redis.call('GET', KEYS[1])" 1 mykey
undefined

Pub/Sub and Messaging

发布/订阅与消息队列

redis
undefined
redis
undefined

Publisher

发布者

PUBLISH channel:notifications '{"type":"alert","message":"New order"}'
PUBLISH channel:notifications '{"type":"alert","message":"新订单"}'

Subscriber

订阅者

SUBSCRIBE channel:notifications
SUBSCRIBE channel:notifications

Pattern subscription

模式订阅

PSUBSCRIBE channel:*
undefined
PSUBSCRIBE channel:*
undefined

High Availability

高可用性

Replication

主从复制

  • Use replicas for read scaling
  • Configure proper persistence on master
redis
undefined
  • 使用从节点实现读扩展
  • 在主节点上配置合适的持久化策略
redis
undefined

On replica

在从节点上配置主节点地址

REPLICAOF master_host 6379
REPLICAOF master_host 6379

Check replication status

查看复制状态

INFO replication
undefined
INFO replication
undefined

Redis Sentinel

Redis哨兵

  • Use for automatic failover
  • Deploy at least 3 Sentinel instances
  • 用于自动故障转移
  • 至少部署3个Sentinel实例

Redis Cluster

Redis集群

  • Use for horizontal scaling
  • Data automatically sharded across nodes
  • Use hash tags for related keys
redis
undefined
  • 用于水平扩展
  • 数据自动分片到各个节点
  • 使用哈希标签确保相关键存储在同一个槽位
redis
undefined

Hash tags ensure keys go to same slot

哈希标签确保相关键进入同一个槽位

SET {user:1234}:profile "data" SET {user:1234}:settings "data"
undefined
SET {user:1234}:profile "data" SET {user:1234}:settings "data"
undefined

Persistence

持久化

RDB Snapshots

RDB快照

redis
undefined
redis
undefined

Manual snapshot

手动触发快照

BGSAVE
BGSAVE

Configure automatic snapshots

配置自动快照策略

CONFIG SET save "900 1 300 10 60 10000"
undefined
CONFIG SET save "900 1 300 10 60 10000"
undefined

AOF (Append-Only File)

AOF(仅追加文件)

redis
undefined
redis
undefined

Enable AOF

启用AOF

CONFIG SET appendonly yes CONFIG SET appendfsync everysec
CONFIG SET appendonly yes CONFIG SET appendfsync everysec

Rewrite AOF

重写AOF文件

BGREWRITEAOF
undefined
BGREWRITEAOF
undefined

Security

安全

  • Require authentication
  • Use TLS for connections
  • Bind to specific interfaces
  • Disable dangerous commands
redis
undefined
  • 启用身份验证
  • 使用TLS加密连接
  • 绑定到特定网络接口
  • 禁用危险命令
redis
undefined

Set password

设置密码

CONFIG SET requirepass "your_strong_password"
CONFIG SET requirepass "your_strong_password"

Authenticate

身份验证

AUTH your_strong_password
AUTH your_strong_password

Rename dangerous commands (in redis.conf)

重命名危险命令(在redis.conf中配置)

rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command KEYS ""
undefined
rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command KEYS ""
undefined

Monitoring

监控

redis
undefined
redis
undefined

Server info

查看服务器信息

INFO
INFO

Memory stats

查看内存统计

INFO memory
INFO memory

Client connections

查看客户端连接

CLIENT LIST
CLIENT LIST

Slow log

查看慢查询日志

SLOWLOG GET 10
SLOWLOG GET 10

Monitor commands (debug only)

监控命令执行(仅用于调试)

MONITOR
MONITOR

Key count per database

查看各数据库的键数量

INFO keyspace
undefined
INFO keyspace
undefined

Connection Management

连接管理

  • Use connection pooling
  • Set appropriate timeouts
  • Handle reconnection gracefully
python
undefined
  • 使用连接池
  • 设置合理的超时时间
  • 优雅处理重连逻辑
python
undefined

Python example with connection pool

Python连接池示例

import redis
pool = redis.ConnectionPool( host='localhost', port=6379, max_connections=50, socket_timeout=5, socket_connect_timeout=5 )
redis_client = redis.Redis(connection_pool=pool)
undefined
import redis
pool = redis.ConnectionPool( host='localhost', port=6379, max_connections=50, socket_timeout=5, socket_connect_timeout=5 )
redis_client = redis.Redis(connection_pool=pool)
undefined

Performance Tips

性能优化技巧

  • Use pipelining for batch operations
  • Avoid large keys (>100KB values)
  • Use SCAN instead of KEYS in production
  • Monitor and optimize memory usage
  • Consider using RedisJSON for complex JSON operations
redis
undefined
  • 使用流水线处理批量操作
  • 避免使用大键(值大于100KB)
  • 生产环境使用SCAN替代KEYS
  • 监控并优化内存使用
  • 复杂JSON操作可考虑使用RedisJSON
redis
undefined

Pipeline example (pseudo-code)

流水线示例(伪代码)

pipe = redis.pipeline() pipe.get("key1") pipe.get("key2") pipe.set("key3", "value") results = pipe.execute()
undefined
pipe = redis.pipeline() pipe.get("key1") pipe.get("key2") pipe.set("key3", "value") results = pipe.execute()
undefined