Spring Cloud学习笔记

一、微服务架构:

微服务架构的核心就是将一个庞大的单体应用根据业务拆分为一个个的小型服务(Module),每个小型服务提供单个业务功能,且能够自行单独启动与销毁,拥有自己独立数据库,实现彻底解耦合。

 

二、微服务架构核心问题:

1、微服务治理问题(服务注册与发现)

2、微服务相互通信问题(服务通信)

3、微服务宕机问题(服务降级与熔断)

4、客户端访问微服务问题(服务网关)

 

三、微服务CAP原则:

1、CAP原则:

CAP原则又称CAP定理,指的是在一个分布式系统中,存在Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可同时保证,最多只能保证其中的两者。

(1)、一致性(C):分布式系统中所有数据备份同一时刻值都相同。

(2)、可用性(A):负载过大后,集群整体中非故障节点还能响应客户端的读写请求。

(3)、分区容错性(P):服务间相互调用问题,分布式系统节点之间组成的网络本来应该是连通的,当遇到某节点或网络分区故障(比如网络丢包等)的时候,仍然能够对外提供满足一致性或可用性的服务。由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。

2、分布式架构三大方案:

分布式架构只能满足其中两种,不可能全部都满足:

(1)、AC:可用性+一致性

要同时保证可用性和一致性,代表着某个节点数据更新之后,需要立即将结果通知给其他节点,并且要尽可能的快,这样才能及时响应保证可用性,这就对网络的稳定性要求非常高,但是实际情况下,网络很容易出现丢包等情况,并不是一个可靠的传输,如果需要避免这种问题,就只能将节点全部放在一起,但是这显然违背了分布式系统的概念,所以对于我们的分布式系统来说,很难接受。

(2)、CP: 一致性+分区容错性

为了保证一致性,那么就得将某个节点的最新数据发送给其他节点,并且需要等到所有节点都得到数据才能进行响应,同时有了分区容错性,那么代表我们可以容忍网络的不可靠问题,所以就算网络出现卡顿,那么也必须等待所有节点完成数据同步,才能进行响应,因此就会导致服务在一段时间内完全失效,所以可用性是无法得到保证的。

(3)、AP:可用性+分区容错性

既然CP可能会导致一段时间内服务得不到任何响应,那么要保证可用性,就只能放弃节点之间数据的高度统一,也就是说可以在数据不统一的情况下,进行响应,因此就无法保证一致性了。虽然这样会导致拿不到最新的数据,但是只要数据同步操作在后台继续运行,一定能够在某一时刻完成所有节点数据的同步,那么就能实现最终一致性所以AP实际上是最能接受的一种方案。

 

四、Spring Cloud简介:

Spring Cloud是一个一站式的开发分布式系统的框架,为开发者提供了一系列的构建分布式系统的工具集;

(服务注册与发现、负载均衡与服务调用、服务降级与熔断、服务消息队列、服务网关、配置中心管理、自动化构建部署、服务监控、全链路追踪、服务定时任务、调度操作)

 

五、Spring Cloud微服务项目构建:

1、Spring Cloud相关组件版本的选择:

Spring Cloud版本(伦敦的地名)Spring Boot版本匹配关系

注:

(1)、Spring Boot官方强烈建议使用2.X以上版本

(2)、Spring Boot和Spring Cloud的版本要契合,否则可能会报错

2、Spring Cloud工程搭建(配置>编码):

(1)、搭建父工程:

统一字符编码:

 

注解生效激活:

统一编译版本:

注:父工程必须遵循两点:

1)、将src目录删掉

2)、设置pom.xml:

(2)、搭建Module子模块工程

建Module(Spring Boot工程)-改POM-写YML-主启动-业务类

 

六、Eureka服务注册与发现:

Eureka能够自动注册并发现微服务,然后对服务的状态、信息进行集中管理,当需要获取其他服务的信息时,只需要向Eureka进行查询,削弱服务之间的强关联性,避免因服务路径的修改而造成调用服务的大规模同步修改。

1、实现服务注册与发现:

(1)、声明注册中心:

创建Eureka服务器工程,实现对服务的状态、信息进行集中管理

添加相关依赖:

<!-- eureka注册中心  -->
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

YML配置:

开启注册中心:

访问Eureka的管理后台:

(2)、服务注册:

相关微服务注册到注册中心

添加相关依赖:

<!-- eureka客户端-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

YML配置:

(3)、服务发现:

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息,即:获取微服务信息或者微服务间相互远程调用,那么就必须要知道其服务的地址,当微服务注册到Eureka之后,我们可以通过服务名称(替代对应的微服务地址)直接向其进行查询。

方式一:服务调用

//spring.application.name=cloud-provider

方式二:获取服务名称、端口号之类的信息

2、实现注册中心的高可用:

搭建Eureka集群,通过运行多个Eureka server实例并相互注册的方式实现,Server节点之间会彼此增量地同步信息,从而确保节点中数据一致

(1)、Eureka服务器工程:

节点一:

节点二:

(2)、微服务注册:

3、BUG解决:

(1)、GSON版本不兼容:

 

由于SpringBoot加载了GsonAutoConfiguration@Configuration类,它试图调用GsonBuilder的setLenient()方法。SpringBoot已经将正确的gson-jar设置为依赖项,它应该自动包含在你的构建中;但是显式地指定对gson的依赖性将会覆盖SpringBoot带来的依赖性。最好的办法是从pom.xml中删除对gson的显式依赖关系,或者更新它以匹配您正在使用的SpringBoot版本所期望的依赖关系。

解决方案:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.2</version>
</dependency>

(2)、Jackson版本不兼容:

解决方案:

<dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-core</artifactId>
     <version>2.13.1</version>
</dependency>
<dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-annotations</artifactId>
     <version>2.13.1</version>
</dependency>

 

七、OpenFeign负载均衡与服务调用:

1、RestTemplate+@LoadBalanced方式实现:

@LoadBalanced是Spring Cloud中提供的一个注解,它用于将一个RestTemplate对象标记为支持负载均衡的,从而可以针对服务名称进行REST调用。

(1)、原理

@LoadBalanced注解,主要是用于构建RestTemplate对象时,让其在发送请求时,具备负载均衡的功能。添加该注解后,请求会被内部的LoadBalancerInterceptor拦截器拦截,拦截后会将请求的服务名转换为具体的访问地址,再发起请求。

(2)、自定义负载均衡策略:

LoadBalancer提供两种负载均衡策略:

1)、 RoundRobinLoadBalancer - 轮询分配策略(默认)

2)、RandomLoadBalancer - 随机分配策略

声明随机分配策略的配置类:

/**
 * 随机分配策略的配置类
 * */
