SpringCloud 总结

Posted 北执南念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud 总结相关的知识,希望对你有一定的参考价值。

一、微服务:

微服务架构风格,是一种将一个单体应用程序开发为一组小型服务的方法(就是把大任务拆成小任务)。每个服务运行在自己的进程中,服务间通信采用轻量级的通信机制(通常用HTTP资源API),这些服务围绕业务能力构建。并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。

二、分布式:

分布式服务是分散部署在不同的机器上,一个服务可能负责几个功能,是一种面向Soa的架构的,服务之间也是通过RPC来交互或者是web service来交互的逻辑架构设计完后就做物
-------------SOA架构是一种面向服务的架构,基于分布式架构,它将不同的业务功能按照服务进行拆分,并通过这些服务之间定义了良好接口和协议联系起来。----
理架构设计,系统应用部署在超过一台服务器或者虚拟机上,且各个分开部署,彼此通过各种通讯协议交互信息就可算作分布式部署。生产环境下,微服务肯定是分布式部署的,分布式部署的应用不一定是微服务架构的。比如集群部署,他是把相同的应用复制到不同的服务器上,但是逻辑功能还是单体应用。

两者区别:微服务是架构设计方式,分布式是系统部署方式。

三、微服务架构:

在做架构的时候,先做逻辑架构,在做物理架构。刚拿到需求后估算过最大用户量和并发量,计算单个应用服务器。能否满足需求,如果用户量只有几百人的小应用,单体应用就能够搞定,即 所有应用部署在一个应用服务器里面;如果是很大的用户量,且某些功能会被频繁访问,或者某些功能计算量很大,建议将应用拆解为多个子系统,各自负责各自功能,而这就是微服务架构。

四、SpringCloud:

-- SpringCloud是分布式微服架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家痛或者组件集合。
-- SingBoot 和 SpringCloud之间的关系:
		1.SingBoot: 专注于快速方便的开发单个个体微服务。
		2.SpringCloud: 是关注全局的微服务协调整理,治理框架,他将SingBoot开发的一个个单体服务整合在一起,并管理起来。为各个单体服务之间提供配置管理,服务发           现,断路由,微代理,事件总线,全局锁,决策迭代,分布式会话等集成服务。

1. SingBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SingBoot属于依赖关系。
2. SingBoot专注于快速、方便的开发单个服务个体,而SpringCloud关注于全局的服务治理框架。

五、SpringCloud的组件:

一、注册中心组件:

   微服务应用和机器越来越多,调用方需要知道接口的网络地址。如果靠配置文件的方式去控制网络地址,对于动态新增机器的url地址的维护会带来很大的问题,而注册中心就是为了解决这个问题,它提供了: --服务注册--发现功能,对于服务的url地址进行统一管理以及对整个系统微服务进行健康状态检查。--url地址:IP地址与端口号
  
  (1).对于服务提供者(provider)的作用:启动时向注册中心上报自己的网络信息。
  (2).对于服务消费者(consumer)的作用,启动时向注册中心上报自己的网络信息,并拉取provider相关网络信息。

所以注册中心的作用就是对微服务的URL进行统一管理;

注册中心分类:

1.Eukeka(1.0开源,之后闭源 netflix)
2.consul (Spring)
3.nacos (阿里)
4.zookeepet

(1)Eureka注册中心:

SpringCloud Euraka是SpringCloud集合中一个组件,它是对Euraka的集成,用于服务注册和发现。Eureka是Netflix中的一个开源框架。它和 zookeeper、Consul一样,都是用于服务注册管理的.

Eukeka客户端(Spring微服务)向Eukeka注册中心(服务端)注册自己的信息
1.使用步骤:

(1)搭建服务注册中心服务端(eureka-server):

01.创建SpringBoot项目,引入Eureka Server(服务端)依赖;

<!--引入 eureka server-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>


02.启动类上贴上 @EnableEurekaServer 注解;

03.配置application.properties文件,添加相关配置信息:

04.运行测试,打开浏览器输入http://localhost:1010

server.port=1010			#执行服务端口
spring.application.name=eurekaserver 				#指定服务名称 唯一标识
eureka.client.service-url.defaultZone=http://localhost:1010/eureka/   #指定服务注册中心的地址

