SpringCloud
技术要求:
java8 + maven + git、github + Nginx + RabbitMQ + SpringBoot2.0
微服务架构概述
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,微服务之间互相协调、互相配合,为用户提供最终价值。每个务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的-个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K6zStySO-1612348294019)(https://spring.io/images/cloud-diagram-1a4cad7294b4452864b5ff57175dd983.svg)]
SpringCloud=分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶。
涉及到的技术:
服务注册与发现、服务调用、服务熔断、均衡负载、服务降级、服务消息队列、配置中心管理、服务网关、服务监控、全链路追踪、自动化构建部署、服务定时任务调度操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aOAgIgE5-1612348294020)(img/image-20210119181835922.png)]
Cloud升级
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-68FGFn67-1612348294022)(img/image-20210120170738994.png)]
微服务模块
1.建module
2.改POM
3.写YML
4.主启动
5.业务类
约定→配制→编码
注册中心
类比Eureka、ZooKeeper、Consul的异同点
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | SpringCloud集成 |
---|---|---|---|---|---|
Eureka | java | AP | 可配置支持 | HTTP | 已集成 |
ZooKeeper | java | CP | 支持 | HTTP/DNS | 已集成 |
Consul | go | CP | 支持 | 客户端 | 已集成 |
CAP理论
一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求。因此根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:
-
CA-单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
-
CP-满足一致性,分区容忍必的系统,通常性能不是特别高。
-
AP–满足可用性,分区容忍性的系统,通常可能对—致性要求低一些。
-
C:Consistency(数据一致性),等同于所有节点访问同一份最新的数据副本;
-
A:Availability(可用性),对数据更新具备高可用性;
-
P:Partition tolerance(分区容错性),能容忍网络分区。
AP架构
当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统的可用性。
结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PsXujOJA-1612348294023)(img/image-20210126122303897.png)]
CP架构
当网络分区出现后,为了保证一致性,就必须拒绝请求,否则无法保证一致性。
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dKRrGJqG-1612348294025)(img/image-20210126122613243.png)]
Eureka原理
在新版本中,Eureka2.0在1.0的基础上添加了新的注解,分别是@EnableEurekaServer(用于标注服务端)和@EnableEurekaClient(用于标注客户端),然后根据业务的性质,进行相关的配置(服务注册、服务发现)。
假设这里有A(consumer),B(provider)服务。当A需要去调用B时,会向eureka中获取B的服务列表(前提是做了集群的情况下)地址缓存在本地。然后根据ribbon的客户端负载均衡,从服务列表中取到一个B服务,然后去调用此B服务。若已经缓存了服务列表地址,则就不需要从Eureka服务端去获取了,直接从本地均衡负载进行调用。
这些已经注册进入Eureka中的客户端,默认没30s会向Eureka服务端发送一次心跳,作为检查的健康状态标识,如果客户端发生意外宕机、网络拥堵等状况没有及时发送心跳,Eureka服务端则会等待90s,还没有接收到的话则会认为注册的客户端已经挂掉,进行注册清除(若没有开启Eureka自我保护模式)。若开启自我保护状态,则会一直保留。
服务调用
Ribbon
Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
Ribbon的使用需要代码里手动调用目标服务,请参考官方示例:https://github.com/Netflix/ribbon
Feign
已停用,现在主流以OpenFeign替代
Feign是Spring Cloud组件中的一个轻量级RESTful
的HTTP服务客户端
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
Feign支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign
Feign本身不支持Spring MVC的注解,它有一套自己的注解
OpenFeign
OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping
等等。
OpenFeign的@FeignClient
可以解析SpringMVC的@RequestMapping
注解下的接口,
并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
Controller
package cn.fyyice.springcloud.controller;
import cn.fyyice.springcloud.entities.CommentResult;
import cn.fyyice.springcloud.entities.Payment;
import cn.fyyice.springcloud.service.PaymentFeignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author fwh
* @version 1.0
* @date 2021/1/27 11:54
* @description
*/
@RestController
@Slf4j
@RequestMapping(value = "/consumer")
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/payment/get/{id}")
public CommentResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout(){
//openfeign-ribbon 客户端一般默认等待1s
return paymentFeignService.paymentFeignTimeout();
}
}
service
package cn.fyyice.springcloud.service;
import cn.fyyice.springcloud.entities.CommentResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author fwh
* @version 1.0
* @date 2021/1/27 11:47
* @description
*/
@Component
/* 对应的微服务 application-name */
@FeignClient(value = "CLOUD-PATMENT-SERVICE")
@RequestMapping(value = "/payment")
public interface PaymentFeignService {
@GetMapping(value = "/get/{id}")
public CommentResult getPaymentById(@PathVariable("id") Long id);
@GetMapping(value = "/feign/timeout")
public String paymentFeignTimeout();
}
application.yml
server:
port: 80
eureka:
client:
# 表示是否将自己注册进EurekaServer默认为true
register-with-eureka: false
service-url:
# defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
ribbon:
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 5000
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ConnectTimeout: 5000
logging:
level:
# feign日志以什么级别监控哪个接口
cn.fyyice.springcloud.service.PaymentFeignService: debug
服务熔断
Hystrix
博文参考来CSDN博主:校长我错了
背景
在分布式的背景下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。当库存服务不可用时,商品服务请求线程被阻塞,当有大批请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链往上传递,这种现象被称为雪崩效应。
初探Hystrix
Hystrix,中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。该框架就是为了实现容错和自我保护。
设计目标:
- 对来自依赖的延迟和故障进行防护和控制——这些依赖通常是通过网络访问的。
- 阻止故障的连锁反应
- 快速失败并迅速恢复
- 回退并优雅降级
- 提供近实时的监控与告警(Hystrix-dashboard)
如何实现这些设计目标?
- 使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
- 每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
- 记录请求成功,失败,超时和线程拒绝。
- 服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
- 请求失败,被拒绝,超时或熔断时执行降级逻辑。
- 近实时地监控指标和配置的修改。
工作执行流程
图片来源Hystrix官网https://github.com/Netflix/Hystrix/wiki
- 构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在构造方法配置请求被执行需要的参数;
- 执行命令,Hystrix提供了4种执行命令的方法,后面详述;
- 判断是否使用缓存响应请求,若启用了缓存,且缓存可用,直接使用缓存响应请求。Hystrix支持请求缓存,但需要用户自定义启动;
- 判断熔断器是否打开,如果打开,跳到第8步;
- 判断线程池/队列/信号量是否已满,已满则跳到第8步;
- 执行HystrixObservableCommand.construct()或HystrixCommand.run(),如果执行失败或者超时,跳到第8步;否则,跳到第9步;
- 统计熔断器监控指标;
- 走Fallback备用逻辑
- 返回请求响应
服务降级
为接口调用提供一个兜底的方法处理。意思是当出现意料之外的情况时(服务故障、调用失败等),给用户一个友好的提示,给系统一个失败时的方法执行。
服务熔断
所谓熔断就是在一定时间范围内,接口调用失败的次数达到了一定的比例,调用方会认为服务当前处于一个不可用的状态,拒绝后续的请求继续访问该接口的提供方,避免了服务器资源的过度消耗。但这种机制不会一直持续下去,默认一段时间后,会放行一条请求(可通过注解的参数设置),若这条请求成功,这认为服务提供方已经恢复、可用,熔断机制结束,否则将继续维持熔断状态。配合使用服务降级,给用户一些友好的提示:你丫的来点正常的行不?
Hystrix的使用
1.在注解@FeignClient中添加fallbackFactory属性值(配合服务降级使用)
feign:
hystrix:
enabled: true
2.在服务接口类上添加@FeignClient
此方法需要实现所有接口的对应熔断方法。
package cn.fyyice.springcloud.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author fwh
* @version 1.0
* @date 2021/1/28 10:28
* @description
* @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class) 统一的fallback处理
fallback:PaymentFallbackService.class为接口FeignFacade的实现类,实现接口,方法内容为熔断时需要走的流程。
*/
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
@RequestMapping(value = "/payment")
public interface PaymentHystrixService {
@GetMapping(value = "/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id);
@GetMapping(value = "/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
@HystrixCommand注解
1.引入依赖坐标
#版本根据实际情况而定
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>${hystrix.version}</version>
</dependency>
2.添加注解
@HystrixCommand注解是方法级别的,在你需要捕获的方法上加上注解
fallbackMethod:标记接口执行异常时,需要执行的方法。
@GetMapping(value = "/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentInfo_TimeoutHandler(Integer id){
return "线程池:"+Thread.currentThread().getName()+ " 系统繁忙,请稍后再试,id:"+ id +" 可惜o(╥﹏╥)o 🙁 ";
}
3.启动项
添加@EnableCircuitBreaker。这个人是Hystrix的作者。
package cn.fyyice.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author fwh
* @version 1.0
* @date 2021/1/28 10:27
* @description
*/
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
网关
GateWay
ort org.springframework.cloud.openfeign.EnableFeignClients;
/**
- @author fwh
- @version 1.0
- @date 2021/1/28 10:27
- @description
*/
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
## 网关
### GateWay