ServiceStateMachine在snapshot的过程中没有加锁,是否安全
Your question
例如:DataConfirmStatusService.copy方法中,是对集合生成了新对象,但是value是引用类型,在snapshot的过程中如果还有LogEntry对引用类型做修改了,是不是会导致snapshot中包含了未来的信息。 假如 logIndex=1000的时候DataNode的值Map<String/ipAddress/, DataNode>只有一个元素,但是snapshot的过程中又来了logIndex-1001的日志,应用到状态机中时将Map中添加了元素,导致最终snapshot的logIndex=1000,可是map内容却又2个元素了,这样在系统重启的时候,先从snapshot中恢复出来的logIndex=1000的包含了2条记录,然后应用1001的LogEntry后,第二条日志会被重复执行,请指点下是不是会存在这个问题
return new DataConfirmStatusService(new ConcurrentHashMap<>(expectNodes), new LinkedBlockingQueue<>(expectNodesOrders));
describe your question clearly
Your scenes
describe your use scenes (why need this feature)
Your advice
describe the advice or solution you'd like
Environment
- SOFARegistry version:
- JVM version (e.g.
java -version): - OS version (e.g.
uname -a): - Maven version:
- IDE version:
看了下源码,snapshot也是往taskQueue的ringBuffer中提交了Task,由于状态机中的Task是顺序onApply的,这样的话如果是单线程执行,就不会出现snapshot的过程中有其他logEntry处理,就不会改变状态机中的其他对象的值了吧
@Override
public boolean onSnapshotSave(final SaveSnapshotClosure done) {
return enqueueTask((task, sequence) -> {
task.type = TaskType.SNAPSHOT_SAVE;
task.done = done;
});
}
这个是由raft框架保证了顺序性 最新的6.x版本,我们去除了raft依赖,因为raft的强一致特性,对于可用性其实是不很友好的,另外raft这种强一致的算法,也无法强管控介入去运维,例如我们想人工指定meta leader,其实是在raft下很难做到的。 @tsgmq