美文网首页
Nacos - 服务发现(1)

Nacos - 服务发现(1)

作者: __元昊__ | 来源:发表于2020-01-02 15:39 被阅读0次

    教学目标

    1)理解什么是微服务
    2)能够说出服务发现的概念以及使用场景
    3)了解主流的服务发现中心
    4)掌握Nacos作为服务发现中心的快速入门方法
    5)理解Nacos服务发现的核心概念及数据模型
    6)掌握使用Nacos控制台管理服务的操作方法
    7)了解Nacos服务发现API的使用方式
    8)掌握Spring cloud alibaba实际项目架构案例
    9)掌握Nacos与dubbo集成方式

    1 概览

    1.1 从单体架构到微服务

    1.1.1 单体架构

    Web应用程序发展的早期,大部分web工程师将所有的功能模块打包到一起并放在一个web容器中运行,所有功能模块使用同一个数据库,同时,它还提供API或者UI访问的web模块等。


    QQ截图20200102145704.png

    尽管也是模块化逻辑,但是最终它还是会打包并部署为单体式应用,这种将所有功能都部署在一个web容器中运行的系统就叫做单体架构(也叫:巨石型应用)。

    单体架构有很多好处:
    开发效率高:模块之间交互采用本地方法调用,并节省微服务之间的交互讨论时间与开发成本。
    容易测试:IDE都是为开发单个应用设计的、容易测试——在本地就可以启动完整的系统。
    容易部署:运维成本小,直接打包为一个完整的包,拷贝到web容器的某个目录下即可运行。

    但是,上述的好处是有条件的,它适用于小型简单应用,对于大规模的复杂应用,就会展现出来以下的不足:
    复杂性逐渐变高,可维护性逐渐变差 :所有业务模块部署在一起,复杂度越来越高,修改时牵一发动全身。
    版本迭代速度逐渐变慢:修改一个地方就要将整个应用全部编译、部署、启动时间过长、回归测试周期过长。
    阻碍技术创新:若更新技术框架,除非你愿意将系统全部重写,无法实现部分技术更新。
    无法按需伸缩:通过冗余部署完整应用的方式来实现水平扩展,无法针对某业务按需伸缩。

    1.1.2 微服务

    许多大型公司,通过采用微服务架构解决了上述问题。其思路不是开发一个巨大的单体式的应用,而是将应用分解为小的、互相连接的微服务。

    一个微服务一般完成某个特定的功能,比如订单服务、用户服务等等。每一个微服务都是完整应用,都有自己的业务逻辑和数据库。一些微服务还会发布API给其它微服务和应用客户端使用。

    比如,一个前面描述系统可能的分解如下:


    QQ截图20200102150020.png

    每一个业务模块都使用独立的服务完成,这种微服务架构模式也影响了应用和数据库之间的关系,不像传统多个业务模块共享一个数据库,微服务架构每个服务都有自己的数据库。

    微服务架构的好处:

    • 分而治之,职责单一;易于开发、理解和维护、方便团队的拆分和管理
    • 可伸缩;能够单独的对指定的服务进行伸缩
    • 局部容易修改,容易替换,容易部署,有利于持续集成和快速迭代
    • 不会受限于任何技术栈

    1.2 什么是服务发现

    在微服务架构中,整个系统会按职责能力划分为多个服务,通过服务之间协作来实现业务目标。这样在我们的代码中免不了要进行服务间的远程调用,服务的消费方要调用服务的生产方,为了完成一次请求,消费方需要知道服务生产方的网络位置(IP地址和端口号)。

    我们的代码可以通过读取配置文件的方式读取服务生产方网络位置,如下:


    QQ截图20200102150236.png

    我们通过Spring boot技术很容易实现:
    Service B(服务生产者)
    Service B是服务的生产方,暴露/service服务地址,实现代码如下:

    @SpringBootApplication
    @RestController
    public class SpringRestProviderBootstrap {
    public static void main(String[] args) {
    SpringApplication.run(SpringRestProviderBootstrap.class, args);
    }
    @GetMapping(value = "/service") //暴露服务
    public String service(){
    return "provider invoke";
    }
    }
    

    配置文件:

    server.port = 56010
    

    Service A(服务消费者)
    实现代码:

    @SpringBootApplication
    @RestController
    public class SpringRestConsumerBootstrap {
    public static void main(String[] args) {
    SpringApplication.run(SpringRestConsumerBootstrap.class, args);
    }
    @Value("${provider.address}")
    private String providerAddress;
    @GetMapping(value = "/service")
    public String service(){
    RestTemplate restTemplate = new RestTemplate();
    //调用服务
    String providerResult = restTemplate.getForObject("http://" + providerAddress +
    "/service",String.class);
    return "consumer invoke | " + providerResult;
    }
    }
    

    配置文件:

    server.port = 56020
    # 服务生产方地址
    provider.address = 127.0.0.1:56010
    

    访问http://127.0.0.1:56020/service,输出以下内容:

    consumer invoke | provider invoke
    

    看上去很完美,但是,仔细考虑以下,此方案对于微服务应用而言行不通。

    首先,微服务可能是部署在云环境的,服务实例的网络位置或许是动态分配的。另外,每一个服务一般会有多个实例来做负载均衡,由于宕机或升级,服务实例网络地址会经常动态改变。再者,每一个服务也可能应对临时访问压力增加新的服务节点。正如下图所示:

    QQ截图20200102150654.png
    基于以上的问题,服务之间如何相互感知?服务如何管理?这就是服务发现的问题了。如下图:
    QQ截图20200102150724.png
    上图中服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端
    (1)在每个服务启动时会向服务发现中心上报自己的网络位置。这样,在服务发现中心内部会形成一个服务注册表,服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。
    (2)服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。
    (3)当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。

    总结一下,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感知。各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。

    1.3 主流服务发现与配置中心对比

    目前市面上用的比较多的服务发现中心有:Nacos、Eureka、Consul和Zookeeper。


    QQ截图20200102151120.png

    从上面对比可以了解到,Nacos作为服务发现中心,具备更多的功能支持项,且从长远来看Nacos在以后的版本会支持SpringCLoud+Kubernetes的组合,填补 2 者的鸿沟,在两套体系下可以采用同一套服务发现和配置管理的解决方案,这将大大的简化使用和维护的成本。另外,Nacos 计划实现 Service Mesh,也是未来微服务发展的趋势。

    1.4 Nacos简介

    2 Nacos 服务发现快速入门

    本小节,我们将演示如何使用Spring Cloud Alibaba Nacos Discovery为Spring cloud 应用程序与 Nacos 的无缝集成。 通过一些原生的spring cloud注解,我们可以快速来实现Spring cloud微服务的服务发现机制,并使用Nacos Server作为服务发现中心,统一管理所有微服务。

    2.1 Spring Cloud服务协作流程

    现在,我们对Spring cloud内的一些组件还不了解,为了能够完全理解快速入门程序,我们需要学习以下内容。
    Spring Cloud 常见的集成方式是使用Feign+Ribbon技术来完成服务间远程调用及负载均衡的,如下图:


    QQ截图20200102151450.png

    (1)在微服务启动时,会向服务发现中心上报自身实例信息,这里ServiceB 包含多个实例。
    每个实例包括:IP地址、端口号信息。
    (2)微服务会定期从Nacos Server(服务发现中心)获取服务实例列表。
    (3)当ServiceA调用ServiceB时,ribbon组件从本地服务实例列表中查找ServiceB的实例,如获取了多个实例如Instance1、Instance2。这时ribbon会通过用户所配置的负载均衡策略从中选择一个实例。
    (4)最终,Feign组件会通过ribbon选取的实例发送http请求。采用Feign+Ribbon的整合方式,是由Feign完成远程调用的整个流程。而Feign集成了Ribbon,Feign使用Ribbon完成调用实例的负载均衡。

    2.1.1 负载均衡的概念

    在SpringCloud服务协议流程中,ServiceA通过负载均衡调用ServiceB,下边来了解一下负载均衡
    负载均衡就是将用户请求(流量)通过一定的策略,分摊在多个服务实例上执行,它是系统处理高并发、缓解网络压力和进行服务端扩容的重要手段之一。它分为服务端负载均衡客户端负载均衡

    服务器端负载均衡:


    QQ截图20200102151750.png

    在负载均衡器中维护一个可用的服务实例清单,当客户端请求来临时,负载均衡服务器按照某种配置好的规则(负载均衡算法)从可用服务实例清单中选取其一去处理客户端的请求。这就是服务端负载均衡。

    例如Nginx,通过Nginx进行负载均衡,客户端发送请求至Nginx,Nginx通过负载均衡算法,在多个服务器之间选择一个进行访问。即在服务器端再进行负载均衡算法分配。

    客户端服务负载均衡:


    QQ截图20200102152052.png

    我们接下来要讲的Ribbon,就属于客户端负载均衡。在ribbon客户端会有一个服务实例地址列表,在发送请求前通过负载均衡算法选择一个服务实例,然后进行访问,这是客户端负载均衡。即在客户端就进行负载均衡算法分配。

    Ribbon是一个客户端负载均衡器,它的责任是从一组实例列表中挑选合适的实例,如何挑选?取决于负载均衡策略 。

    Ribbon核心组件IRule是负载均衡策略接口,它有如下实现,大家仅做了解:

    • RoundRobinRule(默认):轮询,即按一定的顺序轮换获取实例的地址。
    • RandomRule:随机,即以随机的方式获取实例的地址。
    • AvailabilityFilteringRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
    • WeightedResponseTimeRule: 根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越大,被选中的机率越高;
      刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够时,会切换到WeightedResponseTimeRule
    • RetryRule: 先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务;
    • BestAvailableRule: 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
    • ZoneAvoidanceRule: 默认规则,复合判断server所在区域的性能和server的可用性选择服务器;

    可通过下面方式在spring boot 配置文件中修改默认的负载均衡策略:

    account‐service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
    

    account-service 是调用的服务的名称,后面的组成部分是固定的。

    2.1.2 Feign 介绍

    Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。Feign的英文表意为“假装,伪装,变形”, 可以理解为将HTTP报文请求方式伪装为简单的java接口调用方式。

    参考第1章节的ServiceA调用ServiceB的例子,我们使用Feign实现这个过程,代码如下:
    Service B暴露"/service"服务端点,如下:

    @SpringBootApplication
    @RestController
    public class SpringRestProviderBootstrap {
    public static void main(String[] args) {
    SpringApplication.run(SpringRestProviderBootstrap.class, args);
    }
    @GetMapping(value = "/service") //暴露服务
    public String service(){
    return "provider invoke";
    }
    }
    

    Feign调用方式如下:
    (1)声明Feign客户端

    @FeignClient(value = "serviceB")
    public interface ServiceBAgent {
    /**
    * 根据用户名查询账号信息
    * @param username 用户名
    * @return 账号信息
    */
    @GetMapping(value = "/service")
    public String service();
    }
    

    (2)业务调用

    @Autowired
    private ServiceBAgent serviceBAgent;
    //....略
    serviceBAgent.service();
    //....略
    

    是不是非常简单?并且在业务调用时,减少了与业务无关的http请求相关代码的编写,使业务逻辑清晰。咱们分析一下Feign帮我们做了哪些事儿:

    • 在 声明Feign客户端 之后,Feign会根据@FeignClient注解使用java的动态代理技术生成代理类,在这里我们指定@FeignClient value为serviceB,则说明这个类的远程目标为spring cloud的服务名称为serviceB的微服务。
    • serviceB的具体访问地址,Feign会交由ribbon获取,若该服务有多个实例地址,ribbon会采用指定的负载均衡策略选取实例。
    • Feign兼容spring的web注解(如:@GetMapping),它会分析声明Feign客户端方法中的Spring注解,得出Http请求method、参数信息以及返回信息结构。
    • 当业务调用Feign客户端方法时,会调用代理类,根据以上分析结果,由代理类完成实际的参数封装、远程http请求,返回结果封装等操作。

    另外,别忘了,若在在Spring cloud中使用Feign,需要引入以下依赖:

    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring‐cloud‐starter‐openfeign</artifactId>
    </dependency>
    

    Feign默认集成了Ribbon,可以直接使用。

    还需要在spring cloud 启动类中标注@EnableFeignClients,表明此项目开启Feign客户端:

    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class SpringRestConsumerBootstrap {
    public static void main(String[] args) {
    SpringApplication.run(SpringRestConsumerBootstrap.class, args);
    }
    ...
    

    总结:通过上面的学习,我们已经了解Spring cloud的微服务是如何协作的,通过哪些组件的配合能够完成服务间协作?我们了解了什么是负载均衡,Feign用于服务间Http调用,Ribbon用于执行负载均衡算法选取访问实例,而Ribbon的实例列表来源是由Spring cloud的服务发现中心提供(当前实现为Nacos),更详细的内容请学习Spring Cloud的相关课程 。

    相关文章

      网友评论

          本文标题:Nacos - 服务发现(1)

          本文链接:https://www.haomeiwen.com/subject/iykooctx.html