我来为你提供一个完整的 Python 操作 Redis 集群的示例。
1. 安装必要的库
pip install redis-py-cluster
2. 完整的 Redis 集群操作示例
#!/usr/bin/env python3
"""
Redis 集群操作完整示例
"""
from rediscluster import RedisCluster
import json
import time
from datetime import datetime
class RedisClusterManager:
def __init__(self, startup_nodes, password=None):
"""
初始化 Redis 集群连接
Args:
startup_nodes: Redis 集群节点列表
password: 密码(如果有)
"""
# Redis 集群连接参数
self.connection_kwargs = {
'decode_responses': True, # 自动解码,返回字符串而不是字节
'skip_full_coverage_check': True, # 跳过完整覆盖检查
}
if password:
self.connection_kwargs['password'] = password
# 创建 Redis 集群连接
try:
self.redis_cluster = RedisCluster(
startup_nodes=startup_nodes,
**self.connection_kwargs
)
print("✅ Redis 集群连接成功!")
# 获取集群信息
self.print_cluster_info()
except Exception as e:
print(f"❌ 连接 Redis 集群失败: {e}")
raise
def print_cluster_info(self):
"""打印集群信息"""
try:
# 获取集群信息
cluster_info = self.redis_cluster.info()
print("\n=== Redis 集群信息 ===")
print(f"集群状态: {cluster_info.get('cluster_state', '未知')}")
print(f"已知节点数: {cluster_info.get('cluster_known_nodes', '未知')}")
print(f"槽位分配状态: {cluster_info.get('cluster_slots_assigned', '未知')}")
print(f"槽位正常状态: {cluster_info.get('cluster_slots_ok', '未知')}")
except Exception as e:
print(f"获取集群信息失败: {e}")
def basic_operations(self):
"""基本键值操作示例"""
print("\n=== 基本键值操作 ===")
try:
# 1. 设置字符串值
self.redis_cluster.set("user:1001:name", "张三")
print("✅ 设置字符串值成功")
# 2. 获取字符串值
name = self.redis_cluster.get("user:1001:name")
print(f"获取值: user:1001:name = {name}")
# 3. 设置带过期时间的值
self.redis_cluster.setex("session:abc123", 300, "session_data")
print("✅ 设置带过期时间的值成功")
# 4. 检查键是否存在
exists = self.redis_cluster.exists("user:1001:name")
print(f"键 user:1001:name 是否存在: {exists}")
# 5. 删除键
self.redis_cluster.delete("user:1001:name")
exists_after = self.redis_cluster.exists("user:1001:name")
print(f"删除后键是否存在: {exists_after}")
except Exception as e:
print(f"❌ 基本操作失败: {e}")
def hash_operations(self):
"""哈希操作示例"""
print("\n=== 哈希操作 ===")
try:
# 1. 设置哈希字段
user_data = {
"id": "1001",
"name": "李四",
"age": "25",
"email": "lisi@example.com"
}
self.redis_cluster.hset("user:1001", mapping=user_data)
print("✅ 设置哈希成功")
# 2. 获取所有字段
all_fields = self.redis_cluster.hgetall("user:1001")
print(f"用户信息: {all_fields}")
# 3. 获取特定字段
name = self.redis_cluster.hget("user:1001", "name")
print(f"用户名: {name}")
# 4. 设置多个字段
self.redis_cluster.hmset("user:1001", {"city": "北京", "job": "工程师"})
# 5. 删除哈希字段
self.redis_cluster.hdel("user:1001", "job")
except Exception as e:
print(f"❌ 哈希操作失败: {e}")
def list_operations(self):
"""列表操作示例"""
print("\n=== 列表操作 ===")
try:
list_key = "task:queue"
# 1. 从右侧推入元素
for i in range(5):
self.redis_cluster.rpush(list_key, f"task_{i}")
print("✅ 推入列表元素成功")
# 2. 获取列表长度
length = self.redis_cluster.llen(list_key)
print(f"列表长度: {length}")
# 3. 获取列表所有元素
all_tasks = self.redis_cluster.lrange(list_key, 0, -1)
print(f"所有任务: {all_tasks}")
# 4. 从左侧弹出元素
first_task = self.redis_cluster.lpop(list_key)
print(f"弹出的第一个任务: {first_task}")
# 5. 清空列表
self.redis_cluster.delete(list_key)
except Exception as e:
print(f"❌ 列表操作失败: {e}")
def set_operations(self):
"""集合操作示例"""
print("\n=== 集合操作 ===")
try:
set_key = "user:tags:1001"
# 1. 添加元素到集合
tags = ["python", "redis", "database", "backend"]
for tag in tags:
self.redis_cluster.sadd(set_key, tag)
print("✅ 添加集合元素成功")
# 2. 获取集合所有成员
all_tags = self.redis_cluster.smembers(set_key)
print(f"所有标签: {all_tags}")
# 3. 检查元素是否存在
has_python = self.redis_cluster.sismember(set_key, "python")
print(f"是否包含 'python': {has_python}")
# 4. 获取集合大小
size = self.redis_cluster.scard(set_key)
print(f"集合大小: {size}")
# 5. 移除元素
self.redis_cluster.srem(set_key, "database")
except Exception as e:
print(f"❌ 集合操作失败: {e}")
def sorted_set_operations(self):
"""有序集合操作示例"""
print("\n=== 有序集合操作 ===")
try:
zset_key = "game:scores"
# 1. 添加带分数的成员
scores = {
"player1": 1500,
"player2": 1800,
"player3": 1200,
"player4": 2000
}
self.redis_cluster.zadd(zset_key, scores)
print("✅ 添加有序集合成功")
# 2. 按分数排序获取成员
top_players = self.redis_cluster.zrevrange(zset_key, 0, 2, withscores=True)
print("排行榜前三:")
for player, score in top_players:
print(f" {player}: {score}")
# 3. 获取成员的排名
player2_rank = self.redis_cluster.zrevrank(zset_key, "player2")
print(f"player2 的排名: {player2_rank}")
# 4. 获取分数范围内的成员
high_scores = self.redis_cluster.zrangebyscore(
zset_key, min=1500, max=2500, withscores=True
)
print("高分玩家:")
for player, score in high_scores:
print(f" {player}: {score}")
except Exception as e:
print(f"❌ 有序集合操作失败: {e}")
def json_operations(self):
"""JSON 数据操作示例"""
print("\n=== JSON 数据操作 ===")
try:
# 创建复杂 JSON 数据
product_data = {
"id": "P001",
"name": "智能手机",
"price": 2999.99,
"stock": 100,
"specs": {
"brand": "华为",
"model": "Mate 50",
"color": ["黑色", "白色", "蓝色"]
},
"tags": ["手机", "智能", "5G"],
"timestamp": datetime.now().isoformat()
}
# 存储 JSON 数据
json_key = "product:P001"
self.redis_cluster.set(json_key, json.dumps(product_data, ensure_ascii=False))
print("✅ 存储 JSON 数据成功")
# 读取 JSON 数据
json_str = self.redis_cluster.get(json_key)
if json_str:
loaded_data = json.loads(json_str)
print(f"产品名称: {loaded_data['name']}")
print(f"产品价格: {loaded_data['price']}")
print(f"产品品牌: {loaded_data['specs']['brand']}")
except Exception as e:
print(f"❌ JSON 操作失败: {e}")
def pipeline_operations(self):
"""管道操作示例(批量操作)"""
print("\n=== 管道操作 ===")
try:
# 创建管道
pipeline = self.redis_cluster.pipeline()
# 批量添加操作
start_time = time.time()
for i in range(100, 110):
pipeline.set(f"temp:key:{i}", f"value_{i}")
pipeline.expire(f"temp:key:{i}", 60) # 60秒后过期
# 执行所有操作
results = pipeline.execute()
end_time = time.time()
print(f"✅ 管道操作完成,执行了 {len(results)} 个命令")
print(f"耗时: {end_time - start_time:.3f} 秒")
except Exception as e:
print(f"❌ 管道操作失败: {e}")
def transaction_operations(self):
"""事务操作示例"""
print("\n=== 事务操作 ===")
try:
# 注意:Redis 集群的事务限制在单个节点上
# 我们需要确保所有操作在同一个槽位
# 使用相同的槽位键
key1 = "account:1001:balance"
key2 = "account:1001:history"
# 设置初始值
self.redis_cluster.set(key1, 1000)
# 创建事务
pipeline = self.redis_cluster.pipeline()
# 开始事务(MULTI)
pipeline.multi()
# 在事务中执行多个操作
pipeline.decrby(key1, 200) # 扣除 200
pipeline.rpush(key2, f"支出:200,时间:{datetime.now().isoformat()}")
pipeline.incrby(key1, 50) # 增加 50
# 执行事务(EXEC)
results = pipeline.execute()
print(f"✅ 事务执行成功,结果: {results}")
# 查看最终余额
final_balance = self.redis_cluster.get(key1)
print(f"最终余额: {final_balance}")
except Exception as e:
print(f"❌ 事务操作失败: {e}")
def scan_operations(self):
"""SCAN 操作示例(遍历键)"""
print("\n=== SCAN 操作 ===")
try:
# 插入一些测试数据
for i in range(20):
self.redis_cluster.set(f"test:key:{i}", f"value_{i}")
# 使用 SCAN 遍历键
cursor = 0
pattern = "test:key:*"
count = 5
all_keys = []
print(f"使用模式 '{pattern}' 扫描键:")
while True:
cursor, keys = self.redis_cluster.scan(
cursor=cursor,
match=pattern,
count=count
)
if keys:
all_keys.extend(keys)
print(f" 找到键: {keys}")
if cursor == 0:
break
print(f"总共找到 {len(all_keys)} 个匹配的键")
# 清理测试数据
for key in all_keys:
self.redis_cluster.delete(key)
except Exception as e:
print(f"❌ SCAN 操作失败: {e}")
def test_connection(self):
"""测试连接和基本功能"""
print("\n=== 连接测试 ===")
try:
# 简单的 ping 测试
result = self.redis_cluster.ping()
print(f"Ping 响应: {result}")
# 设置测试键值
test_key = "test:connection"
test_value = f"测试数据 {datetime.now().isoformat()}"
self.redis_cluster.setex(test_key, 10, test_value)
retrieved = self.redis_cluster.get(test_key)
print(f"设置的值: {test_value}")
print(f"获取的值: {retrieved}")
if test_value == retrieved:
print("✅ 连接测试通过")
else:
print("❌ 连接测试失败")
except Exception as e:
print(f"❌ 连接测试失败: {e}")
def close(self):
"""关闭连接"""
try:
self.redis_cluster.close()
print("✅ Redis 集群连接已关闭")
except:
pass
def main():
"""
主函数 - 演示 Redis 集群操作
"""
# Redis 集群节点配置
# 根据你的实际集群配置修改这些节点
startup_nodes = [
{"host": "127.0.0.1", "port": 7000},
{"host": "127.0.0.1", "port": 7001},
{"host": "127.0.0.1", "port": 7002},
# 可以添加更多节点
]
# 如果有密码,在这里设置
password = None # 或 "your_password"
# 创建 Redis 集群管理器实例
redis_manager = None
try:
# 初始化连接
redis_manager = RedisClusterManager(startup_nodes, password)
# 运行各种操作示例
redis_manager.test_connection() # 测试连接
redis_manager.basic_operations() # 基本操作
redis_manager.hash_operations() # 哈希操作
redis_manager.list_operations() # 列表操作
redis_manager.set_operations() # 集合操作
redis_manager.sorted_set_operations() # 有序集合操作
redis_manager.json_operations() # JSON 操作
redis_manager.pipeline_operations() # 管道操作
redis_manager.transaction_operations() # 事务操作
redis_manager.scan_operations() # SCAN 操作
print("\n🎉 所有操作示例完成!")
except Exception as e:
print(f"❌ 程序执行出错: {e}")
finally:
# 确保连接被关闭
if redis_manager:
redis_manager.close()
if __name__ == "__main__":
main()
3. 简单的生产环境示例
#!/usr/bin/env python3
"""
生产环境 Redis 集群工具类
"""
from rediscluster import RedisCluster
import logging
from typing import Any, Optional, Dict, List
import json
class RedisClusterClient:
def __init__(self, nodes: List[Dict], password: Optional[str] = None):
"""
初始化 Redis 集群客户端
Args:
nodes: Redis 集群节点列表 [{"host": "127.0.0.1", "port": 7000}, ...]
password: Redis 密码
"""
self.logger = logging.getLogger(__name__)
# 连接配置
self.connection_pool_kwargs = {
'max_connections': 50,
'decode_responses': True,
}
if password:
self.connection_pool_kwargs['password'] = password
try:
self.client = RedisCluster(
startup_nodes=nodes,
skip_full_coverage_check=True,
socket_keepalive=True,
**self.connection_pool_kwargs
)
self.logger.info("Redis 集群连接成功")
except Exception as e:
self.logger.error(f"Redis 集群连接失败: {e}")
raise
# ========== 通用操作 ==========
def set(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
"""设置键值"""
try:
if expire:
return self.client.setex(key, expire, value)
else:
return self.client.set(key, value)
except Exception as e:
self.logger.error(f"设置键值失败 {key}: {e}")
return False
def get(self, key: str) -> Optional[str]:
"""获取键值"""
try:
return self.client.get(key)
except Exception as e:
self.logger.error(f"获取键值失败 {key}: {e}")
return None
def delete(self, *keys) -> int:
"""删除键"""
try:
return self.client.delete(*keys)
except Exception as e:
self.logger.error(f"删除键失败 {keys}: {e}")
return 0
def exists(self, key: str) -> bool:
"""检查键是否存在"""
try:
return bool(self.client.exists(key))
except Exception as e:
self.logger.error(f"检查键存在失败 {key}: {e}")
return False
def expire(self, key: str, seconds: int) -> bool:
"""设置过期时间"""
try:
return bool(self.client.expire(key, seconds))
except Exception as e:
self.logger.error(f"设置过期时间失败 {key}: {e}")
return False
# ========== JSON 操作 ==========
def set_json(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
"""存储 JSON 数据"""
try:
json_str = json.dumps(value, ensure_ascii=False)
return self.set(key, json_str, expire)
except Exception as e:
self.logger.error(f"存储 JSON 失败 {key}: {e}")
return False
def get_json(self, key: str) -> Optional[Any]:
"""获取 JSON 数据"""
try:
json_str = self.get(key)
if json_str:
return json.loads(json_str)
return None
except Exception as e:
self.logger.error(f"获取 JSON 失败 {key}: {e}")
return None
# ========== 哈希操作 ==========
def hset(self, key: str, mapping: Dict) -> bool:
"""设置哈希字段"""
try:
return bool(self.client.hset(key, mapping=mapping))
except Exception as e:
self.logger.error(f"设置哈希失败 {key}: {e}")
return False
def hgetall(self, key: str) -> Dict:
"""获取所有哈希字段"""
try:
return self.client.hgetall(key)
except Exception as e:
self.logger.error(f"获取哈希失败 {key}: {e}")
return {}
# ========== 分布式锁 ==========
def acquire_lock(self, lock_key: str, timeout: int = 10) -> bool:
"""获取分布式锁"""
import uuid
identifier = str(uuid.uuid4())
try:
# 使用 SET NX EX 命令获取锁
result = self.client.set(
lock_key,
identifier,
ex=timeout,
nx=True
)
return result is True
except Exception as e:
self.logger.error(f"获取锁失败 {lock_key}: {e}")
return False
def release_lock(self, lock_key: str, identifier: str) -> bool:
"""释放分布式锁"""
try:
# 使用 Lua 脚本确保原子性释放锁
lua_script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
"""
result = self.client.eval(lua_script, 1, lock_key, identifier)
return bool(result)
except Exception as e:
self.logger.error(f"释放锁失败 {lock_key}: {e}")
return False
# ========== 批量操作 ==========
def pipeline_execute(self, operations: List[tuple]) -> List:
"""执行管道操作"""
try:
pipeline = self.client.pipeline()
for op in operations:
if len(op) == 2:
getattr(pipeline, op[0])(*op[1])
elif len(op) == 3:
getattr(pipeline, op[0])(*op[1], **op[2])
return pipeline.execute()
except Exception as e:
self.logger.error(f"管道操作失败: {e}")
return []
# ========== 监控和统计 ==========
def get_cluster_info(self) -> Dict:
"""获取集群信息"""
try:
return self.client.info()
except Exception as e:
self.logger.error(f"获取集群信息失败: {e}")
return {}
def get_memory_info(self) -> Dict:
"""获取内存信息"""
try:
return self.client.info('memory')
except Exception as e:
self.logger.error(f"获取内存信息失败: {e}")
return {}
def close(self):
"""关闭连接"""
try:
self.client.close()
self.logger.info("Redis 连接已关闭")
except Exception as e:
self.logger.error(f"关闭连接失败: {e}")
# 使用示例
if __name__ == "__main__":
# 配置日志
logging.basicConfig(level=logging.INFO)
# Redis 集群配置
CLUSTER_NODES = [
{"host": "127.0.0.1", "port": 7000},
{"host": "127.0.0.1", "port": 7001},
{"host": "127.0.0.1", "port": 7002},
]
# 创建客户端
redis_client = RedisClusterClient(CLUSTER_NODES)
try:
# 示例:存储用户数据
user_data = {
"id": 1001,
"name": "张三",
"email": "zhangsan@example.com",
"created_at": "2024-01-01"
}
# 存储 JSON 数据
redis_client.set_json("user:1001", user_data, expire=3600)
# 获取 JSON 数据
retrieved_data = redis_client.get_json("user:1001")
print(f"用户数据: {retrieved_data}")
# 使用分布式锁
lock_key = "order:lock:1001"
if redis_client.acquire_lock(lock_key):
try:
print("获得锁,执行业务操作...")
# 这里执行需要加锁的业务逻辑
time.sleep(1)
finally:
# 注意:实际使用时需要保存 identifier
redis_client.release_lock(lock_key, "")
else:
print("获取锁失败,可能有其他进程在处理")
finally:
# 关闭连接
redis_client.close()
4. 注意事项
- 集群节点配置:确保
startup_nodes中至少有一个节点是可用的 - 键哈希槽:Redis 集群根据键的 CRC16 哈希值分配到不同的槽位
- 事务限制:集群模式下的事务操作必须保证所有键在同一个哈希槽
- 错误处理:始终添加适当的异常处理
- 连接池:生产环境应考虑使用连接池管理连接
- 监控:监控 Redis 集群的健康状态和性能指标
这个示例覆盖了 Redis 集群的大部分常用操作,你可以根据实际需求进行调整和扩展。