1. 当缓存遇到一致性难题
作为老牌内存数据库的扛把子,Redis就像个超级快递员,每天处理着数以亿计的数据存取请求。但这位快递员有个职业困惑:当数据需要同时出现在多个仓库(节点)时,如何保证所有包裹(数据)都能准确无误地送达?特别是在网络延迟、机器故障等突发情况下,这个挑战就更加棘手了。
2. 主从复制的数据接力赛
主从架构就像流水线作业,主库(Master)负责接单,从库(Slave)负责打包发货。通过以下命令建立主从关系:
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
复制过程分为三阶段:
- 主库生成RDB快照文件
- 传输快照到从库
- 持续同步增量数据
但需要注意复制延迟问题,当主库写入后立即查询从库可能会读到旧数据。可以通过INFO replication
命令查看复制偏移量:
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=15456,lag=0
master_repl_offset:15456
3. 持久化双保险策略
Redis提供两种数据落地方案,就像给数据上了双重保险:
RDB快照模式(定时存档):
save 900 1 # 15分钟有1次修改就保存
save 300 10 # 5分钟有10次修改
AOF日志模式(实时记账):
appendonly yes
appendfsync everysec # 每秒同步
混合模式配置示例:
aof-use-rdb-preamble yes # 同时启用两种格式
当服务器意外宕机时,重启后会优先加载AOF文件,因为它的数据完整性更好。可以通过BGREWRITEAOF
命令手动触发日志重写压缩。
4. 事务与原子操作控制
Redis的事务不像传统数据库那么严谨,更像是批量操作的打包服务。使用MULTI
开启事务后,所有命令会进入队列,直到EXEC
执行:
using (var redis = ConnectionMultiplexer.Connect("localhost"))
{
var db = redis.GetDatabase();
var tran = db.CreateTransaction();
tran.AddCondition(Condition.StringEqual("balance", "100")); // 乐观锁检查
tran.StringSetAsync("balance", "80");
tran.StringSetAsync("log", "支付成功");
bool committed = tran.Execute(); // 返回是否提交成功
}
这段C#代码使用StackExchange.Redis库实现了带乐观锁的事务操作,适用于账户余额变更等需要原子性保证的场景。
5. Lua脚本的原子魔法
对于需要复杂判断的原子操作,Redis直接内置了Lua解释器。比如库存扣减场景:
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
redis.call('DECR', KEYS[1])
return "SUCCESS"
else
return "OUT_OF_STOCK"
end
执行脚本命令:
EVAL "上述Lua代码" 1 item_001
Lua脚本执行期间会阻塞其他命令,相当于给操作加了原子性保护罩。
6. 分布式锁攻防战
跨节点操作时,RedLock算法是常用解决方案。C#实现示例:
var redlockFactory = RedLockFactory.Create(
new List<RedLockMultiplexer>
{
ConnectionMultiplexer.Connect("server1:6379"),
ConnectionMultiplexer.Connect("server2:6380")
});
using (var redLock = redlockFactory.CreateLock(
"order_lock",
TimeSpan.FromSeconds(30),
TimeSpan.FromSeconds(10),
TimeSpan.FromSeconds(1)))
{
if (redLock.IsAcquired)
{
// 执行业务逻辑
}
}
这里使用RedLockNet库实现分布式锁,设置获取锁的超时时间为10秒,锁持有时间30秒,重试间隔1秒。注意要处理时钟漂移问题,建议配合看门狗线程续期锁。
7. 典型应用场景分析
- 电商秒杀:Lua脚本保证库存扣减原子性
- 金融交易:事务+持久化确保操作可追溯
- 分布式会话:主从复制实现跨机房数据同步
- 实时排行榜:持久化策略保证数据安全
- 配置中心:AOF日志实现配置变更审计
8. 技术方案优劣对比
方案 | 一致性强度 | 性能影响 | 适用场景 |
---|---|---|---|
主从复制 | 最终一致 | 低 | 读写分离、数据备份 |
AOF持久化 | 强一致 | 中 | 金融交易、配置管理 |
事务操作 | 弱原子性 | 低 | 简单批量操作 |
Lua脚本 | 强原子性 | 中 | 复杂业务逻辑 |
分布式锁 | 最终一致 | 高 | 跨服务资源协调 |
9. 避坑指南
- 主从切换时注意脑裂问题,建议设置合理的超时参数
- AOF重写期间可能占用大量IO,建议在低峰期执行
- 事务中的命令不要包含耗时操作,避免阻塞其他请求
- Lua脚本复杂度控制在毫秒级,避免长时间阻塞
- 分布式锁要设置合理的TTL,防止死锁
10. 总结与选择建议
Redis的数据一致性保障就像多层级防护网:
- 单节点场景优先使用事务/Lua脚本
- 跨节点数据同步依赖主从复制+持久化组合拳
- 分布式环境配合RedLock实现跨服务协调
没有银弹方案,需要根据业务的实际需求在一致性和性能之间找到平衡点。对于强一致性要求的场景,建议采用Redis模块的增强功能(如Redis Labs的Active-Active架构)或结合其他数据库实现混合存储方案。