- 官方定义:微服务就是由一系列围绕自己业务开发的微小服务构成,他们独立部署运行在自己的进程里,基于分布式的管理
- 通俗定义:微服务是一种架构,这种架构是将单个的整体应用程序分割成更小的项目关联的独立的服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之间的关联通过暴露api来实现。这些独立的微服务不需要部署在同一个虚拟机,同一个系统和同一个应用服务器中。
- 优点
- 单一架构模式在项目初期很小的时候开发方便,测试方便,部署方便,运行良好。
- 缺点
- 应用随着时间的推进,加入的功能越来越多,最终会变得巨大,一个项目中很有可能数百万行的代码,互相之间繁琐的jar包。
- 久而久之,开发效率低,代码维护困难
- 还有一个如果想整体应用采用新的技术,新的框架或者语言,那是不可能的。
- 任意模块的漏洞或者错误都会影响这个应用,降低系统的可靠性
- 优点
- 将服务拆分成多个单一职责的小的服务,进行单独部署,服务之间通过网络进行通信
- 每个服务应该有自己单独的管理团队,高度自治
- 服务各自有自己单独的职责,服务之间松耦合,避免因一个模块的问题导致服务崩溃
- 缺点
- 开发人员要处理分布式系统的复杂性
- 多服务运维难度,随着服务的增加,运维的压力也在增大
- 服务治理 和 服务监控 关键
- 架构的演变过程
[单一应用架构]===>
[垂直应用架构]===>
[分布式服务架构]===>
[流动计算架构]||[微服务架构]===>
[未知]
1. All in One Application 单一架构
- 起初当网站流量很小时,将所有功能都写在一个应用里面,对整个应用进行部署,以减少部署节点和成本。对于这个架构简化增删改查的工作量的数据访问框架(ORM)是关键。
2. Vertical Application 垂直架构
- 当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
3. Distributed Service 分布式服务架构
- 当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
4. Elastic Computing 流动计算架构即微服务架构
- 当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键
1.Dubbo (阿里系)
初出茅庐:2011年末,阿里巴巴在GitHub上开源了基于Java的分布式服务治理框架Dubbo,之后它成为了国内该类开源项目的佼佼者,许多开发者对其表示青睐。同时,先后有不少公司在实践中基于Dubbo进行分布式系统架构,目前在GitHub上,它的fork、star数均已破万。Dubbo致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案,使得应用可通过高性能RPC实现服务的输出、输入功能和Spring框架无缝集成。Dubbo包含远程通讯、集群容错和自动发现三个核心部分。
停止维护:从2012年10月23日Dubbo 2.5.3发布后,在Dubbo开源将满一周年之际,阿里基本停止了对Dubbo的主要升级。只在之后的2013年和2014年更新过2次对Dubbo
2.4的维护版本,然后停止了所有维护工作。Dubbo对Srping的支持也停留在了Spring 2.5.6版本上。死而复生:多年漫长的等待,随着微服务的火热兴起,在国内外开发者对阿里不再升级维护Dubbo的吐槽声中,阿里终于开始重新对Dubbo的升级和维护工作。在2017年9月7日,阿里发布了Dubbo的2.5.4版本,距离上一个版本2.5.3发布已经接近快5年时间了。在随后的几个月中,阿里Dubbo开发团队以差不多每月一版本的速度开始快速升级迭代,修补了Dubbo老版本多年来存在的诸多bug,并对Spring等组件的支持进行了全面升级。
2018年1月8日,Dubbo创始人之一梁飞在Dubbo交流群里透露了Dubbo 3.0正在动工的消息。Dubbo 3.0内核与Dubbo 2.0完全不同,但兼容Dubbo 2.0。Dubbo 3.0将以Streaming为内核,不再是Dubbo 时代的RPC,但是RPC会在Dubbo
3.0中变成远程Streaming对接的一种可选形态。从Dubbo新版本的路线规划上可以看出,新版本的Dubbo在原有服务治理的功能基础上,将全面拥抱微服务解决方案。结论:当前由于RPC协议、注册中心元数据不匹配等问题,在面临微服务基础框架选型时Dubbo与Spring Cloud是只能二选一,这也是为什么大家总是拿Dubbo和Spring
Cloud做对比的原因之一。Dubbo之后会积极寻求适配到Spring Cloud生态,比如作为Spring
Cloud的二进制通信方案来发挥Dubbo的性能优势,或者Dubbo通过模块化以及对http的支持适配到Spring Cloud。
Spring Cloud:
Spring Cloud NetFlix 基于美国Netflix公司开源的组件进行封装,提供了微服务一栈式的解决方案。
Spring Cloud alibaba 在Spring cloud netflix基础上封装了阿里巴巴的微服务解决方案。
Spring Cloud Spring 目前spring官方趋势正在逐渐吸收Netflix组件的精华,并在此基础进行二次封装优化,打造spring专有的解决方案。
1.官方定义
官方网址:
https://cloud.spring.io/spring-cloud-static/Hoxton.SR5/reference/html/
springcloud为开发人员提供了在分布式系统中快速构建一些通用模式的工具(例如配置管理、服务发现、断路器、智能路由、微代理、控制总线)
2. 通俗定义
springcloud含有众多子项目的工具集 tools collection 微服务工具集合
基于单体基于业务进行拆分,每个服务都是独立的应用 独立部署 运行在自己计算机进程 对于这些服务都是分布式管理
1.核心组件说明
- eurekaserver、consul、nacos 服务注册中心组件
- rabbion & openfeign 服务负载均衡 和 服务调用组件
- hystrix & hystrix dashboard 服务断路器 和 服务监控组件
- zuul、gateway 服务网关组件
- config 统一配置中心组件
- bus 消息总线组件 …
https://spring.io/projects/spring-cloud
- Angel 版本基于springboot1.2.x版本构建与1.3版本不兼容
- Brixton 版本基于springboot1.3.x版本构建与1.2版本不兼容 `2017年Brixton and Angel release官方宣布报废
- Camden 版本基于springboot1.4.x版本构建并在1.5版本通过测试 `2018年Camden release官方宣布报废
- Dalston、Edgware 版本基于springboot1.5.x版本构建目前不能再springboot2.0.x版本中使用
`Dalston(达尔斯顿)将于2018年12月官方宣布报废。Edgware将遵循Spring Boot 1.5.x的生命周期结束。- Finchley 版本基于springboot2.0.x版本进行构建,不能兼容1.x版本
- Greenwich 版本基于springboot2.1.x版本进行构建,不能兼容1.x版本
- Hoxton 版本基于springboot2.2.x版本进行构建
Spring Cloud Dalston、Edgware、Finchley 和 Greenwich 都已达到生命周期结束状态,不再受支持。
2. 版本选择
<!--继承springboot的父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!--自定义properties属性-->
<properties>
<spring.cloud-version>Hoxton.SR6</spring.cloud-version>
</properties>
<!-- 维护版本-->
<dependencyManagement>
<dependencies>
<!-- 维护springcloud版本依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 可以对所有的微服务的信息进行存储,如微服务的名称、IP、端口等
- 可以在进行服务调用时通过服务发现查询可用的微服务列表及网络地址进行服务调用
- 可以对所有的微服务进行心跳检测,如发现某实例长时间无法访问,就会从服务注册表移除该实例。
2.服务注册中心组件开发
常用注册中心组件:eureka (netflix) 、 zookeeper (java) 、consul (co) 、nacos (java阿里巴巴)
3.eureka
简化:eureka是Netflix开发的服务发现框架 springcloud-netflix-eureka 服务注册中心 Eureka
Eureka包含两个组件: Eureka server和Eureka client
<!--引入 eureka server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
#eureka server 端口号 默认就是8761
server.port=8761
#指定服务名称 唯一标识 注意:服务名不能出现下划线_ 默认服务名不区分大小写 推荐服务名大写
spring.application.name=eurekaserver
#指定服务注册中心的地址 暴露服务地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
@EnableEurekaServer //开启当前应用是一个服务中心
http://localhost:8761/eureka
出错解释:eureka 含有两个组件 eureka server、eureka client组件,当项目中引入eureka server 组件时,这个组件同时将eurekaclient引入到项目中,因此启动时即会将自己作为一个服务中心启动,同时也会将自己作为服务客户端进行注册,默认启动时立即注册,注册时服务还有没有准备完成因此会出现当前错误
#关闭eureka client立即注册
eureka.client.fetch-registry=false
#让当前应用仅仅是服务注册中心
eureka.client.register-with-eureka=false
<dependencies>
<!--引入springboot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
#指定服务端口
server.port=9999
#指定服务名
spring.application.name=EUREKACLIENT
#指定服务注册中心地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
@EnableEurekaClient //让当前微服务作为一个eureka server客户端 进行服务注册
注意:自我保护机制默认是开启的
现象:在自我保护模式下,eureka服务器将停止逐出所以实例。
机制:这样做是为了确保灾难性的网络事件不会清除eureka注册表数据,并将其传播到下游的所有客户端,触发自我保护机制
什么时候将客户端在服务注册中清除
eureka.server.enable-self-preservation=false #关闭自我保护
eureka.server.eviction-interval-timer-in-ms=3000 # 超时3s自动清除 60*1000 1分钟
eureka.instance.lease-expiration-duration-in-seconds=10 #用来修改eureka server默认接受心跳的最大时间默认是90s
eureka.instance.lease-renewal-interval-in-seconds=5 #指定客户端多久向eureka server发送一次心跳默认是30s
1.集群搭建
2.完全集群
a.创建3个springboot项目
b.引入 eureka server依赖
c 配置文件 application.properties
node1
server.port:8761
#指定服务注册中心的地址 暴露服务地址
eureka.client.service-url.defaultZone=http://127.0.0.1:8762/eureka,http://127.0.0.1:8763/eureka
node2
server.port:8761
#指定服务注册中心的地址 暴露服务地址
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka,http://127.0.0.1:8763/eureka
node3
server.port:8761
#指定服务注册中心的地址 暴露服务地址
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka,http://127.0.0.1:8762/eureka
@EnableEurekaServer //开启当前应用是一个服务中心
作用:微服务架构充当服务注册中心
两个角色: 服务注册中心、 微服务
eureka(ui界面) 、 zookeeper (java shell查看服务注册)、consul (ui) . nacos (ui)
简介:consul基于go语言进行开发服务注册中心轻量级服务注册中心 google
作用:管理微服务中所有服务注册发现管理服务元数据信息存储(服务名地址列表)心跳健康检查
a.下载consul
consul官网下载
b.在指定目录进行解压缩注意:不建议目录中含有中文
C:\Users\92092\Desktop\文件\consul\consul.exe
c.启动服务注册中心
d.访问consul管理界面
http:端口默认8500浏览器: localhost:8500
e.管理界面基本介绍
dc1:数据中心名称 datacenter 默认为:dc1
指定数据中心启动consul agent -dev -datacenter=abc
services:当前consul服务中注册服务列表︰默认:client server同时启动自己注册自己会出现一个consul服务nodes:用来查看consul的集群节点
f:推荐写个bat文件执行
<!--web-->
<dependencies>
<dependency> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--consul client-->
<dependency> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
server.port=9999
#指定服务名称
spring.application.name=ORDERS
# consul server 服务注册地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
@SpringBootApplication //代表这是一个springboot入口应用
@EnableDiscoveryClient //作用:通用服务注册客户端注解代表consul client zkclient nacos client
解决:
<!-- 健康检查依赖 actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
定义:基于单体应用围绕业务进行服务拆分,拆分出来每一个服务独立应用独立运行独立都署运行在自己计算机进程中基于分布式服务管理
a.Http Rest 方式 使用http协议进行数据传输 JSON (spring cloud 使用HTTP协议传递数据)
b.RPC 方式 远程过程调用 二进制
OST : 物理层 数据链路层 网络层 传输层(RPC) 会话层 表示层 应用层(Http)
a.spring框架提供Httpclient对象RestTemplate发起一个http请求
a.开发两个测试服务用户服务users & 订单服务orders
b.用户服务 订单服务 都是两个独立springboot应用
c.两个服务都引入consul client 依赖 & 健康检查依赖
<!--web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--consul client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--健康检查 actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
d.配置两个服务 application.properties
consul server 服务注册地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
e.在入口类加入服务注册 client注解
@SpringBootApplication //代表这是一个springboot入口应用
@EnableDiscoveryClient //作用:通用服务注册客户端注解代表consul client zkclient nacos client
a.
b.解决restTempalte负载均衡问题?
1.自定义负载均衡解决策略
问题:
1.1.无法实现服务健康检查
1.2.负载均衡策略过于单一(随机)
2.Ribbon springcloud-netflix-ribbon
作用:负载均衡客户端组件 就是用来实现请求调用时负载均衡
c.Ribbon负技均衡原理
通过源码得知Ribbon底层负载均衡策略父接口IRule父接口,在这个父接口中提供很多负载均衡策略轮询 随机 根据响应时间加权 默认是轮询
d.使用Ribbon+RestTemplate实现请求负载均衡
1.使用用户调用订单服务用户服务中引入ribbon依赖
注意:
consul client依赖中已经存在ribbon相关依赖无需项目中显示引入
@Autowired //服务注册与发现客户端对象
private DiscoveryClient discoveryClient;
@Autowired //负载均衡客户端对象
private LoadBalancerClient loadBalancerClient;
使用discovery Client形式调用+RestTemplate
原理:
服务发现客户端对象根据服务id去服务注册中心获取对应服务服务列表到本地中
缺点:没有负载均衡需整自己实现鱼载均衡
//获取服务集合
List<ServiceInstance> orders1 = discoveryClient.getInstances("ORDERS");
使用loadBalance Client形式调用+RestTemplate
原理:
负载均衡客户端对象根据服务id去服务注册中心获取对应服务列表,根据默认负载均衡策略选择列表中一台机器进行返回
缺点:
使用时需要每次先根据服务id获取一个负载均衡机器之后再通过restTemplate调用服务
根据负载均衡策略选取某一个服务调用
ServiceInstance orders2 = loadBalancerClient.choose("ORDERS");
使用@loadBalanced+RestTemplate
缺点:路径写死在代码中不利于维护
//1.整合restTemplate + ribbon
修饰范围:用在方法上作用:让当前方法当前对象具有ribbon负载均衡特性
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
//2.调用服务位置注入RestTemplate
@Autowired
private RestTemplate restTemplate;
//3.调用
String forObject = restTemplate.getForObject("http://ORDERS/order", String.class);
log.info("order响应信息: {}",forObject);
1.为什么使用OpenFeign
2.什么Feign组件----->openFeign组件
历史: Feign (Netflix)---->维护状态---->SpringaCloud OpenFeign( spring) 这两个组件现在使用:特性使用方式—致
简介:
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign
注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,默认实现了负载均衡的效果并且springcloud为feign添加了springmvc注解的支持。
3.使用openFeign
3.1.创建两个springboot 服务 category product
3.2.引入依赖
<!--web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--consul client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--健康检查 actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3.3.创建application.properties配置文件
server.port=8088
spring.application.name=CATEGORY
# consul server 注册中心
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
3.4.在入口类加入注解开启OpenFeign支持
@SpringBootApplication //代表这是一个springboot入口应用
@EnableDiscoveryClient //作用:通用服务注册客户端注解代表consul client zkclient nacos client
@EnableFeignClients //开启openFeign客户端调用
public class CategoryApplication {
public static void main(String[] args) {
SpringApplication.run(CategoryApplication.class,args);
}
}
4.openFeign 服务使用
4.1.在服务调用方法中引入依赖OpenFeign依赖
<!--Open Feign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
4.2.在category服务中创建一个客户端调用接口
```java
@FeignClient("PRODUCTS")
public interface ProductClient {
@GetMapping("test")
String test();
}
4.3.在category服务中使用feignClient客户端对象调用服务
@RestController
public class CategoryController {
@Autowired //注入客户端对象
private ProductClient productClient;
@GetMapping("category")
public String test(){
String p1 = productClient.test();
return "test ok!"+p1;
}
}
4.4.在product服务中
@RestController
public class ProductController {
private static final Logger log = LoggerFactory.getLogger(ProductApplication.class);
@GetMapping("test")
public String test(){
return "product ok!!";
}
}
4.5.浏览器访问
http://localhost:8088/category
1.微服务架构中服务间通信手段
http协议: springcloud两种方式:
1.1.RestTeamplate + Ribbon
1.2.openFeign 推荐
2.服务间通信,参数传递和响应处理
参数传递:
3.零散参数传递
@FeignClient("PRODUCTS")
public interface ProductClient {
//test1?name=dasuan&age=18 @RequestParam方式 注意:注解必须要添加,由于openfeign底层是使用http传参,在这里必须要通过注解告诉openfeign底层该使用哪个方式去对参数处理
@GetMapping("test1")
String test1(@RequestParam("name") String name,@RequestParam("age") Integer age);
//test2/1/dasuan @PathVariable 方式
@GetMapping("test2/{id}/{name}")
String test2 (@PathVariable("id") Integer id,@PathVariable("name") String name);
}
4.对象参数传递
注意:
//传递对象 @RequestBody 方式 application/json
@GetMapping("test3")
String test3(@RequestBody Product product);
5.数组参数传递
**注意:**在openFeign传递数组类型参数时必须在声明时使用@RequestPar am注解标识
//传递一个数组类型 /test4?ids=21&ids=22
@GetMapping("test4")
String test4(@RequestParam("ids") String[] ids);
6.集合类型的参数接收
a.在openfeign中使用
//在openfeign中调用 /test5?ids=21&ids=22
@GetMapping("/test5")
String test5(@RequestParam("ids") String [] ids);
//springmvc不能直接接受集合类型参数,如果想要接收集合类型参数必须将集合放入对象中,使用对象的方式接收才行
//oo: oriented(面向)object(对象)面向对象
//vo (value object):用来传递数据对象称之为值对象
//dto: (data transfer (传输)object):数据传输对象
@GetMapping("test5")
public String test5(CollectionVo collectionVo){
collectionVo.getIds().forEach(id->log.info("id:{}",id));
return "test5 ok";
}
7.模仿分页信息发送与接收
a.在openfeign中使用
@GetMapping("/test6")
Map<String, Object> tset6(@RequestParam("page") Integer page,@RequestParam("pageSize") Integer pageSize,@RequestParam("categoryId") Integer categoryId);
b.在被调用的服务中
@GetMapping("test6")
public Map<String, Object> test6(Integer page,Integer pageSize,Integer categoryId){
log.info("page:{}------pageSize:{}-----categoryId:{}",page,pageSize,categoryId);
List<Product> list = new ArrayList();
list.add(new Product(1,"大蒜",1999.8));
list.add(new Product(2,"小馨",8888.8));
int total=100;
Map<String, Object> map = new HashMap();
map.put("total",total);
map.put("list",list);
return map;
}
13.openfeign细节
1.openFeign默认超时处理
默认的调用超时:
使用openFeign组件在进行服务间通信时要求被调用服务必须在1s内给予响应,一旦服务执行业务逻辑时间超过1s ,openFeign组件将直接报错:
Read timed out executing GET http:/ /PRODUcT/product
2 .修改openFeign超时时间
a.指定服务修改某个服务调用超时时间
feign.client.config.PRODUCTS.readTimeout=5000 #配置指定服务连接超时
feign.client.config.PRODUCTS.readTimeout=5000 #配置指定服务等特超时
b.修改openfeign默认调用所有服务超时间
feign.client.config.default.connectTimeout=5000 #配智所有服务连接超时
feign.client.config.default.readTimeout=5000 #配置所有服务等待超时
3 . openFeign日志展示
OpenFeign伪HttpClient客户端对象,用来帮助我们完成服务间通信,底层用http协议完成服务间调用
日志:openFeign为了更好方便在开发过程中调试openFeign数据传递,和响应处理, openFeign在设计时添加了日志功能,默认openFeign白志功能需要手动开启的
日志使用:
logging.level.com.baizhi.feignclient=debug
HONE
:不记录任何白志BASIC
:仅仅记录请求方法,url,响应状态代码及执行时间HEADERS
记录Basic级别的基础上,记录请求和响应的headerFULL
:记录请求和响应的header,body和元数据 展示全部http协议状态feign.client.config.PRODUCTS.loggerLevel=full #开启指定服务日志展示
feign.client.config.default.loggerLevel=full #全局开启服务日志展示
1.服务雪崩
现象:
在微服务之间进行服务调用是由于某一个服务故障,导致级联服务故障的现象,称为雪崩效应。雪崩效应描述的是提供方不可用,导致消费方不可用并将不可用逐渐放大的过程
而此时,Service A的流量波动很大,流量经常会突然性增加!那么在这种情况下,就算Service A能扛得住请求,Service
B和Service C未必能扛得住这突发的请求。此时,如果Service C因为抗不住请求,变得不可用。那么Service
B的请求也会阻塞,慢慢耗尽Service B的线程资源,Service B就会变得不可用。紧接着,Service
A也会不可用,这一过程如下图所示
“熔断器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器(hystrix)的故障监控,某个异常条件被触发,直接熔断整个服务。向调用方法返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,就保证了服务调用方的线程不会被长时间占用,避免故障在分布式系统中蔓延,乃至雪崩。如果目标服务情况好转则恢复调用。服务熔断是解决服务雪崩的重要手段。
服务降级说明:
服务压力剧增的时候根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚至大部分任务客户能得到正确的响应。也就是当前的请求处理不了了或者出错了,给一个默认的返回。服务降级: 关闭微服务系统中某些边缘服务 保证系统核心服务正常运行 12 淘宝 京东 删除订单 — 关闭订单 确认收货
----> 服务繁忙,!!!
1.共同点
- 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
- 最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
- 粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
- 自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;sentinel
2.异同点
- 触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
- 管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务边缘服务开始)
3.总结
- 熔断必会触发降级,所以熔断也是降级一种,区别在于熔断是对调用链路的保护,而降级是对系统过载的一种保护处理
15.Hystrix组件(防雪崩利器)
<!--引入hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
b. 开启熔断功能在入口类加入注解
@SpringBootApplication
@EnableDiscoveryClient //服务注册中心客户端
@EnableCircuitBreaker //开启hystrix服务熔断
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class,args);
}
}
c.在控制器方法中加入备选处理
@GetMapping("/hystrix")
@HystrixCommand(fallbackMethod = "testBreakFall" )
public String testBreak(int id){
log.info("接收的商品id为: "+ id);
if(id<=0){
throw new RuntimeException("数据不合法!!!");
}
return "当前接收商品id: "+id;
}
public String testBreakFall(int id){
return "当前数据不合法: "+id;
}
1、 当满足一定的阀值的时候(默认10秒内超过20个请求次数)
2、 当失败率达到一定的时候(默认10秒内超过50%的请求失败)
3、 到达以上阀值,断路器将会开启
4、 当开启的时候,所有请求都不会进行转发
5、一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5。
#开启openfeign 在调用服务过程中开启hystrix支持 默认:没有开启
feign.hystrix.enabled=true
@FeignClient(value = "PRODUCTS",fallback = ProductFallBack.class)
public interface ProductClient {
@GetMapping("test")
String test(@RequestParam("id") Integer id);
}
@Component
public class ProductFallBack implements ProductClient {
@Override
public String test(Integer id) {
return "我是客户端的Hystrix服务实现!!!---id:"+id;
}
}
The hystrix-dashboard component of this project has been deprecated and moved to
替换产品:letflix- skunkworks /hystrix-dashboard.
springcloud gateway
-gateway: 动态路由 服务统─管理 请求过滤
-gateway = 路由转发(router)+请求过滤(filter)
gateway 网关使用
注意:去掉项目springboot-starter-web存在冲突
<!--引入gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
spring:
application:
name: gateway
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: user_route # 指定路由唯一标识
uri: http://localhost:8088/ # 指定路由服务的地址
predicates:
- Path=/test/** # 指定路由规则
server:
port: 7979
现有路由配置方式,都是基于服务地址写死的路由转发,能不能根据服务名称进行路由转发同时实现负载均衡的呢?
spring:
application:
name: gateway
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: user_route
#uri: http://localhost:9999/
uri: lb://users # lb代表转发后台服务使用负载均衡,users代表服务注册中心上的服务名
predicates:
- Path=/user/**
- id: product_route
#uri: http://localhost:9998/
uri: lb://products # lb(loadbalance)代表负载均衡转发路由
predicates:
- Path=/product/**
discovery:
locator:
enabled: true #开启根据服务名动态获取路由
After=2020-07-21T11:33:33.993+08:00[Asia/Shanghai] `指定日期之后的请求进行路由
Before=2020-07-21T11:33:33.993+08:00[Asia/Shanghai] `指定日期之前的请求进行路由
Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
Cookie=username,chenyn `基于指定cookie的请求进行路由
Cookie=username,[A-Za-z0-9]+
基于指定cookie的请求进行路由
curl http://localhost:8989/user/findAll --cookie “username=zhangsna”Header=X-Request-Id, \d+ ``基于请求头中的指定属性的正则匹配路由(这里全是整数) `curl http://localhost:8989/user/findAll
-H “X-Request-Id:11”Method=GET,POST `基于指定的请求方式请求进行路由
官方更多: https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.3.RELEASE/reference/html/#the-cookie-route-predicate-factory
spring:
application:
name: gateway
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: user_route
#uri: http://localhost:9999/
uri: lb://users
predicates:
- Path=/user/**
- After=2020-07-21T11:39:33.993+08:00[Asia/Shanghai]
- Cookie=username,[A-Za-z0-9]+
- Header=X-Request-Id, \d+
<!--引入统一配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
server.port=7878
spring.application.name=configserver
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.config.server.git.uri=https://github.com/chenyn-java/configservers.git //指定仓库的url
spring.cloud.config.server.git.default-label=master //指定访问的分支
#spring.cloud.config.server.git.username= 私有仓库访问用户名
#spring.cloud.config.server.git.password= 私有仓库访问密码
@SpringBootApplication
@EnableConfigServer
public class ConfigserverApplication {
public static void main(String[] args) {
SpringApplication.run(Configserver7878Application.class, args);
}
}
注意:
如果匹配文件名不可以找到,则返回公共配置文件信息;如果可以找到,则返回此配置文件信息和公共配置文件信息的组合
<!--引入config client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
spring.cloud.config.discovery.enabled=true #开启统一配置中心服务
spring.cloud.config.discovery.service-id=CONFIGSERVER #指定统一配置服务中心的服务唯一标识
spring.cloud.config.label=master #指定从仓库的那个分支拉取配置
spring.cloud.config.name=client #指定拉取配置文件的名称
spring.cloud.config.profile=dev #指定拉取配置文件的环境
- client.properties //用来存放公共配置
spring.application.name=configclient
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
- client-dev.properties //用来存放研发相关配置 注意:这里端口为例,以后不同配置分别存放
server.port=9099
- client-prod.properties //用来存放生产相关配置
server.port=9098
b.报错原因:
项目中目前使用的是application.properties启动项目,使用这个配置文件在springboot项目启动过程中不会等待远程配置拉取,直接根据配置文件中内容启动,因此当需要注册中心,服务端口等信息时,远程配置还没有拉取到,所以直接报错
c.解决方法
将配置文件名称修改为bootstrap.properties
为什么配置手动刷新
当远端git仓库中配置发生变化时,不需要重启微服务就可以直接读取远端修改之后配置信息,这种就叫手动配置届新
配置手动刷新
a.在config client端加入刷新暴露端点
management.endpoints.web.exposure.include=* #开启所有web端点暴露
@RestController
@RefreshScope
@Slf4j
public class TestController {
@Value("${name}")
private String name;
@GetMapping("/test/test")
public String test(){
log.info("当前加载配置文件信息为:[{}]",name);
return name;
}
}
c.手动调用刷新配置接口
curl -X POST http://localhost:9099/actuator/refresh
未完待续…持续更新中…