public class LoadBalancerConfig {
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

指定分配策略:

2、OpenFeign方式实现:

(1)、概述:

OpenFeign是Feign的加强版,通过@FeignClient注解可以解析@RequestMapping注解下的接口,再通过代理生成实现类,同时在实现类中做负载均衡调用其他的服务,极大的简化了服务之间的相互调用。

(2)、实现:

消费者服务进行消费(即调用生产者接口)

消费者添加相关依赖:

<!--HTTP客户端请求工具: OpenFeign-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启用OpenFeign:

创建对应服务的接口类:(类似Mybatis)

(3)备注:

OpenFeign默认等待一秒钟,超过后报错。OpenFeign底层是由Ribbon实现的,所以只要修改Ribbon的配置即——超时配置:

 

八、Hystrix服务降级与熔断:

为了解决分布式系统的雪崩问题,SpringCloud提供Hystrix熔断器组件以此保证在高访问量、高并发的场景下,应用系统依然稳定,服务依然高可用。

注:服务雪崩是指服务提供者不可用导致服务调用者也跟着不可用,以此类推引起整个链路中的所有微服务都不可用。

1、服务降级和服务熔断的区别:

(1)、服务降级:

服务降级不会直接返回错误,而是提供一个补救措施(备选方案),正常响应给请求者。相当于服务依然可用,但是服务能力下降了。服务降级是一种比较温柔的解决方案,虽然服务本身的不可用,但是能够保证正常响应数据。

(2)、服务熔断:

服务熔断就是在降级的基础上进一步升级形成的,也就是说,熔断机制能够对一段时间内出现的错误进行侦测,当侦测到出错次数过多时,熔断器会打开,所有的请求会直接响应失败(即服务降级,进入备选方案),一段时间后,只执行一定数量的请求,如果还是出现错误(尝试机制),那么则继续保持熔断器打开状态,否则说明服务恢复正常运行,关闭熔断器。

2、实现服务降级与熔断:

(1)、采用Hystrix(已经停止维护)实现降级:

服务提供者进行服务降级

添加相关依赖:

<!-- Hystrix——已经停止维护,需要单独导入-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
     <version>2.2.10.RELEASE</version>
</dependency>

开启Hystrix:

控制类进行降级操作:

当一段时间内多次调用失败,那么就直接升级为熔断,直接返回onAlternate()补救方法,如果还是出现错误(尝试机制),那么则继续保持熔断器打开状态,否则说明服务恢复正常运行,关闭熔断器。

(2)、采用OpenFeign集成Hystrix实现降级:

由于远程调用失败,Hystrix监控到并进行服务降级。根据这个思路,OpenFeign对远程调用声明的接口进行实现(即接口实现类的方法,为降级策略执行方案)——消费者而言。

服务消费者进行服务降级

添加相关依赖:

<!--HTTP客户端请求工具: OpenFeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Hystrix——已经停止维护,需要单独导入-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

启用OpenFeign与Hystrix:

开启熔断支持:

对应服务接口类:

 

九、Hystrix与Actuator服务监控:

hystrix与actuator实现实时监控:

1、开启监控页面部署:

创建hystrix-dashboard服务工程,开启监控页面部署,即监控服务

添加相关依赖:

<!-- hystrix监控页面-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    <version>2.2.10.RELEASE</version>
</dependency>

开启管理页面:

添加配置,支持对localhost监控:

访问监控页面:

访问地址:http://监控者地址与端口/hystrix/

2、实现实时监控:

被监控服务引入监控系统

添加相关依赖:

<!-- Hystrix——已经停止维护,需要单独导入-->
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
     <version>2.2.10.RELEASE</version>
</dependency>
<!--SpringBoot监控系统-->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Actuator暴露配置:

实时监控:

访问地址:http://被监控者地址与端口/actuator/hystrix.stream

3、备注:

监控对象问题只对带上@HystrixCommand注解的方法进行监控,没有则一直loading

 

十、Gateway 路由网关:

1、概述:

一般情况下,可能并不是所有的微服务都需要直接将地址暴露给外部调用,这时我们可以使用路由机制——通过暴露网关微服务系统地址,隐藏其他微服务的内网地址,由前端直接全部访问网关服务,不需要区分各种IP端口服务,让网关对所有的请求进行对应路由,并且转发给多个相同微服务实例也可以实现负载均衡,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控等相关功能。

Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器,现已淘汰。新出现SpringCloud Gateway路由是基于Spring的网关项目,使用的是Webflux中的Reactor-Netty响应式编程组件,底层使用了Netty通讯框架,集成过滤器(Filter),路径重写,性能比Zuul好,旨在为微服务框架提供一种简单而有效的统一的API路由管理方式,统一访问接口

2、Gateway三大核心:

Route(路由)

路由是构建网关的基本模块,由ID,目标URI,一系列的断言和过滤器组成

Predicate(断言)

开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

Filter(过滤)

使用过滤器,可以在请求被路由前或者之后对请求进行修改

备注:

(1)、路由断言工厂Route Predicate Factory:

名称

说明

示例

After

是某个时间点后的请求

- After=2037-01-20T17:42:47.789-07:00[America/Denver]

Before

是某个时间点之前的请求

- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]

Between

是某两个时间点之前的请求

- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]

Cookie

请求必须包含某些cookie

- Cookie=chocolate, ch.p

Header

请求必须包含某些header

- Header=X-Request-Id, \d+

Host

请求必须是访问某个host(域名)

- Host=.somehost.org,.anotherhost.org

Method

请求方式必须是指定方式

- Method=GET,POST

Path

请求路径必须符合指定规则

