04-Nacos服务注册中心应用实践

04-Nacos服务注册中心应用实践Nacos 注册中心简介背景分析在微服务中 首先需要面对的问题就是如何查找服务 软件即服务 如何在不同的服务之间进行通信 如何更好更方便的管理应用中的每一个服务 如何建立各个服务之间联系的纽带 由此注册中心诞生 例如淘宝网卖家提供服务 买家调用服务 市面上常用注册中心有 Zookeeper 雅虎 Apache Eureka Netfix Nacos Alibaba Consul Google 那他们分别都有什么特点 我们如何进行选型呢 从社区活跃度上分析 Consul 和新晋的 Nacos 的社区

注册中心简介

背景分析

Nacos概述

Nacos(DynamicNaming and Configuration Service)是一个应用于服务注册与发现、配置管理的平台。它孵化于阿里巴巴,成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。其官网地址如下:

https://nacos.io/zh-cn/docs/quick-start.html

构建Nacos服务

准备工作

下载与安装

第一步:Nacos下载,可在浏览器直接输入如下地址:

https://github.com/alibaba/nacos/releases

第三步:解压Nacos(最好不要解压到中文目录下),其目录结构如下:

在这里插入图片描述

初始化配置

source d:/nacos-mysql.sql 

执行成功以后,会创建一个nacos_config数据库,打开数据库会看到一些表,例如;

在这里插入图片描述

第二步:打开/nacos/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有”#”要将其去掉):

 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_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC db.user.0=root db.password.0=root 

服务启动与访问

第一步:启动Nacos服务(nacos的bin目录去通过指令启动)。

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

./startup.sh -m standalone 

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

startup.cmd -m standalone 

第二步:访问Nacos服务。

其中,默认账号密码为nacos/nacos.

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

业务描述

生产者服务创建及注册

第一步:创建服务提供者工程(module名为sca-provider,假如已有则无需创建),继承parent工程(01-sca),其pom.xml文件内容如下:

 
    <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>01-sca 
     artifactId> <groupId>com.jt 
      groupId> <version>1.0-SNAPSHOT 
       version>  
        parent> <modelVersion>4.0.0 
         modelVersion> <artifactId>sca-provider 
          artifactId> <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>  
                  project> 

第二步:创建并修改配置文件application.yml(或者application.properties),实现服务注册,关键代码如下:

server: port: 8081 spring: application: name: sca-provider #进行服务注册必须配置服务名 cloud: nacos: discovery: server-addr: localhost:8848 
package com.jt; @SpringBootApplication public class ProviderApplication { 
    public static void main(String[] args) { 
    SpringApplication.run(ProviderApplication.class, args); } } 

第四步:启动启动类,然后刷先nacos服务,检测是否服务注册成功,如图所示:

在这里插入图片描述

第五步:停掉sca-provider服务,然后不断刷新nacos服务列表,检查服务的健康状态。

消费者服务发现及调用

第一步: 在sca-provider项目中创建服务提供方对象,基于此对象对外提供服务,例如:

 package com.jt.provider.controller; /定义Controller对象(这个对象在spring mvc中给他的定义是handler), * 基于此对象处理客户端的请求*/ @RestController public class ProviderController{ 
    //@Value默认读取项目配置文件中配置的内容 //8080为没有读到server.port的值时,给定的默认值 @Value("${server.port:8080}") private String server; //http://localhost:8081/provider/echo/tedu @GetMapping("/provider/echo/{msg}") public String doRestEcho1(@PathVariable String msg){ 
    return server+" say hello "+msg; } } 

第二步:创建服务消费者工程(module名为sca-consumer,假如已有则无需创建),继承parent工程(01-sca),其pom.xml文件内容如下:

 
    <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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>01-sca 
     artifactId> <groupId>com.jt 
      groupId> <version>1.0-SNAPSHOT 
       version>  
        parent> <modelVersion>4.0.0 
         modelVersion> <artifactId>sca-consumer 
          artifactId> <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>  
                  project> 

第三步:创建sca-consumer服务中的配置文件application.yml,关键代码如下:

server: port: 8090 spring: application: name: sca-consumer #服务注册时,服务名必须配置 cloud: nacos: discovery: server-addr: localhost:8848 #从哪里去查找服务 

第四步:创建消费端启动类并实现服务消费,关键代码如下:

package com.jt; @SpringBootApplication public class ConsumerApplication { 
    public static void main(String[] args) { 
    SpringApplication.run(ConsumerApplication.class,args); } } 

第五步:在sca-consumer启动类中添加如下方法,用于创建RestTemplate对象.

