Spring Cloud Nacos

一、介绍: What is Nacos

     Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

    1、架构: 

二、运行

    1)、单机版:        

        1、nacos-server二进制包: 图解Nacos单机| ProcessOn免费在线作图,在线流程图,在线思维导图

            (1)、下载nacos-server-2.0.4.tar.gz

            (2)、解压:tar -zxvf nacos-server-2.0.4.tar.gz

            (3)、运行(单机):sh bin/startup.sh -m standalone

            (4)、关闭:sh bin/startup.sh shutdown.sh

            其他:默认集群模式,可见startup.sh默认MODE是cluster;默认端口8848,可见conf/application.properties       

     2、源码运行

            (1)、下载nacos-2.0.4.zip

            (2)、解压并用idea工具编译

            (3)、运行nacos-console

            (4)、运行参数增加:VM options:-Dnacos.standalone=true -Dnacos.home=nacos-home-standalone

            其他:默认集群模式,可见startup.sh默认MODE是cluster;默认端口8848,可见conf/application.properties

    2)、集群

            1、多服务器部署:简易图解: 图解Nacos集群| ProcessOn免费在线作图,在线流程图,在线思维导图

            (1)、准备三台服务器        

            192.168.226.128
            192.168.226.129
            192.168.226.130

            (2)、nacos集群配置:修改3台服务器配置文件 conf/cluster.conf.example 并重名名为cluster.conf文件

            #it is ip
            #example
            192.168.226.128:8848
            192.168.226.129:8848
            192.168.226.130:8848

             (3)、初始化nacos mysql脚本:设置在130服务

mysql -uroot -p
create database nacos;
use nacos;
source /root/nacos/conf/nacos-mysql.sql;
show tables;

            

             (4)、derby切换成mysql数据库:

                4.1、打开nacos/conf/application.properties配置mysql数据库地址和账号

                4.2、重启nacos

                    依次启动3台nacos:sh  /bin/startup.sh

                4.3、访问nacos管理界面                       

            2、单服务器集群部署: 图解Nacos集群-source版| ProcessOn免费在线作图,在线流程图,在线思维导图

nacos2.x版本采用grpc进行集群通信,grpc默认nacos server端口+1000作为通信端口(默认8848+1000=9848),所以服务部署避免grpc端口冲突。

                (1)、idea打开nacos源码

                (2)、新增conf/cluster.conf文件:可以从distribution/conf/cluster.conf.example拷贝重命名文件修改                            

            (3)、将derby修改成mysql数据库         

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://192.168.226.130:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=

         

            (4)、配置启动参数:分别配置8841、8843、8845

            (5)、启动服务

三、服务注册和发现

    1)、http接口

            1、注册:

curl -X POST 'http://serverIp:8848/nacos/v1/ns/instance?serviceName=client.server.name&ip=clinetIp&port=client端口'
例如:curl -X POST 'http://192.168.226.130:8848/nacos/v1/ns/instance?serviceName=lis.routine&ip=172.17.17.15&port=20010'

            2、发现:

curl -X GET 'http://serverIp:8848/nacos/v1/ns/instance/list?serviceName=client.server.name'
例如:curl -X GET 'http://192.168.226.130:8848/nacos/v1/ns/instance/list?serviceName=lis.rounte'

    2)、java SDK: Java SDK (nacos.io)

            1、应用maven包

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>2.0.4</version>
        </dependency>

            2、模拟http注册和发现

public static void main(String[] args) throws NacosException, IOException {
        Properties properties = new Properties();
        properties.setProperty("serverAddr","127.0.0.1:8848");
        NamingService namingService = NamingFactory.createNamingService(properties);
        //服务注册
        namingService.registerInstance("lis.user","172.17.17.114",20100,"DEV1");
        //服务发现
        System.out.println(namingService.getAllInstances("lis.user"));
        // 进程不停止,nacos client会不断地向nacos server发送心跳  时间间隔
        System.in.read();
    }

    3)、spring cloud:

            1、添加pom依赖

<!--spring bott依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--引入nacos 注册依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

            2、application配置

server:
  port: 9091
  
spring:
  application:
    # 服务名称
    name: order
  cloud:
    nacos:
      # nacos 注册地址
      server-addr: localhost:8848

        3、启动两个服务

四、原理

    1)、Nacos领域模型

    namespace:命名空间(相当于租户概念),隔离资源空间

    group:数据分组

    service:服务

    cluster:服务下的集群

    instance:具体提供服务的实例

    2)、nacos元数据

            描述信息,版本号、容灾策略、负载策略、鉴权配置、自定义标签等配置信息

spring:
  cloud:
    nacos:
      discovery:
        metadata:
          version: 1.0.0
          date: 2023-08-09

           

四、源码

   4.1、概述            

    

    4.2、源码流程解析        

        1)、N1 Nacos Server 启动

               源码流程图:N1 Nacos Server 启动 流程图模板_ProcessOn思维导图、流程图

               1、Spring Boot 启动流程

                

                2、通过Spring Boot 扩展机制:bean的扩展机制beanPostPrecessor拦截bean ->BaseRpcServer#start                

                3、nacos启动:9848作为grpc服务端和客户端通信;9849作为grpc服务端注册中心数据同步

                4、nacos服务启动提供api                            

        

            

        2)、S1 服务注册

        源码流程图:S1 服务注册 流程图模板_ProcessOn思维导图、流程图

            1、SpringApplication.run 项目启动:Spring Boot发布ServletWebServerInitializedEvent事件

            

            2、Spring Cloud监听器AbstractAutoServiceRegistration 监听感兴趣事件WebServerInitializedEvent,并回调AbstractAutoServiceRegistration#onApplicationEvent