如果此时启动管理界面会显示项目启动控制台报错:

 - 出现上述问题原因:eureka组件包含 eurekaserver 和 eurekaclient。server是一个服务注册中心,用来接受客户端的注册。client的特性会让当前启动的服务把自己作为eureka的客户端进行服务中心的注册,当项目启动时服务注册中心还没有创建好,所以找我不到服务的客户端组件就直接报错了,当启动成功服务注册中心创建好了,日后client也能进行注册,就不再报错啦!

解决办法:

-关闭Eureka自己注册自己:

server.port=1010
spring.application.name=eurekaserver
eureka.client.service-url.defaultZone=http://localhost:1010/eureka
eureka.client.register-with-eureka=false    #不再将自己同时作为客户端进行注册  
eureka.client.fetch-registry=false				  #关闭作为客户端时从eureka server获取服务信息

(2)搭建(eureka-client)客户端:

1.创建项目并引入eureka client依赖:

<!--引入eureka client-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

 2.编写配置application.properties:
server.port=8080			#服务端口号
spring.application.name=eurekaclient8080			#服务名称唯一标识
eureka.client.service-url.defaultZone=http://localhost:1010/eureka     #eureka注册中心地址
 3.启动类上贴上 @EnableEurekaClient 注解;
 4.启动之前的1010的服务 注册中心之后,再启动eureka客户端8888服务
 5.查看eureka server的服务注册情况

2.SpringCloud Eureka 自我保护机制
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果服务刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败,对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。
我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,这个时候就会触发 Eureka 的保护机制,一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐)
自我保护机制(Self Preservation Mode)
1.自我保护机制默认是开启的
现象:在自我保护模式下,eureka服务器将停止逐出所有实例,
机制: 这样做是为了确保灾难性的网络事件不会清除eurea注册表数据,并将其传播到下游的所有客户端用户服务

触发自我保护机制,什么时候将客户端从服务注册中中清除:
	1.心跳的次数高于预期阅值
	2.自我保护被禁用

2.eureka server关闭自我保护机制:
eureka.server.enable-self-preservation=false #关闭白我保护
eureka.server.eviction-interval-timer-in-ms-3000 #超时3s自动清除 60*1000 1分钟.

3.微服务修改减短服务心跳的时间:
eureka.instance.lease-expiration-duration-in-seconds=10 #用来修改eureka server默认接受心跳的最大时间 默认是90s
eureka.instance.lease-renewal-interval-in-seconds=5     #指定客户端多久向eureka server发送一次心跳 默认是30s

