SpringCloud:nacos配置中心+nacos服务发现个人总结

文章目录

  • nacos配置中心(cloud-alibaba)
  • nacos服务发现
    • 负载均衡,引入 服务发现的目的
    • 没有nacos服务注册中心时,微服务调用
    • nacos服务注册的实现
    • 有了nacos服务注册中心时,利用feign(ribbon)进行微服务调用

前言:基于黑马程序员B站视频
对应笔记+源码0积分下载
核心内容: Springcloud(alibaba),nacos配置中心,nacos服务发现,负载均衡,zuul网关
最终实现效果:
配置中心:
SpringCloud:nacos配置中心+nacos服务发现个人总结_第1张图片
服务发现:
SpringCloud:nacos配置中心+nacos服务发现个人总结_第2张图片


nacos配置中心(cloud-alibaba)

SpringCloud:nacos配置中心+nacos服务发现个人总结_第3张图片

配置管理的必要性:

同一份程序在不同的环境(开发,测试,生产)、不同的集群(如不同的数据中心)经常需要有不同的

配置,所以需要有完善的环境、集群配置管理

在微服务架构中,当系统从一个单体应用,被拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移

(分割),这样配置就分散了,不仅如此,分散中还包含着冗余,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lp7d1a0R-1656345257365)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627173947910.png)

配置中心的服务流程如下:

1、用户在配置中心更新配置信息。

2、服务A和服务B及时得到配置更新通知,从配置中心获取配置。

总得来说,配置中心就是一种统一管理各种应用配置的基础服务组件。

在系统架构中,配置中心是整个微服务基础架构体系中的一个组件,如下图,它的功能看上去并不起眼,无非就是

配置的管理和存取,但它是整个微服务架构中不可或缺的一环

总而言之,在传统巨型单体应用纷纷转向细粒度微服务架构的历史进程中,配置中心是微服务化不可缺少的一个系

统组件,在这种背景下中心化的配置服务即配置中心应运而生

通过配置中心,我们实现了:

  • 合格的配置中心需要满足如下特性:
  • 配置项容易读取和修改
  • 分布式环境下应用配置的可管理性,即提供远程管理配置的能力
  • 支持对配置的修改的检视以把控风险
  • 可以查看配置修改的历史记录
  • 不同部署环境下应用配置的隔离性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4f1Y4G9C-1656345257366)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627173914565.png)

问:nacos配置中心的配置是动态的,我们的微服务已经跑起来后,是如何派上用场的?懂了,只是集中管理,但是需要:重新跑!

示例服务中,配置只是进行打印,如何 将配置派上用场?

一般来说,spring boot的配置将在application.yml(也可以是application.properties)文件中编写,

由于使用外部 配置中心,必须将原先的application.yml重命名为bootstrap.yml,bootstrap.yml如下所示:

spring.cloud.nacos.confifig.server-addr 指定了Nacos Server的网络地址和端口号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMr6Bfog-1656345257367)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627174121228.png)

如此,外部(nacos)配置中心派上了用场

通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件

结论:实现简单,后期可以整,暂时没必要!!!


nacos服务发现

笔记摘自:黑马程序员 nacos-服务发现.pdf

负载均衡,引入 服务发现的目的

先导: Spring Cloud服务协作流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4rTyo5f-1656345257368)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627183219988.png)

(1)在微服务启动时,会向服务发现中心上报自身实例信息,这里ServiceB 包含多个实例。

每个实例包括:

IP地址、端口号信息。

北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090(2)微服务会定期从Nacos Server(服务发现中心)获取服务实例列表。

(3)当ServiceA调用ServiceB时,ribbon组件从本地服务实例列表中查找ServiceB的实例,如获取了多个实例如

Instance1、Instance2。这时ribbon会通过用户所配置的负载均衡策略从中选择一个实例。

(4)最终,Feign组件会通过ribbon选取的实例发送http请求。

采用Feign+Ribbon的整合方式,是由Feign完成远程调用的整个流程。而Feign集成了Ribbon,Feign使用Ribbon

完成调用实例的负载均衡。

考察核心:光凭zuul网关配置,能否实现负载均衡?(而非在 service微服务互相调用过程中,通过feign实现!)

