微服务之注册中心Nacos应用实践

启动Nacos服务

Linux/Unix/Mac启动命令(standalone代表着单机模式运行,非集群模式):

#./startup.sh -m standalone

Windows启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone
说明:
1)执行执行令时要么配置环境变量,要么直接在nacos/bin目录下去执行.
2)nacos启动时需要本地环境变量中配置了JAVA_HOME(对应jdk的安装目录),

访问Nacos服务

打开浏览器,输入http://localhost:8848/nacos,其中默认账号密码nacos/nacos

服务注册与调用入门(重点)

业务描述

创建两个项目Module分别为服务提供者和服务消费者,两者都要注册到NacosServer中(这个server本质上就是一个web服务,端口默认为8848),然后服务提供者可以为服务消费者提供远端调用服务(例如支付服务为服务提供方,订单服务为服务消费方),

 创建Maven父工程,作用就是来管理子模块中所需要的共性依赖,

说明:父工程资源初始化完成以后,将src目录删除,因为父工程只负责依赖管理

pom文件:

 生产者服务创建及注册

创建服务提供者,在父工程中创建子工程,并且添加项目依赖,

创建修改配置文件application.yml,实现服务注册

server:
     port: 8081
spring:
    application:
        name: sca-provider  #服务名,后续会在注册中心呈现这个名字   
    cloud:
        nacos:
            server-addr: localhost:8848

 创建启动类,并定义处理请求的控制层对象和方法,然后启动,检验服务注册是否成功

打开浏览器,输入http://localhost:8081/provider/echo/msa,然后进行访问

package com.cy;

@SpringBootApplication
public class ScaProviderApplication {

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

@Value("${server.port}")
private String server;

    @RestController
    public class ProviderController {
        @GetMapping(value = "/provider/echo/{msg}")
        public String doEcho(@PathVariable String msg) {
            return server+"say:Hello Nacos Discovery " + msg;
        }
    }

}
消费者服务创建及调用

创建服务消费者继承父工程,并添加项目依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
</dependencies>


修改配置文件application.yml

server:
  port: 8090
spring:
  application:
    name: sca-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #从哪里去查找服务

创建启动类并实现服务消费

package com.cy;
@SpringBootApplication
public class ScaConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScaConsumerApplication.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    @RestController
    public class ConsumerController{

        @Value("${spring.application.name}")
        private String appName;
        @Autowired
        private RestTemplate restTemplate;
        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho01(){
            String url = "http://localhost:8081/provider/echo/"+appName;
            System.out.println("request url:"+url);
           return restTemplate.getForObject(url, String.class);
        }
    }
}
小节面试分析:

为什么要将服务注册到nacos?(为了更好的查找这些服务)
在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
服务启动时如何找到服务启动注册配置类?(NacosNamingService)
服务消费方是如何调用服务提供方的服务的?(RestTemplate)

服务负载均衡设计及实现

入门案例

一个服务实例可以处理请求是有限的,假如服务实例的并发访问比较大,我们会启动多个服务实例,让这些服务实例采用一定策略均衡(轮询,权重,随机,hash等)的处理并发请求

第一步:修改ConsumerController类,注入LoadBalancerClient对象,
并添加doRestLoadBalancerClientEcho方法,然后进行服务访问.


  @Autowired
  private LoadBalancerClient loadBalancerClient;
   
  @GetMapping("/consumer/doRestEcho02")
 public String doRestEcho02(){
     ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
     String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
     System.out.println("request url:"+url);
     return restTemplate.getForObject(url, String.class);
     }
 }
 

打开IDEA服务启动配置,修改并发运行选项

 修改服务提供者配置文件,分别以8081,8082端口方式启动,同时在Nacos上检测服务是否注册成功

启动服务消费者项目模块,打开浏览器,输入如下网址进行反复服务访问:

http://localhost:8090/consumer/doRestEcho02


这里多个实例并发提供服务的方式为负载均衡,这里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。
 

@loadBalanced

当使用RestTemplate进行远程服务调用时,假如需要负载均衡,可以在RestTemplate对象构建时,使用@LoadBalanced对构建RestTemplate的方法进行修饰,例如在ScaConsumerApplication中构建RestTemplate对象:

@Bean
@LoadBalanced
public RestTemplate loadBalancedRestTemplate(){
    return new RestTemplate();
}
在需要RestTemplate实现负载均衡调用的地方进行依赖注入.例如在ConsumerController类中添加loadBalancedRestTemplate属性

@Autowired
private RestTemplate loadBalancedRestTemplate;

在对应的服务端调用方的方法内,基于RestTemplate借助服务名进行服务调用

@GetMapping("/consumer/doRestEcho3")
public String doRestEcho03(){
    String url=String.format("http://%s/provider/echo/%s",
"sca-provider",appName);
    //向服务提供方发起http请求,获取响应数据
    return loadBalancedRestTemplate.getForObject(
            url,//要请求的服务的地址
            String.class);//String.class为请求服务的响应结果类型
}
RestTemplate在发送请求的时候会被LoadBalancerInterceptor拦截,它的作用就是用于RestTemplate的负载均衡,LoadBalancerInterceptor将负载均衡的核心逻辑交给了loadBalancer,核心代码如下所示(了解):

public ClientHttpResponse intercept(final HttpRequest request, 
    final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
    final URI originalUri = request.getURI();
    String serviceName = originalUri.getHost();
    return this.loadBalancer.execute(serviceName, 
    requestFactory.createRequest(request, body, execution));
}
@LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器

基于Feign的远程服务调用

Feign 是一种声明式Web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。如图所示:

 在服务消费方,添加项目依赖,在启动类上添加@EnableFeignClients注解

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

@EnableFeignClients
@SpringBootApplication
public class ScaConsumerApplication {…}

定义Http请求API,基于此API借助OpenFeign访问远端服务

 其中,@FeignClient描述的接口底层会为其创建实现类。

创建FeignConsumerController中并添加feign访问

Feign配置进阶实践

一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务
启动就会失败,例如假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识即可

 当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如:
第一步:定义FallbackFactory接口的实现

第二步:在feign访问接口中应用FallbackFactory对象,

 

 在配置文件application.yml中添加配置,启动feigin方式调用时的服务中断处理机制

总结:

 Feign 调用过程分析(了解)
Feign应用过程分析(底层逻辑了解):
1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
2) Feign Starter 在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
3) 接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request对象,基于此对象进行远程过程调用。
4) 请求对象经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
5) 通过 Client 携带 Request 调用远端服务返回请求响应。
6) 通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据。

何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
微服务架构下项目的构建过程?(聚合工程)
 

FAQ分析


Nacos是什么,提供了什么特性(服务的注册、发现、配置)?
你为什么会选择Nacos?(活跃度、稳定、性能、学习成本)
Nacos的官网?(nacos.io)
Nacos在github的源码?(github.com/alibaba/nacos)
Nacos在windows环境下安装?(解压即可使用)
Nacos在windows中的的初步配置?(application.properties访问数据库的数据源)
Nacos服务注册的基本过程?(服务启动时发送web请求)
Nacos服务消费的基本过程?(服务启动时获取服务实例,然后调用服务)
Nacos服务负载均衡逻辑及设计实现?(Ribbon)
注册中心的核心数据是什么?(服务的名字和它对应的网络地址)
注册中心中心核心数据的存取为什么会采用读写锁?(底层安全和性能)
Nacos健康检查的方式?(基于心跳包机制进行实现)
Nacos是如何保证高可用的?(重试,本地缓存、集群)
Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)
 


版权声明:本文为weixin_57801340原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。