4.尽管如此关闭自我保护机制还是会出现警告
- THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
- `官方并不建议在生产情况下关闭

3.Eureka 客户端与服务器之间的通信
1. Register(注册)
     Eureka客户端将关于运行实例的信息注册到Eureka服务器。注册发生在第一次心跳;

2. Renew(更新 / 续借)
    Eureka客户端需要更新最新注册信息(续借),通过每30秒发送一次心跳。更新通知是为了告诉Eureka服务器实例仍然存活。如果服务器在90秒内没有看到更新,它会将实例从注册表中删除。建议不要更改更新间隔,因为服务器使用该信息来确定客户机与服务器之间的通信是否存在广泛传播的问题;
 
3.Fetch Registry(抓取注册信息)
    Eureka客户端从服务器获取注册表信息并在本地缓存。之后,客户端使用这些信息来查找其他服务。通过在上一个获取周期和当前获取周期之间获取增量更新,这些信息会定期更新(30秒更新一次)。获取的时候可能返回相同的实例。Eureka客户端自动处理重复信息。
    
4.Cancel(取消)
   Eureka客户端在关机时向Eureka服务器发送一个取消请求。这将从服务器的实例注册表中删除实例,从而有效地将实例从流量中取出。
4.搭建eureka server 集群:
完全集群:
a.创建3个springboot项目;
b.引入eureka server依赖;
c.配置文件application.properties;
nodel:  server.port-8761
        http://localhost:8762/eureka,http://localhost:8763/eureka

node2:  server.port=8762
        http://localhost:8761/eureka,http://localhost:8763/eurek

node3:  server.port=8763
        http://localhost:8761/eureka,http://localhost:8762/eureka

d.在每个项目启动类上加入 @EnableEurekaServer 注解

(2) Consul服务注册中心:

-- 它本身是一个软件,不相eurka 那样服务端与客户端都用代码定义,而是作为客户端的一方用代码定义,而服务端的一方用软件启动,所以他的server端用软件启动就行;

consul 服务注册中心:
简介: consul 基于go语言进行开发服务注册中心 轻量级服务注册中心 google
作用: 管理微服务中所有服务注册 发现 管理服务元数据信息存储(服务名 地址列表)心跳健康检查
  1. consul 服务端(注册中心)安装与使用:
a.下载consul:
    https://www.consul.io/downloads

b.启动服务注册中心在consul安装目录中打开cmd黑窗口:
consul agent -dev ---代表以开发者模式启动(用它就行)
consul agent -server ---以服务器模式启动,但是必须构建集群

c.访问consul 管理界面
  http:端默认8500
  浏览器: localhost:8500

d.管理界面基本介绍:
     dcl: 数据中心名称 datacenter 默认为:dcl 指定数据中心启动 consul agent -dey -datacenter=aa
services: 当前consul服务中注册服务列表 默认:client server同时启动自己注册自己 会出现一个consul服务
   nodes:用来查看consul的集群节点

  1. consul client 客户端即微服务项目搭建
1.创建项目并引入consul客户端依赖:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
2.编写配置文件 properties配置
(1)server.port=8889
(2)spring.application.name=consulclient8889 #指定服务名称

---指定consul server服务配置:
(3)spring.cloud.consul.host=localhost		#注册consul服务的主机
(4)spring.cloud.consul.port=8500			#注册consul服务的端口号
(5)spring.cloud.consul.discovery.register-health-check=false	    #关闭consu了服务的健康检查[不推荐]

#执行注册当前服务的服务名称默认为$spring.application.name 如果不写以上面第二步为主,写了就已把上面覆盖了,以自己为主。
(6)spring.cloud.consul.discovery.service-name=$spring.application.name   #指定注册的服务名称 默认就是应用名

3.在启动类上加上注解 @EnableDiscoveryclient
表示这是一个consumerclient客户端,他是一个通用注解。除了Eurekaclient不能用。Consumeclient、nacosclient、zookeepetclient 都可以用。哪种client取决于引入的依赖;

4.注意要引入健康检查的依赖,否则会出现当前服务不可用的情况的错误:
  原因:consulserver检测所有客户端心跳但是发送心跳时,consulclient必须给予响应才能让该服务正常使用,在现有的客户端中没有引入健康检查的依赖,所以导致健康检查始终不同通过,导致服务不能使用。
  
  解决办法:
   1. 可以关闭健康检查,不建议在生产的情况下关闭是友好的机制。
   
--      spring.cloud.consul.discovery.register-health-check=false	    	#关闭consu了服务的健康检查[不推荐]
   
   2.引入健康检查依赖
   	<!-- 这个包是用做健康度监控的-->
 	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>

   注意,新的console服务注册中心是没有自我保护机制的。
   

5.启动服务查看consul界面服务信息

二、服务间通信:

1、如何解决微服务的服务间通信问题?

a、HTTP Rost 方式:  使用http协议进行数据传递JSon  springcloud 使用Http协议传递数据

b、RPC 方式: 远程过程调用 二进制

OSI: 物理层 数据链路层  网络层 传输层(RPC) 会话层 表示层 应用层(Http)
A服务---->B服务发送请求传递相应的参数,p服务处理完成之后给予相应的响应。

Sprincode使用的是:
    HTTP Rest方式使用HTTP协议进行数据传递。

而如何在服务之间通过JAVA代码发起HTTP请求:
 (1).Spring框架提供了HTTP client的对象及ret发起一个HTTP请求。
因为浏览器可以发送HTTP协议,浏览器又叫客户端,但是在JAVA中没有浏览器,所以JAVA封装了一个类似浏览器的东西叫RestTemplate,它可以发送gate,post等方式的请求;

(2)通过OpenFeign组件进行通信;

2、使用RestTemplate进行通信:

1)创建RestTemplate 对象:
	RestTemplate   restTemplate = new RestTemplate();
 
 (2)发送请求 如get 请求:
 String order= restTemplate.getForObject(Url,返回类型);

    Url: "http//localhost:9999/order" A服务---->B服务 这个URL就写B的地址
返回类型:String.class    
列 在用户微服务中调用订单服务(两者处于不同的微服务中):

(1)用户微服务:
  
@GetMapping("/user")
    public  String invokedemo()
     RestTemplate restTemplate = new RestTemplate();

     String order= restTemplate.getForObject("http//localhost:9999/order",String.class);
     return  order;
 

(2)订单服务:   
@GetMapping("/order")
    public  String orderdemo()
     return  "调用订单服务成功";
     

3、直接使用RestTemplate进行通信的问题:

1.url写死了:无法实现服务集群时请求的负载均衡;
2.url写死了:日后服务器地址改变,不利于维护;
解决RestTemplate负载均衡的办法:
1.自定义解决策略:
   将访问的所有url放在一个list当中,通过随机数生成去获取其中一个URL,但是这种方法它无法实现服务的健康检查。
2.使用Springcode的组件Ribbon组件解决:
  Ribbon作用是负载均衡的客户端组件,就是用来解决直线请求调用时的负载均衡。

三、Ribbon负载均衡组件:

Ribbon是一个基于HTTPTCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
他是一个负载均衡客户端组件 就是用来实现请求调用时负载均衡
原理:
   首先A服务调用B服务时,不再是以url地址直接访问。而是以B服务的服务名访问。而Ribbon通过这个服务名去注册中心中拿到服务名对应的所有B服务的地址地址,在本地进行一个缓存之后,通过轮询策略将一个个服务地址交给RestTemplate进行访问。下一次再一次调用b服务的时候,就不会再去服务中心拿了,而是从本地缓存中取来。
   如果有一个服务死机了,恰好调用这个服务时只会调不通。但注册中心会每次发送更新缓存用于更新,如果此时恰好没来得及更新,那么还是调不通。

1、Ribbon实现步骤:

--  A服务调用B服务,那么就在 A服务中引入Ribbon依赖。
 注意:Consul的客户端依赖中已近继承Ribbon依赖,无需再次引入
 
(1)使用Ribbon组件 + RestTemplate实现负载均衡:
Ribbon 提供了三种方式:
(1) Discoveryclient 对象-----l  服务与注册发现对象
                             ----------> 当我们引入了robin这个组件的时候,会自己在咱们项目中自动在工厂中创建这两个对象使用的时候直接注入就行。
(2) LoadBalancelient 对象----l  负载均衡客户端对象

(3) 通过 @LoadBalance 注解
(1)使用Discoveryclient 方式:
A--->B服务:
1.A服务中使用:
 @Autowired
 Private Discoveryclient dis;
 List<ServiceInstance> serviceInstances = dis.getInstances("B服务唯一标示"); 

2.再通过 serviceInstances 获取服务地址将其交给RestTemplate 进行访问:
    String urL= serviceInstances.get(0).getUri();
  String result = new RestTemplate().getForObject(urL + "/B服务接口地址", String.class);  
    
    
//------------------------------------------------------------------
 @Autowired
 Private Discoveryclient dis;
 @GetMapping("A")
    public String invokeDemo()
      //返回B服务的端口和IP地址信息集合,如果B服务是一个集群部署的话就是多个
       List<ServiceInstance> serviceInstances = dis.getInstances("B服务唯一标示"); 
       serviceInstances.forEach(serviceInstance -> 
           sout("服务主机:  服务端口: 服务地址:",serviceInstance.getHost(),serviceInstance.getPort(),serviceInstance.getUri());
      );
       String result = new RestTemplate().getForObject(serviceInstances.get(0).getUri() + "/B服务接口地址", String.class);
    
        return result;


--- 缺点:
     并没有实现负载均衡,而是需要自己实现。
    
(2) 使用LoadBalancelient 方式:
A--->B服务:
1.A服务中使用:
 @Autowired
 Private LoadBalancelient load;
 
2.给他一个服务唯一标示ID返回一个不确定的机器,由此证明帮我们实现了负载均衡,即我们把B服务唯一标示给他,由他进行负载均衡返回一个机器给我们用于使用。
 ServiceInstance serviceInstance = load.choose("B服务唯一标示");//默认轮询
 
3. 再通过 serviceInstances 获取服务地址将其交给RestTemplate 进行访问:
    String urL= serviceInstance.getUri();
  String result = new RestTemplate().getForObject(urL + "/B服务接口地址", String.class);        
 
#--------------------------------------------------------------------------
 @Autowired
 Private LoadBalancelient load;
 @GetMapping("A")
    public String invokeDemo()
      //返回B服务的端口和IP地址信息集合,如果B服务是一个集群部署的话就是多个
       ServiceInstance serviceInstance = load.choose("B服务唯一标示");//默认轮询
       String URL= serviceInstance.getUri();
       String result = new RestTemplate().getForObject( URL + "/B服务接口地址", String.class);
    
        return result;
    
    
-- 缺点:
     使用的时候需要每次先根据ID获取一个负载均衡的机器,之后再通过与RestTemplate调用服务。

(3) @LoadBalance 注解
该注解不能单独使用,需和 ResTtemplate一起使用;
修饰范围:用在方法上,作用是让当前方法返回的实例对象具有Ribbon负载均衡的特性。

使用步骤:

1.定义一个类 并在该类上面贴上@Configuration 注解
@Configuration 注解:
     代表这是一个SpringBoot的配置类作用和Spring中XML文件的作用相同,只是SpringBoot中不能写Xml文件了。
     在这个注解类中,@Bean相当于Bean标签。方法名相当于ID。作用相当于在工厂中创建这个对象。
 
 @Configuration
 public class Beancofig()
 
      @Bean
      @LoadBalance         //--------》要贴在方法上面 让当前方法 返回当前对象具有rbbon负载均衡特性
      public RestTeamplate restTemplate()
       return new RestTemplate();
      
 
 

#------------------------ 第二中------------
    将该方法放到 启动类中  因为启动类中注解包含了@Configuration
     
    @Bean
      @LoadBalance         //--------》要贴在方法上面 让当前方法 返回当前对象具有rbbon负载均衡特性
      public RestTeamplate restTemplate()
       return new RestTemplate();
      

 
A--->B服务:
2.A服务中使用:
    直接注入获取RestTemplate 对象
    @Autowired
    private  RestTemplate restTemplate;
    //  注意这里的url和以前不一样了要写B服务唯一标识和B服务接口地址。
    String result = restTemplate.getForObject("http://B服务唯一标识/B服务接口地址",String.class); 


#------------------------------------------------------
 @Autowired
 private  RestTemplate restTemplate;

@GetMapping("A")
 public String invokeDemo()
                              //  注意这里的url和以前不一样了要写B服务唯一标识和B服务接口地址。
    String result = restTemplate.getForObject("http://B服务唯一标识/B服务接口地址",String.class);
   return result;
   
      
   
-- 缺点:
   还是解决不了路径写死的问题,不利于维护。

2、Ribbon组件实现负载均衡原理

根据调用服务ID去服务注册中心获取对应服务ID的服务列表。并将服务列表拉取本地进行缓存,然后在本地通过默认的轮询负载均衡策略。
在现有的列表中选择一个可用的节点提供服务。

注意: Rbbon实现负载均衡是在客户端当中实现负载均衡的。

四、OpenFeign 服务通

以上是关于SpringCloud 总结的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud中Rabbitmq的使用

2020最新大厂高频微服务面试总结:Spring-Cloud+Spring-Boot+Dubbo(面试题+笔记+项目实战)

开启springcloud全家桶4:极简API调用方式 Spring Cloud Feign 总结

32Spring Cloud 服务跟踪总结

Spring Cloud 与微服务学习总结(17)—— SpringCloud Gateway API 接口安全设计(加密 签名安全)

超详细的 Spring Cloud 总结--加薪升职必备