(负载均衡的两个环节:1.通过feign(调用ribbon组件)微服务直接互相调用(客户端负载均衡,微服务是nacos客户端 nacos server是服务端) 2.通过zuul 网关配置,端口转发(服务端负载均衡,通过nginx实现的一样是服务端负载均衡;zuul和nginx往往是一起使用的!) )

ribbon根据负载均衡策略负责选择示例,feign会通过ribbon来选择实例进而发送请求(feign集成来ribbon)

(本文档,似乎一直在集中阐述 客户端负载均衡!)


没有nacos服务注册中心时,微服务调用

在微服务架构中,如果没有nacos服务注册中心,如何进行微服务之间互相调用(通信)?

Service B暴露接口供Service A调用:

@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去调用Service B

@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; 
} 
}

RestTemplate工具类,spring提供的一个HTTP请求工具

在服务的调用过程中,使用到了一个工具,叫做 RestTemplate,RestTemplate 是由 Spring 提供的一个 HTTP 请求工具。在上文的案例中,开发者也可以不使用 RestTemplate ,使用 Java 自带的 HttpUrlConnection 或者经典的网络访问框架 HttpClient 也可以完成上文的案例,只是在 Spring 项目中,使用 RestTemplate 显然更方便一些。在传统的项目架构中,因为不涉及到服务之间的调用,大家对 RestTemplate 的使用可能比较少

总结:

关键: application.yml中配置provider.address属性,拼凑出地址后,使用restTemplate.getForObject方法进行调用!

但是,微服务可能是部署在云环境的,服务实例的网络位置或许是动态分配的。另外,每一个服务一般会有多个实

例来做负载均衡,由于宕机或升级,服务实例网络地址会经常动态改变。再者,每一个服务也可能应对临时访问压

力增加新的服务节点。正如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pK72PVE8-1656345257369)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627192149824.png)


nacos服务注册的实现

(服务发现(让服务之间互相感知)与管理问题)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9PJda5TR-1656345257369)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627192235974.png)

(1)在每个服务启动时会向服务发现中心上报自己的网络位置。这样,在服务发现中心内部会形成一个服务注册

服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。

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

(3)当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地

址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。

总结一下,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无

法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感

。各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发

现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。

服务注册的实现极其简单:

(下面这个例子是从 海马程序员-服务发现中,摘出来的部分代码,像@EnableFeignClients如果仅为实现服务注册而不实现feign调用其他微服务,那它是多余的)

(为了更深刻理解,看源文档 nacos-服务发现.pdf (文档视频中有,我的博客中也有) or 黑马nacos-服务发现 视频)

  1. application.yml配置

    server: 
    	port: 56020 #启动端口 命令行注入 
    	
    spring: 
    	application: 
    		name: quickstart‐consumer 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848
    

    2.Provider(生产者)远程代理定义

@SpringBootApplication 
@EnableDiscoveryClient 
@EnableFeignClients #开启FeignClient,如果只是实现服务注册,不使用feign调用其他微服务的话,就没必要了
public class NacosConsumerApp { 
    public static void main(String[] args) { 
        SpringApplication.run(NacosConsumerApp.class, args); 
    } 
}

Note: @EnableDiscoveryClient 在spring cloud项目中表明此项目是一个注册发现客户端,这里注册服务发

现使用的是Nacos

Note: @EnableFeignClients 开启FeignClient

可以说,实现服务注册,只需要: @EnableDiscoveryClient 就行!!!


有了nacos服务注册中心时,利用feign(ribbon)进行微服务调用

spring(boot)使用feign需在pom.xml中加入依赖:

<dependency> 
	<groupId>org.springframework.cloudgroupId> 
	<artifactId>spring‐cloud‐starter‐openfeignartifactId> 
dependency>

参考前面 没有nacos服务注册中心时,微服务调用 的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"; } }

Service A中,通过Feign调用Service B方式如下:

(1)声明Feign客户端

@FeignClient(value = "serviceB") 
public interface ServiceBAgent { 

    /** 
    * 根据用户名查询账号信息 
    * @param username 用户名 
    * @return 账号信息 
    */ 
//Feign英文表意为“假装,伪装,变形”,此处正是将HTTP报文请求方式 伪装为简单的java接口(内部,未通过TTTP)调用方式
@GetMapping(value = "/service") 
public String service(); }

Feign是Netflflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。Feign