/*
* 1、Spring Cloud监听器AbstractAutoServiceRegistration 监听感兴趣事件WebServerInitializedEvent,回调AbstractAutoServiceRegistration#onApplicationEvent
*/
public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.bind(event);
    }
}


/*
* 2、bind
*/
@Deprecated
public void bind(WebServerInitializedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
        this.port.compareAndSet(0, event.getWebServer().getPort());
        this.start();
    }
}


/*
* 3、start
*/
public void start() {
    if (!this.isEnabled()) {
        if (logger.isDebugEnabled()) {
            logger.debug("Discovery Lifecycle disabled. Not starting");
        }




    } else {
        if (!this.running.get()) {
            this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
            this.register();
            if (this.shouldRegisterManagement()) {
                this.registerManagement();
            }
            this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
            this.running.compareAndSet(false, true);
        }
    }
}


/*
* 4、register
*/
protected void register() {
    this.serviceRegistry.register(this.getRegistration());
}

            3、Spring Cloud 注册接口:org.springframework.cloud.client.serviceregistry#register,其他组件实现注册方法,具体结构如下图

public interface ServiceRegistry<R extends Registration> {
    void register(R registration);
}

            4、Nacos实现注册

                    Nacos注册服务默认临时节点,通过grpc发送InstanceRequest调用Nacos服务注册(1.4.X版本没有grpc功能)

  

/*
* 1、Nacos注册:NacosServiceRegistry#register -> namingService.registerInstance(serviceId, group, instance)
*/
public void register(Registration registration) {
    if (StringUtils.isEmpty(registration.getServiceId())) {
        log.warn("No service to register for nacos client...");
    } else {
        NamingService namingService = this.namingService();
        String serviceId = registration.getServiceId();
        String group = this.nacosDiscoveryProperties.getGroup();
        Instance instance = this.getNacosInstanceFromRegistration(registration);
        try {
            namingService.registerInstance(serviceId, group, instance);
            log.info("nacos registry, {} {} {}:{} register finished", new Object[]{group, serviceId, instance.getIp(), instance.getPort()});
        } catch (Exception var7) {
            if (this.nacosDiscoveryProperties.isFailFast()) {
                log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var7});
                ReflectionUtils.rethrowRuntimeException(var7);
            } else {
                log.warn("Failfast is false. {} register failed...{},", new Object[]{serviceId, registration.toString(), var7});
            }
        }

    }
}


/*
* 2、NacosNamingService#registerInstance
*/
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    NamingUtils.checkInstanceIsLegal(instance);
    this.clientProxy.registerService(serviceName, groupName, instance);
}


/*
* 3、NamingClientProxyDelegate#registerInstance  -> 临时节点(注册进程停了移除) -> grpcClientProxy
*/
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    this.getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);
}


private NamingClientProxy getExecuteClientProxy(Instance instance) {
    return (NamingClientProxy)(instance.isEphemeral() ? this.grpcClientProxy : this.httpClientProxy);
}


/*
* 4、NamingGrpcClientProxy#registerInstance
*/
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", new Object[]{this.namespaceId, serviceName, instance});
    this.redoService.cacheInstanceForRedo(serviceName, groupName, instance);
    this.doRegisterService(serviceName, groupName, instance);
}

            5、Nacos服务端接收客户端InstanceRequest注册请求

       3)、S2 服务心跳:客户端创建rpcClient连接会发送心跳检查

                源码流程图:S2 定时心跳客户端检测 流程图模板_ProcessOn思维导图、流程图

                  1、客户端每5s发送心跳检查

       4)、N2 定时心跳客户端检测   

                源码流程图:N2 定时心跳客户端检测 流程图模板_ProcessOn思维导图、流程图

        4.1、临时实例:

           1、1.x版本 15s没收到健康状态healthy设置为true,30s后还没接收到客户端心跳使用HTTP DELETE方式调用/v1/ns/instance地址,注册表表剔除该实例(该接口也是在InstanceController类中);

           2、 2.x版本 20s添加到过期集合-探活失败移除实例

       

     4.1、持久实例:

        1、注册中心探测机制:探测周期2s~5s随机,检测异常健康状态设置true,不会剔除实例。采用tcp(ping)、http、mysql探测

        2、使用场景:非弹性扩容实例,可检测不健康实例;另外起到保护阈值防止雪崩作用(分流作用)

       5)、 C1 服务发现与订阅

                源码流程图:https://www.processon.com/preview/64f1906d8abe6e4c2dd893bb

                    服务发现:客户端 向 服务端pull查询接口

                    服务订阅:服务端 向 客户端push更新数据

       6)、 C2 服务列表本地缓存

                源码流程图:C2 服务列表本地缓存 流程图模板_ProcessOn思维导图、流程图

                1、服务发现和订阅 获取客户端会优先从本地缓存获取

            

                2、服务发现 本地缓存未获取从Nacos服务获取客户端后,更新到本地缓存

                        2.1、异步任务获取后更新到本地缓存                    

                        2.1、异步任务未获取到从Nacos服务端获取到更新到本地缓存

                3、订阅 服务更新后  发布ServiceChangedEvent事件,用于推送消息给对应的订阅者

五、CAP

        1)、AP:Distro同步数据架构

        2)、CP:raft架构

                     Raft Consensus Algorithm

                     Raft (thesecretlivesofdata.com)

六、删除服务

    1、临时实例无需删除,不健康实例自动删除

    2、持久实例先通过OpenAPI注销实例

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值