nacos 笔记

Nacos AP 实现

Distro协议。Distro是阿里巴巴的私有协议,目前流行的 Nacos服务管理框架就采用了 Distro协议。Distro 协议被定位为 临时数据的一致性协议 :该类型协议, 不需要把数据存储到磁盘或者数据库 ,因为临时数据通常和服务器保持一个session会话, 该会话只要存在,数据就不会丢失 。

Distro 协议是一个比较简单的最终一致性协议。整体由节点寻址、数据全量同步、异步增量同步、定时上报client所有信息、心跳探活其他节点等组成。

Distro 协议保证写必须永远是成功的,即使可能会发生网络分区。当网络恢复时,把各数据分片的数据进行合并。

Distro 协议具有以下特点:

专门为了注册中心而创造出的协议;
客户端与服务端有两个重要的交互,服务注册与心跳发送;
客户端以服务为维度向服务端注册,注册后每隔一段时间向服务端发送一次心跳,心跳包需要带上注册服务的全部信息,在客户端看来,服务端节点对等,所以请求的节点是随机的;
客户端请求失败则换一个节点重新发送请求;
服务端节点都存储所有数据,但每个节点只负责其中一部分服务,在接收到客户端的“写”(注册、心跳、下线等)请求后,服务端节点判断请求的服务是否为自己负责,如果是,则处理,否则交由负责的节点处理;
每个服务端节点主动发送健康检查到其他节点,响应的节点被该节点视为健康节点;
服务端在接收到客户端的服务心跳后,如果该服务不存在,则将该心跳请求当做注册请求来处理;
服务端如果长时间未收到客户端心跳,则下线该服务;
负责的节点在接收到服务注册、服务心跳等写请求后将数据写入后即返回,后台异步地将数据同步给其他节点;
节点在收到读请求后直接从本机获取后返回,无论数据是否为最新。

Distro协议服务端节点发现使用寻址机制来实现服务端节点的管理。在 Nacos中,寻址模式有三种:

  1. AddressServerMemberLookup, //使用地址服务器存储节点信息,服务端节点定时拉取信息进行管理
  2. FileConfigMemberLookup //使用Cluster.conf 配置集群
  3. StandaloneMemberLookup //单机模式
    public static MemberLookup createLookUp(ServerMemberManager memberManager) throws NacosException {
        if (!EnvUtil.getStandaloneMode()) {
            String lookupType = EnvUtil.getProperty(LOOKUP_MODE_TYPE);
            LookupType type = chooseLookup(lookupType);
            LOOK_UP = find(type);
            currentLookupType = type;
        } else {
            LOOK_UP = new StandaloneMemberLookup();
        }
        LOOK_UP.injectMemberManager(memberManager);
        Loggers.CLUSTER.info("Current addressing mode selection : {}", LOOK_UP.getClass().getSimpleName());
        return LOOK_UP;
    }

同步数据分两种:

全量同步数据

Distro协议节点启动时会从其他节点全量同步数据。在 Nacos中,整体流程如下:

异步增量同步

      新增数据使用异步广播同步:

  • DistroProtocol 使用 sync() 方法接收增量数据

  • 向其他节点发布广播任务

    • 调用 distroTaskEngineHolder 发布延迟任务

  • 调用 DistroDelayTaskProcessor.process() 方法进行任务投递:将延迟任务转换为异步变更任务

  • 执行变更任务 DistroSyncChangeTask.run() 方法:向指定节点发送消息

    • 调用 DistroHttpAgent.syncData() 方法发送数据

    • 调用 NamingProxy.syncData() 方法发送数据

  • 异常任务调用 handleFailedTask() 方法进行处理

    • 调用 DistroFailedTaskHandler 处理失败任务

    • 调用 DistroHttpCombinedKeyTaskFailedHandler 将失败任务重新投递成延迟任务。