的英文表意为“假装,伪装,变形”, 可以理解为将HTTP报文请求方式伪装为简单的java接口调用方式。

(2)业务调用

@Autowired 
private ServiceBAgent serviceBAgent.; 
//....略 
serviceBAgent.service();
//....略
  • 在 声明Feign客户端 之后,Feign会根据**@FeignClient注解使用java的动态代理技术生成代理类**,在这里我们

指定@FeignClient value为serviceB,则说明这个类的远程目标为spring cloud的服务名称为serviceB的微服

务。

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

    衡策略选取实例。 (Feign默认集成了Ribbon,可以直接使用)

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

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

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

  • Feign兼容spring的web注解(如:@GetMapping),它会分析声明Feign客户端方法中的Spring注解,得出

    Http请求method、参数信息以及返回信息结构。

  • 当业务调用Feign客户端方法时,会调用代理类,根据以上分析结果,由代理类完成实际的参数封装、远程

    http请求,返回结果封装等操作。


  • 综合架构演示:

由于Feign是基于Http Restful的调用,在高并发下的性能不够理想,我们将RPC方案从feign切换为Dubbo, 将Spring Cloud与阿里系的若干组件完美集成()

系统架构图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5hEqqxd-1656345257370)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627201408150.png)

  • service-api的作用:

    优劣:

    取舍:

  • Service2配置(纯生产者):

    package com.itheima.microservice.service2.service; 
    @org.apache.dubbo.config.annotation.Service 
    public class ProviderServiceImpl implements ProviderService { 
       @Override 
       public String service() { 
           return "Provider invoke"; 
       } 
    }
    

    其中, @org.apache.dubbo.config.annotation.Service 是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现

    为 Dubbo 服务。 因此,下一步需要将其配置 Dubbo 服务(远程)。

    配置 Dubbo 服务

    在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包

    Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注 @DubboComponentScan 来实现基准包扫描。

    同时,Dubbo 远程服务需要暴露网络端口,并设定通讯协议,完整的 YAML 配置如下所示:

    server: port: ${port:56040} #启动端口 命令行注入 
    spring: application: 
    	name: service2 
    	main: 
    		allow‐bean‐definition‐overriding: true # Spring Boot 2.1 需要设定 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 
    				cluster‐name: DEFAULT 
    			config: server‐addr: 127.0.0.1:8848 # 配置中心地址 
    				file‐extension: yaml 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 # 开发环境 
    				group: NACOS_MICROSERVICE_GROUP # xx业务组 
    				dubbo: 
    					scan: # dubbo 服务扫描基准包 
    					base‐packages: com.itheima.microservice protocol: # dubbo 协议 
    					name: dubbo # dubbo 协议端口( ‐1 表示自增端口,从 20880 开始) 
    					port: ${dubbo_port:20891} 
    			registry: 
    				address: nacos://127.0.0.1:8848 
    			application: 
    				qos‐enable: false 
    			consumer: 
    				check: false
    

    核心:

    标注 @DubboComponentScan 来实现基准包扫描;Dubbo 远程服务需要暴露网络端口

    • dubbo.scan.base-packages : 指定 Dubbo 服务实现类的扫描基准包,将@org.apache.dubbo.confifig.annotation.Service注解标注的service暴露为dubbo服务

    • dubbo.protocol : Dubbo 服务暴露的协议配置,其中子属性 name 为协议名称, port 为dubbo协议端口 可以指定多协议,如:dubbo.protocol.rmi.port=1099

    • dubbo.registry : Dubbo 服务注册中心配置,其中子属性 address 的值 “nacos://127.0.0.1:8848”,说明dubbo服务注册到nacos ,相当于原生dubbo的xml配置中的

    启动服务提供方应用

    Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:

    @SpringBootApplication 
    @EnableDiscoveryClient 
    public class Service2Bootstrap { 
    	public static void main(String[] args) { 
            SpringApplication.run(Service2Bootstrap.class, args); 
        }
    }
    
  • Service1配置(生产者&消费者):

    实现dubbo服务

    package com.itheima.microservice.service1.service; 
    @org.apache.dubbo.config.annotation.Service  
    //能替换成 import org.apache.dubbo.config.annotation   @Service
    public class ConsumerServiceImpl implements ConsumerService { 
        @Override
        public String service() { 
            return "Consumer invoke " ; 
        } 
    }
    

    使用@org.apache.dubbo.confifig.annotation.Service标记dubbo服务

    bootstrap.yml配置文件与Service2一致

    pom.xml引入 spring-cloud-starter-dubbo依赖,它会根据接口生成代理对象

    > 
    	>com.alibaba.cloud> 
    	>spring‐cloud‐starter‐dubbo> 
    >
    

    实现Service1调用Service2

    @org.apache.dubbo.config.annotation.Service 
    public class ConsumerServiceImpl implements ConsumerService { 
        @Reference 
        ProviderService providerService; 
        public String service() { 
            return "Consumer invoke | "+providerService.service(); 
        } 
    }
    

    关键:

    使用@Reference 注入 代理对象! (引入的dubbo依赖只在此处使用,引导类处不会像feign的使用一样有@EnableFeignClients注释)

    Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别(引导类处不会像feign的使用一样有@EnableFeignClients注释)

  • Application1配置:

    实现 application1调用Service1

    @RestController 
    public class Application1Controller { 
        @org.apache.dubbo.config.annotation.Reference 
        private ConsumerService consumerService; 
        
        @GetMapping("/service") 
        public String service(){ 
            return "test" + consumerService.service(); 
        } 
    }
    

    测试: 请求:http://localhost:56020/application1/service

    consumerService正常生成代理对象,service1被调用。

  • zuul配置:

    原来的单体架构,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在

    独立的虚拟机上的 Java进程了。客户端UI如何访问?他的后台有N个服务,前台就需要记住管理N个服务,一个服

    务下线/更新/升级,前台就要重新部署,这明显不服务我们拆分的理念,特别当前台是移动应用的时候,通常业务

    变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VujOFLBE-1656345257371)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627233329623.png)

    • Zuul网关的作用:

    • 提供统一服务入口,让微服务对前台透明

    • 聚合后台的服务,节省流量,提升性能

    • 提供安全,过滤,流控等API管理功能

    Spring Cloud Zuul是整合Netflflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过

    等 功能。

    • Zuul与Nginx怎么配合使用?

    Zuul与Nginx在实际项目中需要配合使用,如下图,Nginx的作用是反向代理、负载均衡,Zuul的作用是保障微服

    务的安全访问,拦截微服务请求,校验合法性及负载均衡。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hKW870pZ-1656345257372)(SSM(含springboot)]+Maven高级+Mybatis.assets/image-20220627233539020.png)

    api-gateway配置

    server: 
    	port: 56010 #启动端口 命令行注入 
    spring: 
    	application: 
    		name: api‐gateway 
    	main: 
    		allow‐bean‐definition‐overriding: true # Spring Boot 2.1 需要设定 
    	cloud: 
    		nacos: 
    			discovery: 
    				server‐addr: 127.0.0.1:8848 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 
    				cluster‐name: DEFAULT 
    			config: 
    				server‐addr: 127.0.0.1:8848 # 配置中心地址 
    				file‐extension: yaml 
    				namespace: c67e4a97‐a698‐4d6d‐9bb1‐cfac5f5b51c4 # 开发环境 
    				group: NACOS_MICROSERVICE_GROUP # xx业务组
    

    网关的路由配置采用nacos远程配置,在nacos控制台开发环境中新增api-gateway.yaml配置集,配置组为

    TEST_GROUP,配置内容如下:

    zuul: 
    	routes: 
    		application1: 
    			stripPrefix: false 
    			path: /application1/**
    

    将请求为 /application1/ 开头的请求路由至 application1 服务,保留请求url中的 /application1/

    api-gateway启动:

    注意在启动类上使用@EnableZuulProxy注解标识此工程为Zuul网关,启动类代码如下:

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

    浏览器访问: http://127.0.0.1:56010/application1/service (相当于UI 前端 get请求)

    通过网关(api-gateway)请求Application1应用,Application1的业务实现又贯穿service1、service2

使用@org.apache.dubbo.confifig.annotation.Service标记dubbo服务


杂记:

浏览器中输入:

http://127.0.0.1:56020/service

相当于前端发送get请求,请求地址(url)为:http://127.0.0.1:56020/service,即 服务器:http://127.0.0.1 端口:56020 的service后端接口

但是,还是postman好用,能够发出post请求

你可能感兴趣的:(ssm,spring,cloud,服务发现,java)