Nacos
1. Nacos的注册表结构
回答:
描述
Nacos采用了分级存储模型,最外层是NameSpace,用来隔离环境,比如开发,测试环境。然后是Group服务分组。接下来就是服务(Service)了,一个服务包括很多的实例,但是这些实例可以处在不同的机房,因此Service下面有集群(Cluster),集群下面就是对应不同的实例(Instance)。
对应Java代码
Nacos采用多层Map来表示。结构为Map< String,Map< String,Service> ,其中最外层key是对应NameSpace,值是一个Map。内层Map的key对应Group拼接ServiceName值对应是service对象。service对象内部又是一个Map,key是集群名称,value是Cluster对象。而Cluster对象内部维护着一个Instance的set集合。
2. Nacos如何支撑数十万的服务注册
从两个方面来说一个是Nacos集群(高可用),另一个从Nacos底层执行注册功能的步骤来说。
集群就不多说,主要说说内部如何处理注册请求(高并发写)。
Nacos内部接受注册的请求时,不会立即写数据,而是将服务注册的任务放到一个阻塞队列就立即响应给客户端。然后利用线程池读取阻塞队列中的任务(是个死循环,有则处理,无则等待),异步完成实例的更新,其中Service是利用局部同步锁,使得service服务中的实例串行执行,从而保证安全的同时提高并发写的能力。
其实思想与抢优惠卷是一样的:利用lua脚本在缓存中操作(速度快),然后将信息放入消息队列,数据库则从消息队列中一直读取数据并且进行操作。
3. Nacos如何避免并发读写冲突的问题?
Nacos在更新实例列表时,采用copy-on-write的技术,首先将旧的数据拷贝一份,然后更新拷贝的实例列表,再用更新后的实例列表来覆盖旧的实例列表。
在更新过程中避免了读写冲突,只是读的是旧数据,最后直接一次性覆盖。
注意:这里有的小伙伴会问如果多个不同线程都去copy-on-write最后乱写(并发写),其实是不存在的,因为在第二点中提到在Service层使用了同步锁,使得更新实例是串行执行的。
4. Nacos的心跳检测
时间都是相对最后一次心跳时间。
- 对于临时实例(默认是临时实例),实例需要向注册中心提供心跳信息(每隔5s),如果注册中心15s后未收到心跳信息,认为该实例处于不健康状态,超过30s自动剔除。
- 对于非临时实例(亲儿子),Nacos自动定期发送健康检测,询问其是否健康。