@Bean public RestTemplate restTemplate(){ 
   //基于此对象实现远端服务调用 return new RestTemplate(); } 

第六步:定义sca-consumer服务的消费端Controller,在此对象方法内部实现远端服务调用

package com.jt.consumer.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; / * 定义服务消费端Controller,在这个Controller对象 * 的方法中实现对远端服务sca-provider的调用 */ @RestController public class ConsumerController { 
    / * 从spring容器获取一个RestTemplate对象, * 基于此对象实现远端服务调用 */ @Autowired private RestTemplate restTemplate; / * 在此方法中通过一个RestTemplate对象调用远端sca-provider中的服务 * @return * 访问此方法的url: http://localhost:8090/consumer/doRestEcho1 */ @GetMapping("/consumer/doRestEcho1") public String doRestEcho01(){ 
    //1.定义要调用的远端服务的url String url="http://localhost:8081/provider/echo/8090"; //2.基于restTemplate对象中的相关方法进行服务调用 return restTemplate.getForObject(url, String.class); } } 

第七步:启动消费者服务,并在浏览器输入http://localhost:8090/consumer/doRestEcho1地址进行访问测试。

小节面试分析

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

服务负载均衡设计及实现(重点)

业务描述

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

LoadBalancerClient应用

LoadBalancerClient对象可以从nacos中基于服务名获取服务实例,然后在工程中基于特点算法实现负载均衡方式的调用,案例实现如下:

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

 @Autowired private LoadBalancerClient loadBalancerClient; @Value("${spring.application.name:8090}") private String appName; @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 allow parallel run),如图所示:

在这里插入图片描述

第四步:修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。

server: port: 8082 spring: application: name: sca-provider cloud: nacos: server-addr: localhost:8848 

在这里插入图片描述

在这里插入图片描述

第六步:启动sca-consumer项目模块,打开浏览器对consumer服务进行访问,访问时不断刷新,检测页面数据变化。

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

@LoadBalanced

当使用RestTemplate进行远程服务调用时,假如需要负载均衡,还可以在RestTemplate对象构建时,使用@LoadBalanced对构建RestTemplate的方法进行修饰,例如在ConsumerApplication中构建名字为loadBalancedRestTemplate的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的拦截器。

Ribbon负载均衡策略(了解)

小节面试分析

  • @Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
  • @Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
  • Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)
  • Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
  • Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
  • Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
  • @LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
  • 我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)

基于Feign的远程服务调用(重点)

背景分析

服务消费方基于rest方式请求服务提供方的服务时,一种直接的方式就是自己拼接url,拼接参数然后实现服务调用,但每次服务调用都需要这样拼接,代码量复杂且不易维护,此时Feign诞生。

Feign是什么

Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由一些社区进行维护,更名为 OpenFeign。

Feign应用实践(掌握)

第一步:在服务消费方,添加项目依赖(SpringCloud团队基于OpenFeign研发了starter),代码如下:

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

第二步:在启动类上添加@EnableFeignClients注解,代码如下:

@EnableFeignClients @SpringBootApplication public class ConsumerApplication { 
   } 

第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:

package com.jt.consumer.service; @FeignClient(name="sca-provider")//sca-provider为服务提供者名称 public interface RemoteProviderService{ 
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务 public String echoMessage(@PathVariable("string") String string); } 

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

第四步:创建FeignConsumerController中并添加feign访问,代码如下:

package com.jt.consumer.controller; @RestController @RequestMapping("/consumer/ ") public class FeignConsumerController { 
    @Autowired private RemoteProviderService remoteProviderService; /基于feign方式的服务调用*/ @GetMapping("/echo/{msg}") public String doFeignEcho(@PathVariable String msg){ 
    //基于feign方式进行远端服务调用(前提是服务必须存在) return remoteProviderService.echoMessage(msg); } } 

第五步:启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示(反复刷新检测其响应结果):

在这里插入图片描述
说明,feign方式的远程服务调用,底层会自动基于ribbon组件实现负载均衡。

Feign配置进阶实践

 @FeignClient(name="sca-provider") public interface RemoteOtherService { 
    @GetMapping("/doSomeThing") public String doSomeThing(); } 

其启动异常如下:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled. 

此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识(这个标识是Bean对象的名字)即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称 interface RemoteProviderService{ 
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务 public String echoMessage(@PathVariable("string") String string); } 

还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如,在Feign应用中通过FallbackFactory接口的实现类进行默认的相关处理,例如:

第一步:定义FallbackFactory接口的实现,代码如下:

package com.jt.service.factory; / * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题 */ @Component public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> { 
    / * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行. * @param throwable 用于接收异常 */ @Override public RemoteProviderService create(Throwable throwable) { 
    return (msg)->{ 
    return "服务维护中,稍等片刻再访问"; }; } } 

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

@FeignClient(name = "sca-provider", contextId = "remoteProviderService", fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名 public interface RemoteProviderService { 
    @GetMapping("/provider/echo/{msg}") public String echoMsg(@PathVariable String msg); } 

第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.

feign: hystrix: enabled: true #默认值为false 

第四步:在服务提供方对应的调用方法中添加Thread.sleep(5000)模拟耗时操作,然后启动服务进行访问测试.

Feign 调用过程分析(了解)

小节面试分析

  • 为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
  • @FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
  • Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
  • @EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)

总结(Summary)

重难点分析

  • 何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
  • 注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
  • 市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
  • Nacos安装、启动、服务的注册、发现机制以及实现过程
  • 服务调用时RestTemplate对象的应用。
  • 基于Feign方式的服务调用及基本原理?

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是如何保证高可用的?(重试,本地缓存、集群)
  • RestTemplate的基本作用是什么?
  • Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
  • Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)

Bug分析

  • 404
  • 400
  • 405
  • 500
  • ………
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206482.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午3:36
下一篇 2026年3月19日 下午3:36


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号