Nacos如何避免并发读写冲突问题
刚开始:
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
这个serviceMap装的时一个旧的实例列表,在对集群注册更新的时候,后台异步执行时会将旧的实例拷贝一份整出一个全新的集合,拷贝后
异步执行的线程池里面要往里面新加就新加,想从里面删除就删除,想修改就修改,改的是拷贝过来的,改完再覆盖线上的实例对象,来替换旧的数据。也即是采用了copyOnWrite技术
这样当有其他实例注册进来的时候,就不会有冲突,或者说脏读,读的永远都是最新的,如果直接在原注册表里修改,就会读到中间状态的数据,就会出现服务注册问题。
总结:
Nacos在更新实例列表时,会采用CopyOnWrite技术,首先将旧的实例列表拷贝一份,然后更新拷贝的实例列表,再用更新后的实例列表来覆盖旧的实例列表。
这样在更新的过程中,就不会对读实例列表的请求产生影响,也不会出现脏读问题了。
如果是写的情况下,大家都拷贝完了,如果并发的多个实例都来拷贝,大家都各写个的,结果就会导致注册表不一致,出现服务更新的问题,这个问题其实是在加实例的时候有对服务资源进行加锁处理,因此一个服务的多个实例只能串行执行,不同服务之间当然是可以并行执行的,但是不同服务本身是不一样的,你拷贝你的,我拷贝我的,是不会对整体的服务列表有影响的。因为是同步代码块锁定了这个服务资源,它们是串行执行的,所以并发写是没有冲突的