Nacos RAFT 实现

Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它。为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导选取(leader selection)、日志复制(log replication)、安全(safety),并且使用了更强的一致性来减少了必须需要考虑的状态。

Raft算法将 Server划分为3种状态,或者也可以称作角色:
【1】Leader:负责 Client交互和 log复制,同一时刻系统中最多存在1个。
【2】Follower:被动响应请求RPC,从不主动发起请求RPC。
【3】Candidate:一种临时的角色,只存在于 Leader的选举阶段,某个节点想要变成 Leader,那么就发起投票请求,同时自己变成 Candidate。如果选举成功,则变为 Candidate,否则退回为 Follower

在 Raft中,问题分解为:领导选取、日志复制、安全和成员变化。
日志:每台机器保存一份日志,日志来自于客户端的请求,包含一系列的命令
状态机:状态机会按顺序执行这些命令
一致性模型:分布式环境下,保证多机的日志是一致的,这样回放到状态机中的状态是一致的
Nacos server在启动时,会通过 RunningConfig.onApplicationEvent()方法调用 RaftCore.init()方法。

在 init方法主要做了如下几件事:

  1. 获取 Raft集群节点 peers.add(NamingProxy.getServers());
  2. Raft集群数据恢复 RaftStore.load();
  3. Raft选举 GlobalExecutor.register(new MasterElection());
  4. Raft心跳 GlobalExecutor.register(new HeartBeat());
  5. Raft发布内容
  6. Raft保证内容一致性

参照: https://www.cnblogs.com/zhengzhaoxiang/p/14009118.html

注册中心:


sentinel支持500规模

nacos-client:

  1. nacos-client 本地缓存文件 Failover 机制 保证高可用
  2. nacos-client 在接收到 nacos-server 的服务推送之后,会在内存中保存一份,随后会落盘存储一份快照。
  3. snapshot 默认的存储路径为:{USER_HOME}/nacos/naming/ 中
  4. 一个心跳报文包含了全部的服务信息,可以在心跳期间就恢复出服务,保证可用性。
  5. nacos-server 出现网络分区。由于心跳可以创建服务,从而在极端网络故障下,依旧保证基础的可用性。

AP模式下:启动时首先从其他远程节点同步全部数据。 启动时会全量去其他server上获取所有数据,后期增量更新数据
持久化service,所有数据会写到磁盘,并且重启时第一步会先去从磁盘中读取数据。

nacos-server端

持久化方式包括两种:临时节点(AP),持久化节点(CP),其中AP使用的阿里自己的Distro协议,CP使用的是JRaft协议。
Raft协议:写操作只能由master(每个节点负责一部分,不是自己的转发请求)来处理,读由所有节点提供。
AP 协议:distro协议每个server负责部分节点,容易扩容且每个服务器压力不大,Eureka注册时上报所有信息,节点多时,网络,服务端压力大,且浪费内存。
对比:Eureka客户端使用简单的轮询机制,当服务数量巨大时,服务器压力大。
Nacos使用长轮询30S超时
包含的定时器包括:心跳定时器,检测每个server心跳时间(15s disable,30s移除),

 

服务列表实时更新方式:
1. 服务端推送:

实现类:com.alibaba.nacos.naming.push.PushService#onApplicationEvent
服务端有服务列表的事件更新会发布ServiceChangeEvent,心跳检查、服务注册等会触发事件,server取本机上维护的订阅者,每个节点都会维护一部分订阅者,并且维护的订阅者之间还会有重复,
由于后续是UDP发送,重复维护订阅者的成本不是很高
udp推送相对tcp长连接来说会节约很多资源,
udp并不能保证能真正的送到订阅者,但是Nacos还有定时轮训作为兜底,不需要担心数据不会更新的情况

2. 客户端拉取:
      实现类:com.alibaba.nacos.client.naming.core.HostReactor#getServiceInfo

  

原文地址:https://www.cnblogs.com/snow-man/p/15319908.html