Spring Cloud微服务
一 微服务架构
- 拆分粒度更微小、服务更独立、服务之间往往通过Restfu轻量级通信。
- 微服务架构强调的⼀个重点是业务需要彻底的组件化和服务化。
二 Spring Cloud 综述
-
Spring Cloud其实是一套规范,是一套用于构建微服务架构的规范。
-
Spring Cloud 解决什么问题:
- Distributed/versioned configuration (分布式/版本化配置)
- Service registration and discovery (服务注册和发现)
- Routing (智能路由)
- Service-to-service calls (服务调用)
- Load balancing (负载均衡)
- Circuit Breakers (熔断器)
- Global locks (全局锁)
- Leadership election and cluster state ( 选举与集群状态管理)
- Distributed messaging (分布式消息传递平台)
三 Spring Cloud 架构
3.1 Spring Cloud 核心组件
3.2 Spring Cloud 体系结构(组件协同工作机制)
- 消费方、提供方注册到注册中心。
- API网关(gateway)负责转发所有外来的请求。
- 配置中心提供了统一的配置信息管理服务,可以实时的通知各个服务获取最新的配置信息。
3.3 Spring Cloud 与 Dubbo 对比
- Spring Cloud Netflix是基于HTTP的,所以效率上没有Dubbo高(TCP、UDP),但前者具有Sprign大家族背景,能提供一站式服务解决方案。
四 Spring Cloud核心组件
4.1 Eureka注册中心
1. 基础架构图
- 微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒,默认Eureka Server 90S会将还没有续约的给剔除)以续约自己的信息。30S续约,90S滚蛋。
- Eureka通过心跳检测、健康检查和客户端缓存等机制,提高系统的灵活性、可伸缩性和高可用性。
2.搭建注册中心
server:
port: 9300
spring:
application:
name: lagou-cloud-eureka-server # 应用名称,会在Eureka中作为服务的id标识
eureka:
instance:
prefer-ip-address: true #自定义实例显示格式
instance-id: ${spring.cloud.client.ipaddress}:${spring.application.name}:${server.port}:@project.version@
client:
serviceurl:
defaultZone: http://127.0.0.1:9301/eureka #集群情况相互注册
register-with-eureka: true # 注册服务
fetch-registry: false #自己就是服务不需要从Eureka Server获取服务信息,默认为true
- 启动类使用:
- @EnableEurekaServer注解。声明当前项目为Eureka服务
3. 元数据定义
-
使用eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。
-
获取:
List<ServiceInstance> instances = discoveryClient.getInstances("lagouservice-page");
instance.getMetadata().entrySet();//转为key value视图
4. 自我保护机制
- 如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么 Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现 以下几种情况:
- 不再移除过期服务。
- 仍可注册、查询,但不会同步。
- 网络恢复后,再同步信息到其余节点。
4.2 Ribbon负责均衡
-
启动类添加:@EnableDiscoveryClient,声明当前是Eurake客户端。
-
使用restTemplate调用时,直接在生成Bean接口上添加@LoadBalanced即可。
1. 负责均衡策略一览
2. 修改负载均衡策略
#针对的被调用方微服务名称,不加就是全局生效
lagou-service-goods:
ribbon:
ReadTimeout: 5000 # 超时时间
MaxAutoRetries: 0 #对当前选中实例重试次数,不包括第一次调用
MaxAutoRetriesNextServer: 0 #切换实例的重试次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #随机策略
4.3 Hystrix熔断器
- 启动类:@EnableCircuitBreaker。
/**
* 注解简化写法
* @SpringCloudApplication =
@SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker
*/
- 一种容错机制。
- 服务雪崩效应:是一种因“服务提供者的不可用”(原因)导致“服务调用者不可用”(结果),并将不可用逐渐放大的现象。
1. 熔断+服务降级
- 所有熔断方法使用一个Hystrix线程池(10个线程),那么这样的话会导致因线程机制导致服务不可用。
- 解决办法:为每个方法创建一线程池,取代默认的所有方法维护一个线程池。
@HystrixCommand(
// 线程池标识,要保持唯一,不唯一的话就共用了
threadPoolKey = "getProductServerPort3TimeoutFallback",
// 线程池细节属性配置
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "2"), // 线程数
@HystrixProperty(name = "maxQueueSize", value = "100") // 等待队列长度
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "80") // 队列最大阈值
},
commandProperties = {
//超时时间
@HystrixProperty(name ="execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
fallbackMethod = "myFallBack" // 回退方法
)
@RequestMapping("/getPort3")
public String getProductServerPort3() {
String url = "http://lagou-service-product/server/query";
return restTemplate.getForObject(url, String.class);
}
/**
* 定义回退方法,返回预设默认值
* 注意:该方法形参和返回值与原始方法保持一致
*/
public String myFallBack() {
return "-1"; // 兜底数据
}
2. 高级应用+自我修复
-
出现问题,开启时间窗(10S)。
-
10S内是否达到最新请求数?
-
没达到,回到1。
-
达到:失败占比是否达到阈值?
-
未达到,回到1
-
达到:熔断
-
-
-
熔断后,开启活动窗口(默认5s)。每隔5s,Hystrix会让一个请求通过,到达那个问题服务,看是否调用成功,如果成功,重置断路器回到第1步,如果失败,回到第3步
/**
* 8秒钟内,请求次数达到2个,并且失败率在50%以上,就跳闸
* 跳闸后活动窗口设置为3s(3S通过一个请求,检测是否可用)
*/
@HystrixCommand(
commandProperties = {
//统计窗口时间的设置
@HystrixProperty(name ="metrics.rollingStats.timeInMilliseconds",value = "8000"),
//统计窗口内的最小请求数
@HystrixProperty(name ="circuitBreaker.requestVolumeThreshold",value = "2"),
//统计窗口内错误请求阈值的设置 50%
@HystrixProperty(name ="circuitBreaker.errorThresholdPercentage",value = "50"),
//自我修复的活动窗口时间
@HystrixProperty(name ="circuitBreaker.sleepWindowInMilliseconds",value = "3000")
}
)
3.提取到配置文件
# 配置熔断策略:
hystrix:
command:
default:
circuitBreaker:
forceOpen: false # 关闭强制开启熔断器
# 触发熔断错误比例阈值,默认值50%
errorThresholdPercentage: 50
# 熔断后休眠时长,默认值5秒
sleepWindowInMilliseconds: 3000
# 熔断触发最小请求次数,默认值是20
requestVolumeThreshold: 2
execution:
isolation:
thread:
# 熔断超时设置,默认为1秒
timeoutInMilliseconds: 2000
4. 服务暴露健康检测等端口
# springboot中暴露健康检查等断点接口
management:
endpoints:
web:
exposure:
include: "*"
- 访问健康检查接口:http://localhost:9100/actuator/health
5. 最大请求数优化
- 之前关于hystrix线程池配置了队列最大等待长度:maxQueueSize。
- 但Hystrix还有一 个queueSizeRejectionThreshold属性,这个属性是控制队列最大阈值的,两个属性必须同时设置。
- 正确配置:
# 将核心线程数调低,最大队列数和队列拒绝阈值的值都设置大一点:
hystrix:
threadpool:
default:
coreSize: 10
maxQueueSize: 1500
queueSizeRejectionThreshold: 1000
4.4 Feign远程调用组件
-
Feign是Netflix开发的一个轻量级RESTful的HTTP服务客户端(用它来发起请求,远程调用)
-
Feign = RestTemplate+Ribbon+Hystrix
-
启动类:添加@EnableFeignClients、消除@EnableCircuitBreaker。(前者自动引入)
1. 创建Feign接口
@FeignClient(name="lagou-service-product",fallback = ProductFeignFallBack.class)
public interface ProductFeign {
/**
* 获得端口号
* @return
*/
@RequestMapping("/server/query")
public String findServerPort();
}
2. 创建降级返回类
- 实现Feign接口
@Component
public class ProductFeignFallBack implements ProductFeign {
@Override
public String findServerPort() {
return "这是Feign的降级返回数据";
}
}
3. 远程调用
/**
* Feign远程调用
* 负载均衡+服务熔断降级
* 有无休眠+有无降级返回数据
*/
@GetMapping("/getServicePortByFeign")
public String getProductByFeign(){
return productFeign.findServerPort();
}
- name与服务提供方名称相同。
- 对于负载均衡,Feign本身完成了自动配置,在ribbon直接配置即可。
4.熔断策略
- 开启熔断
# 开启Feign的熔断功能
feign:
hystrix:
enabled: true
- Feign的超时时长设置那其实就上面Ribbon的超时时长。
- 针对超时这一点,当前有两个超时时间设置(Feign/hystrix),熔断的时候是根据这两个时间的最小值来进行的,即处理时长超过最短的那个超时时间了就熔断进入回退降级逻辑。
5.Feign对请求压缩和响应压缩的支持
- Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数 即可开启请求与响应的压缩功能
feign:
#开启请求和响应压缩
compression:
request:
enabled: true #默认不开启
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型,处也是默认值
min-request-size: 2048 # 设置触发压缩的大小下限,此处也是默认值
response:
enabled: true #默认不开启
4.5 GateWay
- Spring Cloud GateWay不仅提供统一的路由方式(反向代理)并且基于 Filter(定义过滤器对请求过 滤,完成一些功能) 链的方式提供了网关基本的功能,例如:鉴权、流量控制、熔断、路径重写、日志监控等。
1. 配置文件
spring:
application:
name: lagou-cloud-gateway
#配置网关
cloud:
gateway:
routes:
- id: lagou-service-product
# 动态路由(负载均衡) lb代表从注册中心获取服务
uri: lb://lagou-service-product
# 断言匹配成功,转发给相应的微服务
predicates:
- Path=/product/**
filters:
- StripPrefix=1 #去掉uri中的第一部分(匹配断言字段)
- 发送接口:
http://127.0.0.1:9501/product/product/query/1
- 断言规则有许多,时间、cookie、Header、Method、Path、QueryParam、RemoteAddr等。
2. GateWay过滤器
- pre:调用路由之前。
- post路由后执行。
4.6 配置中心
- 对配置文件进行集中式管理。
- Spring Cloud Config + Spring Cloud Bus 实现自动刷新,一次通知处处生效。
1. 配置中心服务器
- 在Github上上传配置文件,如lagou-service-page-dev.yml。项目+环境。
- 引入Config依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!--消息总线支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
- 启动类添加:@EnableConfigServer // 开启配置服务器功能;并注册到注册中心。
- 配置文件:
spring:
application:
name: lagou-service-config # 应用名称,会在Eureka中作为服务的id标识
cloud:
config:
server:
git:
uri: https://github.com/用户名/项目名.git #git地址
username: 用户名
password: 密码
search-paths:
- lagou-config #项目名
label: master #分支
rabbitmq:
host: IP
port: 5672
username: 用户名
password: 密码
# springboot中暴露所以端口
management:
endpoints:
web:
exposure:
include: "*"
2. 客户端读取配置
- 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
- 配置文件:bootstrap.yml
spring:
cloud:
config:
name: application #配置文件名称
profile: dev #后缀名称
label: master #分支名称
uri: http://localhost:9400 #ConfigServer配置中心地址
rabbitmq:
host: IP
port: 5672
username: 用户名
password: 密码
- 测试类
@RestController
@RefreshScope //手动刷新
public class ConfigController {
@Value("${person.name}")
private String name;
@RequestMapping("getConfig")
public String getConfig(){
return name;
}
}
分支名称
uri: http://localhost:9400 #ConfigServer配置中心地址
rabbitmq:
host: IP
port: 5672
username: 用户名
password: 密码
- 测试类
@RestController
@RefreshScope //手动刷新
public class ConfigController {
@Value("${person.name}")
private String name;
@RequestMapping("getConfig")
public String getConfig(){
return name;
}
}
-
向配置中心服务端发送post请求,各个客户端配置即可自动刷新
-
http://127.0.0.1:9400/actuator/bus-refresh
-
定向更新:http://localhost:9006/actuator/bus-refresh/lagou-service-page:9100