Nacos服务注册与发现——服务发现

1、概览

1.1、什么是服务发现

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

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

 我们通过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

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

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

         基于以上的问题,服务之间如何相互感知﹖服务如何管理?这就是服务发现的问题了。如下图:

         上图中服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端。

      (1)在每个服务启动时会向服务发现中心上报自己的网络位置。这样,在服务发现中心内部会形成一个服务注册表服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。

        (2)服务发现客户端会定期从服务发现中心同步服务注册表,并缓存在客户端。

      (3)当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。

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

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

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

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

2、Nacos服务发现快速入门

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

2.1、Spring Cloud服务协作流程

        Spring Cloud常见的集成方式是使用Feign+Ribbon技术来完成服务间远程调用及负载均衡的,如下图:

(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,下边来了解一下负载均衡︰

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

        服务器端负载均衡∶

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

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

        客户端负载均衡:

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

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

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

        RoundRobinRule(默认)轮询,即按一定的顺序轮换获取实例的地址。

        RandomRule:随机,即以随机的方式获取实例的地址。

        AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;   

        WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越大,被选中的机率越高;

                刚启动时,如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够时,会切换到weightedResponseTimeRule

        RetryRule:先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务;

        BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;

        ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器;

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

account-service.ribbon.NFLoadBalancerRuleClassName=con.netflix.loadbalancer.RandomRule

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

2.1.2、Feign介绍

        Feign是Netflix开发的声明式、模板化的HTTP客户端,Feign可以帮助我们更快捷、优雅地调用HTTP APL。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客户端

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

        (2)、业务调用

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

        在业务调用时,减少了与业务无关的http请求相关代码的编写,使业务逻辑清晰。分析一下Feign做了哪些事儿:

        1、在声明Feign客户端之后,Feign会根据@FeIgnClient注解使用java的动态代理技术生成代理类,在这里我们指定@FeignClient value为serviceB,则说明这个类的远程目标为spring cloud的服务名称为serviceB的微服务。

        2、serviceB的具体访问地址,Feign会交由ribbon获取,若该服务有多个实例地址,ribbon会采用指定的负载均衡策略选取实例。

        3、Feign兼容spring的web注解(如:@GetMapping ),它会分析声明Feign客户端方法中的Spring注解,得出Http请求method、参数信息以及返回信息结构。

        4、当业务调用Feion客户端方法时佘调用代理类,根据以上分析结果,由代理类完成实际的参数封装,远程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 SpringRestConsumerBootstrarr {
    public static void main(String[ ] arg) {
        SpringApplication.run(SpringRestConsumerBootstrap.class, args);
    }
}

        总结:Feign用于服务间Http调用,Ribbon用于执行负载均衡算法选取访问实例,而Ribbon的实例列表来源是由Spring cloud的服务发现中心提供(当前实现为Nacos )。

2.2、创建父工程

        为了规范依赖版本,这里创建父工程,指定依赖的版本

        父工程pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xm
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值