文章目录
注册中心简介
背景分析
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