- Path=/red/{segment},/blue/**

Query

请求参数必须包含指定参数

- Query=name, Jack或者- Query=name

RemoteAddr

请求者的ip必须是指定范围

- RemoteAddr=192.168.1.1/24

Weight

权重处理

 

(2)、过滤器工厂 GatewayFilterFactory:

名称

说明

AddRequestHeader

给当前请求添加一个请求头

RemoveRequestHeader

移除请求中的一个请求头

AddResponseHeader

给响应结果中添加一个响应头

RemoveResponseHeader

从响应结果中移除有一个响应头

RequestRateLimiter

限制请求的流量

...

 

3、实现Gateway路由网关:

创建Gateway路由服务工程,暴露网关微服务系统地址,隐藏其他微服务的内网地址:

添加相关依赖:

添加配置,进行服务注册与路由网关:

通过路由访问服务:

4、实现路由Filter过滤器:

过滤器的作用:对路由的请求或响应做加工处理,比如添加请求头配置,在路由下的过滤器只对当前路由的请求生效。

(1)、单路由过滤器:

添加过滤器配置:

对应服务可获取相关请求头信息:

(2)、自定义全局路由过滤器:

网关服务进行全局路由过滤器配置:

//@Order(0)   //不生效
@Component   //需要注册为Bean
public class GlobalFilterTest implements GlobalFilter, Ordered {

    /**
     *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {   //只需要实现此方法
        //获取ServerHttpRequest对象(注意不是HttpServletRequest)
        ServerHttpRequest request = exchange.getRequest();
//        System.out.println(request.getHeaders().get("Test"));   //获取单路由过滤器配置,用于判断优先级
        //获取所有的请求参数
        System.out.println(request.getQueryParams());
        MultiValueMap<String, String> params = request.getQueryParams();
        String auth = params.getFirst("authorization");
        // 3.判断参数值是否等于 admin
        if ("admin".equals(auth)) {
            // 4.是,放行
            //将ServerWebExchange向过滤链的下一级传递(跟JavaWeb中介绍的过滤器其实是差不多的)
            return chain.filter(exchange);
        }
        //拦截请求,直接在这里不再向下传递,然后返回响应
        return exchange.getResponse().setComplete();
    }

    //配置Order的值,实现过滤器执行优先级
    @Override
    public int getOrder() {
        return 0;   //Order的值越小优先级越高
    }
}

(3)、备注:

备注

说明

1

Order值越小表示优先级越高,并且无论是在配置文件中编写的单个路由过滤器还是全局路由过滤器,都会受到Order值影响

2

单个路由的过滤器Order值按从上往下的顺序从1开始递增

3

当Order值一样时 全局路由过滤器执行优于单个路由过滤器执行

 

十一、Config配置中心:

1、概述:

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。

SpringCloud Config为微服务架构中的微服务提供集中化的外部配置支持(即,集中管理配置文件),配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。

Config配置中心

说明

服务端

服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。

客户端

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息(配置服务器默认采用GIT来存储配置信息)

2、存储配置信息:

可以采用本地仓库、远程仓库或者服务器(Linux)来存储配置信息(默认采用GIT来存储配置信息),当前以本地仓库为例

(1)、在当前位置下打开Git Bash Here,创建一个新的本地仓库:

(2)、执行相应操作:

#查看是否已设置用户信息
git config --global -l
#若无则设定用户名和邮箱来区分不同的用户,否则跳过
git config --global user.name "YourName"
git config --global user.email "email@example.com"
#创建一个用于存储配置信息的目录
mkdir remote-config
cd remote-config/
#当前目录下创建本地仓库
git init
#添加配置文件与相关配置信息,例如vim cloudprovider-test.yml
vim {服务名称}-{环境}.yml
#提交到本地仓库中
git add .
git commit -m "Init commit"
#查看当前分支
git branch

(3)、管理配置文件信息:

3、服务端实现:

创建Config配置服务工程,获取配置信息,实现对配置文件的集中管理:

添加相关依赖:

    <dependencies>
        <!--eureka注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--config配置中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>

开启服务端配置管理:

添加配置,进行服务注册与配置文件管理:

访问配置文件信息:

(1)、方式一:

http://localhost:5080/cloudprovider/test/master

(2)、方式二:

http://localhost:5080/master/cloudprovider-test.yml

4、客户端实现:

客户端添加bootstrap.yml文件,可以实现配置文件远程获取

(bootstrap.yml在application.yml之前加载,且可同时存在,最后无论是远端配置还是本地配置都会被加载)

相关配置信息:

5、备注:

applicaiton.yml是用户级的资源配置项

bootstrap.yml是系统级的,优先级更加高

Spring Cloud会创建一个Bootstrap Context,作为Spring应用的Application Context的父上下文。初始化的时候,BootstrapContext负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment。Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。Bootstrap context和Application Context有着不同的约定,所以新增了一个bootstrap.yml文件,保证Bootstrap Context和Application Context配置的分离。

要将Client模块下的application.yml文件改为bootstrap.yml,这是很关键的,因为bootstrap.yml是比application.yml先加载的,故bootstrap.yml优先级高于application.yml。

 

posted on 2024-03-29 00:23  爱文(Iven)  阅读(41)  评论(0编辑  收藏  举报

导航