Spring Cloud
不在能知,乃在能行。
1.环境配置
- Spring Boot:2.2.2
- Spring Cloud:Hoxton.SR1
- Cloud Alibaba:2.1.0
- MySQL:5.7
1.1 创建父工程
1.1.1 步骤
- 编写POM文件
- 创建依赖管理
- 设置依赖数量
- 设置依赖版本管理
1.1.2 dependencyManagement 和 dependencies 的区别
dependencyManagement是父工程依赖版本和约束,并不会下载相应的依赖,主要的目的是对后面子工程的依赖约束。
dependencies导入相关依赖。
当父工程有了依赖管理后,子模块导入相关依赖时,会首先选用父工程中依赖管理的版本,如果不想用父工程中的版本设置,也可以自己设定。
对于版本是从当前逐渐向上查找的过程,先找到就用先找到版本。
在框架中,约定 > 配置 > 编码,一定要先将环境配置好,然后编写相关的配置文件以后再进行业务编码。
1.2 第一个模块
1.2.1 创建子模块步骤
-
通过Maven创建子模块
- 设置相应的父模块
-
改POM
- 添加POM文件中要使用的依赖
- 修改子模块所需要的设置
-
写配置文件 - YML
- 设置端口号
- 设置模块名
-
编写主启动
没有直接用框架创建Spring项目,需要自己编写相关主启动类。
-
编写业务类
- 创建数据库和表
- 编写对应数据库表的实体类
- 数据库字段和实体类字段属性和名字一一对应
- 编写数据库操作层 - Dao层
- 编写服务层 - Service层
- 编写页面层 - Controller层
-
测试
- POSTMAN测试
1.3 抽取公共模块
1.3.1 步骤
- 创建公共模块
- 安装到Maven仓库
- 其他模块导入依赖
注意:
导入类的路径要和原来的相同,否则需要重新导入(import)。
2.Eureka 服务注册与发现
如果只是服务的调用方是不用注册进Eureka中的,服务的提供方是一定需要注册进Eureka中。
2.1 服务治理
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,可以使用服务治理,来管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等。实现服务发现与注册。
2.2 服务注册
什么是服务注册与发现?
Eureka采用了CS的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC
远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。
将自己注册到服务中心,方便其他模块调用。Eureka就是这样的一个服务中心。
2.3 Eureka两大组件
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
EurekaClient通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。
服务端使用Service依赖和相关注解,客户端使用Client依赖和相关注解。
2.4 创建Eureka服务中心
- 创建Module
- 改POM
- 改YML
- 主启动
- 测试
2.5 修改原有模块
- 添加客户端依赖
- 修改配置文件
- 主启动类添加相关注解
- 测试
2.6 创建Eureka集群
创建两个Eureka服务注册中心,互相注册,相互守望。
- 修改原有服务端的名字,便于区分
- 依照前面的Eureka服务端再创建一个新的
- 相互注册
- 修改原有的客户端,注册到两个服务端之中
3.相互注册
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false #是否向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defalutZone: http://eureka7002.com:7002/eureka/
修改自己的服务名称,向其他服务中心注册自己。
4.修改原有的客户端,注册到两个服务端之中
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
注册多个服务端地址。
2.7 创建多个服务提供者 - payment
- 依照已有的Payment-Server创建一个新的
- 修改配置文件
2.8 负载均衡
现在我们已经有两个Payment服务提供方,虽然都已经注册到了Eureka中,但是客户端的请求如果需要两个服务端轮询提供,那么需要在RestTemplate上加上@LoadBalance注解。
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
2.9 自我保护
Eureka默认是开启自我保护,开启之后如果注册在Eureka中的客户端,因各种原因不能即时的给Eureka服务端发送心跳,Eureka也不会立即将这个客户端删除,而是会登上一段时间,如果一直没有发现心跳,那么就会将这个客户端删除。
2.9.1 禁用自我保护
eureka.server.enable-self-preservation = false
3.其他的服务注册
3.1 概述
- Zookeeper
- Consul
- Ribbon - 负载均衡
- OpenFeign(推荐,自带Ribbon)
3.2 OpenFeign
3.2.1 概述
Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。
通过标注相应注解即可调用在注册中心的服务模块。
3.2.2 功能
Feign能干什么?
Feign旨在使编写Java Http客户端变得更容易。前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下我们只需创建一个接口并使用注解式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon
利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通服务绑定式的方法,优雅而简单的实现了服务调用。
3.2.3 使用步骤
- 创建模块
- 修改POM
- 创建YML
- 创建主启动类
- 编写业务逻辑
3.2.4 详细步骤
1.服务注册
2.服务调用
通过编写相应的接口并通过注解调用服务注册中心的相关服务块即可。
/*
* OpenFeign调用接口
* - 标注@Component将该类注册到容器中
* - 使用@FeignClient注解,使用Feign的服务调用且指明调用的模块名
* */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
/*
* 指明调用的服务块名的具体Controller层
* */
@GetMapping("/payment/get/{id}")
CommonResult<Payment> getPaymentByID(@PathVariable("id") Long id);
}
3.测试
3.2.5 超时控制
默认Feign客户端只等待一秒钟,但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错。为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
通过修改YML相关配置可以提高等待时间。
3.2.6 日志输出
1.概述
Feign提供了日志能,我们可以知道相关Feign模块的Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出。
2.步骤
- 编写相关配置类,并设置日志级别
- YML配置文件中开启相关功能
3.3 三者区别
Eureka、Zookeeper、Consul
3.3.1 CAP理论
C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance(分区容错)
最多只能时较好的满足两个。
CAP理论的核心是::一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,因此,根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP
三大类:
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
AP-满足可用性,分区容忍性的系统,通常可能对一致性要求低—些。
P必须满足,另外的C和A选择一个满足,Eureka是AP - 高可用,另外两个服务注册中心是CP数据不允许有误。
4.Hystrix 断路器
官网:https://github.com/Netflix/Hystrix/wiki/How-To-Use
4.1 概述
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝)回调
预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
保证客户端在服务器宕机等意外情况下,依旧可以有友好的反应给客户端。
4.2 作用
- 服务降级
- 服务熔断
- 实时监控
- …
4.3 服务降级
服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback。
服务器因为各种原因不能很好的服务客户端,客户端可以选择服务降级,不等待服务端的回复,而是客户端本身进行回复。
不仅仅是客户端可以服务降级,服务端也可以服务降级。
4.3.1 导致的原因
-
运行超时
-
程序运行异常
-
服务熔断触发服务降级
后面有详细的解释
-
线程池/信号量打满导致服务降级
4.4 服务熔断
类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。
相当于我们家中的保险丝。
服务器承受不了请求以后做出的反应,拒绝访问,并且直接开启服务降级。
4.4.1 步骤
- 服务降级
- 熔断
- 恢复调用链路
4.4.2 原理
设定在一定的时间内,服务端如果相应的失败率达到一定以后,就会触发服务熔断,后面继续到达的请求不再处理,而是直接交给服务降级处理,然后后面的处理如果能够成功处理的次数达到一定的比例,继续开始服务请求处理。
一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。
4.5 服务限流
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。
大部分的操作查看相关代码,因为后面这方面主要使用阿里巴巴的Spring Cloud相关程序,这里就不做代码过多解释。
5.Gateway 新一代网关
5.1 概述
在Zuul 1.0停止更新且2.0没有发布,Spring自己研发的一套网关系统。在Nginx之后的网关路由。
传统的Web框架,比如说:struts2,springmvc等都是基于ServletAPI与Servlet容器基础之上运行的。
但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程(Spring5必须让你使用java8)Spring WebFlux 是 Spring 5.0 引入的新的响应式框架,区别于 Spring MVC,它不需要依赖Servlet APl,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。
更好、更快。
底层是Netty网络请求。
5.2 功能
- 反向代理
- 鉴权
- 流量控制
- 熔断
- 日志监控
- …
5.3 三大核心概念
客户端向SpringCloudGateway发出请求。然后GatewayHandlerMapping中找到与请求相匹配的路由,送到 GatewayWeb Handler。
Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之(“pre”)或之后(“post”)执行业务逻辑。
Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
路由转发+执行过滤器链
5.3.1 Route(路由)
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。
经过断言和过滤以后进行具体的路由。
5.3.2 Predicate(断言)
参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
断言,满足断言所设置的定义则通过,不满足断言的定义则阻断。
5.3.3 Filter(过滤)
指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
过滤规则和JavaWeb中的过滤器类似。
5.4 实现
- 创建模块
- 修改POM
- 设置主启动类
- 需要将自己添加到注册中心@EnableEurekaClient
- 设置网关映射
- 开启动态的映射,到注册中心寻找
5.4.1 修改POM
添加网关依赖支持。
<!--新增gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
5.4.2 设置网关映射
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
#配置路由规则
routes:
#规则名称
- id: payment_routh
#路由的目的地址
uri: lb://cloud-payment-service
#路由断言
predicates:
- Path=/payment/get/**
#开启动态注册,直接到注册中心寻找
discovery:
locator:
enabled: true
5.4.3 常用断言
1.After Route Predicate
在某个时间后,可以访问这个地址,时间格式有限制,时间格式可以通过ZoneDateTime.now()
来获取得到。
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
同样的断言还有:Before、Between都是类似。
2.Cookie Route Predicate
- Cookie=username,pox #并且Cookie是username=pox才能访问
还有类似其他的,向前可以查询官网。
5.5 过滤器
5.5.1 概述
路由过滤器。Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
5.5.2 自定义
Gateway本身自带了许多过滤器,但是常用还是推荐自己写。实现相关接口并将该类注册到容器中。
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*********come in MyLogGateWayFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("username");
if(StringUtils.isEmpty(username)){
log.info("*****用户名为Null 非法用户,(┬_┬)");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//给人家一个回应
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
// 过滤器优先级,越小优先级越高
@Override
public int getOrder() {
return 0;
}
}
6.Stream 消息驱动
6.1 概念
官方定义Spring Cloud Stream 是一个构建消息驱动微服务的框架。应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream中binder对象交互。通过我们配置来binding(绑定),而 Spring Cloud Stream 的 binder对象负责与消息中间件交互。
所以,我们只需要搞清楚如何与Spring Cloud Stream 交互就可以方便使用消息驱动的方式。通过使用Spring Integration来连接消息代理中间件以实现消息事件驱动。
Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,引用了发布-订阅、消费组、分区的三个核心概念。
屏蔽底层消息中间件的差异,降低切换版本,统一消息的编程模型。
目前仅支持:RabbitMQ、kafka
6.2 原理
- 生产者是INPUT
- 消费者是OUTPUT
具体看原笔记。
7.Nacos
7.1 概念
一个更易于构建云原生应用的动态服务发现,配置管理和服务管理中心。
Nacos就是注册中心+配置中心的组合。
7.2 功能
- 做服务注册与发现
- 做配置中心
7.3 测试
-
作为服务中心
-
作为配置中心
-
需要先配置一个bootstrap.yaml
在Spring官方,bootstrap启动的优先级是最高的,加载这个以后,再去拉取配置
-
在具体的需要用到配置的地方加上@RefreshScope注解,实现动态刷新获取
-
在Nacos上编写配置文件,名字符合匹配规则
-
注意:在yaml文件中填写的namespace为具体生成的id,不是直接填写名字。
代码查看:cloudalibaba-provider-payment-9001、cloudalibaba-config-nacos-client-3377模块。
8.Alibaba Sentinel 熔断与限流
8.1 概述
加强版的hystrix。
8.2 主要功能
- 服务雪崩
- 服务降级
- 服务熔断
- 服务限流
8.2.1 组成
官网下载相关的启动jar包,后台端口为8080,默认登录用户名和密码均为:sentinel。
8.3 测试
创建模块…
8.3.1 修改YAML
添加到Sentinel和Nacos监测、注册。
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
启动完具体的服务以后,不会立即出现到Sentinel中,需要访问过具体的地址以后,才会出现在Sentinel管理界面中,原理为:Sentinel为懒加载模式。
8.4 界面配置参数
详情结合实例查看脑图。