nacos入门实战到源码解析

分布式系统  容错性好  备份数据  一致性协议模块 

实战

本地源码编译

下载源码后,移除 test模块

执行:mvn -Prelease-nacos -Dmaven.test.skip=true -Drat.skip=true clean install -U

多加了个 -Drat.skip=true,这样就能编译成功了。然后在进入 target目录下去启动。

默认用户名和密码: nacos/nacos

IDEA 启动nacos 单机

单例模式,需要设置 -Dnacos.standalone=true

实际上是启动  nacos-console 模块, 该模块包含了 nacos-naming,nacos-config 主要模块

本地IDEA启动之后 就可以 打断点了

IDEA启动nacos 集群

在一台机器 启动 nacos 集群需要注意的地方:

需要将 nacos源码 copy 几份

1. nacos-distribution 模块下:

配置 cluser.conf

2. nacos-console模块下:

配置 mysql数据库信息

#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
 spring.datasource.platform=mysql

### Count of DB:
 db.num=1

### Connect URL of DB:
 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
 db.user=root
 db.password=root

并且,将  nacos-distribution  模块下的 nacos-mysql.sql 中的 sql 执行

3. 需要注意的点:

a. 如果 nacos ip list 和 配置的不一致,看下 C:\Users\yourname\nacos\conf 路径下的 cluster.conf

    如果是linux,则在 /usr/local/nacos/conf目录下

b. 在 C:\Users\yourname\nacos\data\protocol 下 新建一个 raft2 文件夹

nacos源码中  全局搜索  data/protocol/raft ,将其改为 data/protocol/raft2,确保不同的nacos源码中的值不一致就行。

final String parentPath = Paths.get(ApplicationUtils.getNacosHome(), "data/protocol/raft2").toString();

c. 需要修改一下 端口号:确保不同的nacos实例端口不一样

server.port=8848

启动 nacos-console 模块 即可

总结,集群启动,如果是 在一台机器上的话,data/protocol/raft 文件夹不能共用,需要修改。

项目搭建

1. 本地启动nacos服务

        见上

2. 创建 生产者

        pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wxj</groupId>
    <artifactId>nacostest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacostest</name>
    <description>Demo project for nacos</description>
    <properties>
        <java.version>1.8</java.version>
        <nacos.version>2.1.1.RELEASE</nacos.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
        <alibaba-cloud.version>2.1.1.RELEASE</alibaba-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${nacos.version}</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba-cloud.version}</version>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

启动应用加: @EnableDiscoveryClient

     

@SpringBootApplication
@EnableDiscoveryClient
public class NacostestApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacostestApplication.class, args);
    }

}

   

application.yml

server:
  port: 8091
spring:
  profiles:
    active: dev
  application:
    name: nacos-test

application-dev.yml

spring:
  cloud:
    nacos:
      discovery:
        serverAddr: 127.0.0.1:8848
        namespace: 7766dd06-75bf-418d-b779-97b22f488395

3. 创建消费者

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wxj</groupId>
    <artifactId>nacos-consumer-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos-consumer-test</name>
    <description>nacos-test</description>
    <properties>
        <java.version>1.8</java.version>
        <nacos.version>2.1.1.RELEASE</nacos.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
        <alibaba-cloud.version>2.1.1.RELEASE</alibaba-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${nacos.version}</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba-cloud.version}</version>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

        消费者实例代码:

@RestController
@RequestMapping("/v1")
public class ApiController {

    RestTemplate restTemplate = new RestTemplate();
    
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @PostMapping
    public String t1(HttpServletRequest request){
        // 获取 provider
        ServiceInstance provider = loadBalancerClient.choose("nacos-test");
        String url = "http://"+provider.getHost()+":"+provider.getPort()+"/v1?port=8848";

        // 发起调用
        String result = restTemplate.getForObject(url, String.class);
        return "ok";

    }
}

通过springboot + nacos搭建的微服务环境就OK啦

