NServiceBus:如何确保Worker Server间的SagaData保持同步?
解决NServiceBus 4.6.5多Worker Server下SagaData一致性问题
针对你在多Worker Server环境下遇到的SagaData同步问题,结合你已经实现ISagaPersister到Oracle的情况,我给你几个关键的解决方案:
启用乐观并发控制(核心手段)
NServiceBus Saga天生支持乐观并发,你只需要在SagaData类中添加一个版本控制属性,比如:public class YourSagaData : ContainSagaData { // 其他业务字段 public int Version { get; set; } }然后在你的
ISagaPersister实现中,处理更新逻辑时必须做版本校验:- 新增SagaData时,将
Version初始化为0或1; - 更新时,执行带版本条件的SQL语句:
UPDATE YourSagaDataTable SET BusinessField1 = @Value1, BusinessField2 = @Value2, Version = Version + 1 WHERE SagaId = @SagaId AND Version = @CurrentVersion
如果这条语句返回的受影响行数为0,说明当前加载的SagaData已经过期,此时要抛出
NServiceBus.ConcurrencyException。NServiceBus捕获到这个异常后,会自动重试该消息,重试时会从Oracle重新加载最新的SagaData,这样就能保证拿到更新后的版本。- 新增SagaData时,将
确保每次消息处理都加载最新SagaData
NServiceBus的Saga机制默认不会在内存中缓存SagaData,每次处理相关消息时,都会通过ISagaPersister.Get()方法从数据库读取最新数据。所以只要你的Get实现是直接查询Oracle的最新记录(没有做本地缓存),那么其他服务器修改SagaData后,下一次消息处理就会自动获取到更新后的版本。配置合理的重试策略
为了应对并发冲突导致的重试,你需要在NServiceBus 4.6.5中配置重试机制:- 开启二级重试(Second Level Retries):通过
Configure.Features.Enable<SecondLevelRetries>()来启用,它会在一级重试失败后,间隔一段时间再重试,避免短时间内重复冲突; - 调整一级重试的次数,确保有足够的重试机会来获取最新的SagaData。
- 开启二级重试(Second Level Retries):通过
优化ISagaPersister实现与消息处理流程
- 不要在Saga处理逻辑中长时间持有SagaData引用,处理完业务逻辑后立即执行更新并释放,减少并发冲突的概率;
- 避免在Saga中开启长时间的数据库事务,确保更新操作尽快完成,让其他服务器能更快看到最新的SagaData;
- 验证你的
ISagaPersister的Get、Save、Update方法逻辑正确,没有遗漏版本控制或者缓存旧数据的情况。
内容的提问来源于stack exchange,提问作者Miguel Domingos
相关产品推荐
相关产品推荐

