Nacos服务注册表结构:Map<namespace, Map<group::serviceName, Service>>
nacos 可部署一套对应多个环境,比如生产、开发、测试等,用 namespace 来区分。
举例说明:
ephemeralInstances 临时实例注册,存在内存 BlockingQueue。使用异步队列设计,满足高并发。
persistentInstances 持久实例注册,存在文件
不采用加锁的设计,可以保证高并发。当要更新实例时,先将内存中的注册表实例复制出来,跟要更新的实例对比,如果不一致,则去更新注册表中的实例。
nacos 客户端使用 ScheduledExecutorService 每隔5秒(默认)向服务端发送心跳。
如果 Nacos 是集群的状态,并不是集群中的每节点机器都会检测所有的 Instance 的心跳,而是用算法来计算每个节点机器需要检测那些 Instances,我们来看看源码中是如何计算的:
通过 serviceName 计算出一个 Hash 值然后跟 Nacos 集群中所有机器数量进行取模,对得到的结果进行判断,是否采用当前的Nacos Server节点进行心跳检测。
public boolean responsible(String serviceName) { final List<String> servers = healthyList; // 如果采用独立模式启动,直接返回true if (!switchDomain.isDistroEnabled() || EnvUtil.getStandaloneMode()) { return true; } if (CollectionUtils.isEmpty(servers)) { // means distro config is not ready yet return false; } // 获取当前Nacos Server节点在所有节点列表的第一个index int index = servers.indexOf(EnvUtil.getLocalAddress()); // 获取当前Nacos Server节点在所有节点列表的最后个index int lastIndex = servers.lastIndexOf(EnvUtil.getLocalAddress()); if (lastIndex < 0 || index < 0) { return true; } // 把serviceName进行Hash操作,然后跟service size进行取模 // 取模后的结果在index和lastIndex之间,那么就返回true int target = distroHash(serviceName) % servers.size(); return target >= index && target <= lastIndex; }