生产端 和 消费端 指定 nacos-client 版本号:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${nacos.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba.nacos</groupId>
                    <artifactId>nacos-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>2.0.3</version>
        </dependency>

开启认证权限功能

nacos配置: 

### If turn on auth system:
nacos.core.auth.enabled=true

服务配置:

spring:
  cloud:
    nacos:
      discovery:
        serverAddr: 127.0.0.1:8848
        namespace: ce9e7df0-b2db-4c5d-a742-3fd2f1eb58c4
        username: nacos
        password: nacos

pom.xml

        

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wxj</groupId>
    <artifactId>nacostest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacostest</name>
    <description>Demo project for nacos</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.7.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>com.alibaba.nacos</groupId>
                    <artifactId>nacos-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>2.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>2.2.9.RELEASE</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.7.RELEASE</version>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

理论

前言

介绍之前,先闲谈几句:

当今 各种技术纷繁复杂,这都是偏向于 应用层面的技术。而应用层面的技术,都是 在使用 基础层面的技术上,开发出来的 为解决 某一方面的问题 而诞生的。

什么叫基础层面的技术呢?比如:通信协议、序列化技术。

什么叫应用层技术呢?比如 nacos

但是,就像是一座大楼,由不同的建筑材料组成,但是 建筑材料 可能又由其他的 材料组成。所以,站在 不同的 层面,基础和应用 是相对的,互相转换的。所以,首先需要确定 一个 对象后,来解析其中用到的技术,可以 把其中用到的技术 称为 基础层面的技术,而这个对象是应用层面的技术。

总体来谈一下 nacos 2.x 组件 用到了哪些技术:

通过查资料,可以从下面几个方面:

1.  访问, OpenAPI / SDK 

2. 通信

3. 业务层/功能

4. 一致性协议

5. 持久化

每一层,都有很多种 不同的 基础层的技术来实现 相应的功能,而每一种 基础层的技术 都可以作为一个专题 来讲了,知识太多 根本学不完啊。

通信

        应用层 通信协议,最常用的 就是 HTTP,像是 Restfull API。一般 使用 HTTP协议 就能满足绝大多数 功能的 使用。然而,通信层 有 面向连接的TCP协议 和 面向无连接的UDP协议。应用层的协议 也有 长连接 和 短连接之分。 HTTP 协议 就是 短链接。 短链接的弊端就是 每次都得 建立连接。nacos 作为 服务发现组件,需要保证 能够 对 微服务 做健康检查。 如果用 HTTP 来做通信,那么 就需要不断的建立连接,然后再断开连接。这对 并发量高的情况下,是不行的。于是,可以选择 长连接 来做通信。当长连接建立后,都基于此长连接来进行通信,就可以很好的支持并发量了。

        因此,是用哪种应用层通信协议呢? 那就需要 根据实际需要来选择。

        当然,HTTP 比较简单方便、长连接 像 grpc 不研究一下 还不懂。

一致性协议

        对于 一致性,是分布式系统的一个问题,CAP说明了 要么满足 CP 要么满足 AP。nacos 作为 数据存储 、分布式的应用,需要 选择 一种 一致性协议 来实现 一致性的要求。一致性协议算法,也有对应的 算法实现。比如:2PC、3PC、Paxos 协议、Raft协议、ZAB协议 等。

        主要区分,应该是 在保证性能的情况下,看是满足 AP 还是 满足 CP。不同是应用 有不同的要求,也需要根据实际需要来选择。

持久化

        持久化也有很多组件,数据库、普通的文件、缓存中间件等等。

业务层/功能层

        这一层 就是 实际的业务能力的实现了,根据实际的需要,来实现不同的功能。功能层 也有很多技术来辅助完成所需要的功能。例如:消息中间建,定时任务,SPI等等,其实 很多的 技术 都是为 功能层 提供服务的,为了更高效的实现 所需要的功能。

        需要注意的是,上面提到的 像 通信、一致性协议、持久化,如果选择了不同的技术,对于 功能层的实现来说,相应的 功能代码 也不一样。

总的来说:

        对于某一个系统,基本可以 从上述 几个方面来 了解。其实 还有 操作系统级别的。技术纷繁复杂,学不完啊。

一致性协议算法

nacos是一个需要存储数据的组件, nacos 服务集群模式下,需要考虑如何保障 各节点数据的一致性 以及数据的同步。于是,需要一些算法来完成。

Raft算法

对于强一致性共识算法,当前工业生产中,最多使用的就是 Raft 协议,Raft 协议更容易让人理解,并且有很多成熟的工业算法实现,比如蚂蚁金服的 JRaft、Zookeeper 的 ZAB、Consul 的 Raft、百度的 braft、Apache Ratis;因为Nacos是Java技术栈,因此只能在 JRaft、ZAB、Apache Ratis 中选择,但是 ZAB 因为和Zookeeper 强绑定,再加上希望可以和 Raft 算法库的支持团队随时沟通交流,因此选择了 JRaft,选择 JRaft 也是因为 JRaft 支持多 RaftGroup,为 Nacos 后面的多数据分片带来了可能。

Raft算法(强一致性)介绍:

两个RPC通信

投票选举  RequestVote RPC

数据交互 AppendEntries RPC

Distro算法

Distro 协议是阿里巴巴自研的一个最终一致性协议,而最终一致性协议有很多,比如 Gossip、Eureka 内的数据同步算法。而 Distro 算法是集 Gossip 以及 Eureka 协议的优点并加以优化而出来的,对于原生的Gossip,由于随机选取发送消息的节点,也就不可避免的存在消息重复发送给同一节点的情况,增加了网络的传输的压力,也给消息节点带来额外的处理负载,而 Distro 算法引入了权威 Server 的概念,每个节点负责一部分数据以及将自己的数据同步给其他节点,有效的降低了消息冗余的问题。

客户端注册:

如果时临时实例,会添加一个 心跳任务,定时 上报心跳,1.x 通过HTTP, 2.x 通过 RPC

1. nacos节点启动时,全量拉取 其他 nacos节点的数据。通过调用 HTTP API

2. 心跳 :微服务 向 nacos 发起 HTTP

3. 探测 :nacos 向微服务 发起 HTTP 或者 TCP 

用哪种算法

根据实际使用需求来看:

注册中心:高可用

服务注册中心组件,需要尽最大可能保证可以对外提供服务,保证服务注册中心的高可用性,因此,需要使用 最终一致性 共识算法,不能用强一致性算法

强一致性共识算法能否对外提供服务是有要求的,如果当前集群可用的节点数没有过半的话,整个算法直接“罢工”,导致服务不可用了。

最终一致共识算法的话,更多保障服务的可用性,并且能够保证在一定的时间内各个节点之间的数据能够达成一致,及时 部分数据没有一致,但是可以对外提供服务,并且数据可以最终一直。

非持久化服务 (Distro):

        微服务通过nacos api注册到nacos节点后,由nacos来保障 数据 在各nacos节点的一致性(naos节点通过调用其他nacos节点的HTTP API 进行数据同步,直到同步成功)。并且需要微服务应用 向nacos节点 上报心跳进行服务实例续约。 

持久化服务  (Raft):

        强一致性共识算法来保障数据的一致性

配置管理:强一致性  raft协议

配置管理的配置数据,必须保证大部分的节点都保存了此配置数据才能认为配置被成功保存了,否则就会丢失配置的变更,如果出现这种情况,问题是很严重的,如果是发布重要配置变更出现了丢失变更动作的情况,那多半就要引起严重的现网故障了,因此对于配置数据的管理,是必须要求集群中大部分的节点是强一致的,而这里的话只能使用强一致性共识算法

注册中心

原理:

网络架构是每个主机都有一个独立的 IP 地址,那么服务发现基本上都是通过某种方式获取到服务所部署的 IP 地址

数据模型:

1. 服务的名字和它对应的网络地址

2. 需要对不健康的实例进行过滤或者针对实例的一些特征进行流量的分配,那么就需要在实例上存储一些例如健康状态、权重属性

3. 随着服务规模的扩大,渐渐的又需要在整个服务级别设定一些权限规则、以及对所有实例都生效的一些开关,于是在服务级别又会设立一些属性

4, 发现单个服务的实例又会有划分为多个子集的需求,例如一个服务是多机房部署的,那么可能需要对每个机房的实例做不同的配置,这样又需要在服务和实例之间再设定一个数据级别

注册中心的健康检查机制

第一种: 普通服务 向注册中心 发送心跳

第二种:注册中心 主动探测 普通服务

nacos健康检查:

临时实例:心跳检查

 永久实例:主动探测

源码解析

基于事件的设计

nacos2.0.3版本,基于长连接,很多的操作都是由事件驱动的。现在分析下:

基本类图如下:

角色1: 事件,Event

角色2:订阅者,Subscriber

角色3:事件发布,EventPublisher

事件发布者 发布事件,订阅该事件的订阅者 便会进行事件处理。

具体代码:

事件,只是一个 简单类,没有特殊的行为:

public abstract class Event implements Serializable {
    
    private static final AtomicLong SEQUENCE = new AtomicLong(0);
    
    private final long sequence = SEQUENCE.getAndIncrement();
    
    /**
     * Event sequence number, which can be used to handle the sequence of events.
     *
     * @return sequence num, It's best to make sure it's monotone.
     */
    public long sequence() {
        return sequence;
    }
    
}

事件订阅者,拥有处理事件的 若干个方法 

public abstract class Subscriber<T extends Event> {
    
    /**
     * Event callback.
     *
     * @param event {@link Event}
     */
    public abstract void onEvent(T event);
    
    /**
     * Type of this subscriber's subscription.
     *
     * @return Class which extends {@link Event}
     */
    public abstract Class<? extends Event> subscribeType();
    
    /**
     * It is up to the listener to determine whether the callback is asynchronous or synchronous.
     *
     * @return {@link Executor}
     */
    public Executor executor() {
        return null;
    }
    
    /**
     * Whether to ignore expired events.
     *
     * @return default value is {@link Boolean#FALSE}
     */
    public boolean ignoreExpireEvent() {
        return false;
    }
}

事件发布者,主要是 对 事件、订阅者的管理 

public interface EventPublisher extends Closeable {
    
    /**
     * Initializes the event publisher.
     *
     * @param type       {@link Event >}
     * @param bufferSize Message staging queue size
     */
    void init(Class<? extends Event> type, int bufferSize);
    
    /**
     * The number of currently staged events.
     *
     * @return event size
     */
    long currentEventSize();
    
    /**
     * Add listener.
     *
     * @param subscriber {@link Subscriber}
     */
    void addSubscriber(Subscriber subscriber);
    
    /**
     * Remove listener.
     *
     * @param subscriber {@link Subscriber}
     */
        void removeSubscriber(Subscriber subscriber);
    
    /**
     * publish event.
     *
     * @param event {@link Event}
     * @return publish event is success
     */
    boolean publish(Event event);
    
    /**
     * Notify listener.
     *
     * @param subscriber {@link Subscriber}
     * @param event      {@link Event}
     */
    void notifySubscriber(Subscriber subscriber, Event event);
    
}

看一下 默认的 事件发布的类:

可以看到,一个线程 管理 一种事件,那么事件很多的时候,线程创建的就很多。只不过,nacos服务端 的事件类型 有限,不会无线的创建事件管理线程。

// 首先,这是一个线程类
public class DefaultPublisher extends Thread implements EventPublisher

// 拥有 事件订阅者 列表 和 事件 列表
protected final ConcurrentHashSet<Subscriber> subscribers = new ConcurrentHashSet<>();
private BlockingQueue<Event> queue;

// 实例化后,该线程就启动运行了
    @Override
    public void init(Class<? extends Event> type, int bufferSize) {
        // 其他代码省略了
        start();
    }

    @Override
    public synchronized void start() {
        // 其他代码省略了
       super.start();
    }

// run方法核心代码, 有事件后,拿到该事件,通知订阅者
           for (; ; ) {
                //其他代码省略了
                
                // 取事件
                final Event event = queue.take();  

                // 订阅者处理,就是遍历订阅者列表 然后调用 订阅者的 方法来处理事件
                for (Subscriber subscriber : subscribers) {
                      notifySubscriber(subscriber, event);
                }
            }
  
//  发布事件,就是 往队列加数据
@Override
    public boolean publish(Event event) {
        //其他代码省略了
        boolean success = this.queue.offer(event);
        return true;
    }

// 订阅管理,就是 对 subscribers Map 的 添加 和删除,就叫者 订阅

这就是 事件机制,和观察者模式很像。只不过,这种模式设计的代码不好阅读,因为事件的 订阅者 和事件 之间的关系,在代码里不太好找。

比如:有微服务注册后,需要将注册信息同步到其他的nacos节点

首先 客户端会发起一个 InstanceRequest 的请求

服务端 会有 InstanceRequestHandler 来处理

服务的处理完后会发布几个事件:

NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));

其中ClientEvent.ClientChangedEvent事件的订阅者的订阅代码如下:

//DistroClientComponentRegistry 类:

@PostConstruct
    public void doRegister() {
        DistroClientDataProcessor dataProcessor = new DistroClientDataProcessor(clientManager, distroProtocol,
                upgradeJudgement);
    }

//DistroClientDataProcessor 类:

public DistroClientDataProcessor(ClientManager clientManager, DistroProtocol distroProtocol,
            UpgradeJudgement upgradeJudgement) {
        this.clientManager = clientManager;
        this.distroProtocol = distroProtocol;
        this.upgradeJudgement = upgradeJudgement;
        NotifyCenter.registerSubscriber(this, NamingEventPublisherFactory.getInstance());
    }


//NotifyCenter 类:
public static void registerSubscriber(final Subscriber consumer, final EventPublisherFactory factory) {

        // DistroClientDataProcessor  是 SmartSubscriber子类
        if (consumer instanceof SmartSubscriber) {
            for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {
 
                if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {
                    INSTANCE.sharePublisher.addSubscriber(consumer, subscribeType);
                } else {
                    addSubscriber(consumer, subscribeType, factory);
                }
            }
            return;
        }
  
    }

// 上面那个 for循环 ((SmartSubscriber) consumer).subscribeTypes() 调的 
//DistroClientDataProcessor 类的方法 返回的 订阅的事件的集合,然后再订阅

@Override
    public List<Class<? extends Event>> subscribeTypes() {
        List<Class<? extends Event>> result = new LinkedList<>();
        result.add(ClientEvent.ClientChangedEvent.class);
        result.add(ClientEvent.ClientDisconnectEvent.class);
        result.add(ClientEvent.ClientVerifyFailedEvent.class);
        return result;
    }

真是,源代码写的爽,读就为难了。不过,这也还算好的了

基于任务的模型

nacos2.0.3 的任务设计如下:

1. 首先 是真正干活的一些接口定义,并且 有一个 类 专门 持有这些接口,也可以把这些真正干活的接口 当作是 组件.

2. task抽象层

task抽象层,分成了2种:一种是 立即执行的,继承了线程接口,是一个线程类。一种是延迟执行。 任务内部是执行任务的具体逻辑,当然,是使用了 上述真正干活的类 来完成具体事情的,task 只是一个 入口。

3. processor 层

processor是执行 task的

4. 引擎层

引擎层,完成 对 task、processor的整合和调用

5. 包装

这一层对 引擎的封装,主要是方便、统一

可以看到,基于task的模型,设计了很多层,对于普通的一般需求开发,似乎不会做这样的设计。

基于事件和任务两种类型有什么不一样呢?

事件,主要是 一种通知

任务,主要是完成某种功能

事件可以不断的产生,但是任务 需要根据某种需求 来执行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值