# springcloud
**Repository Path**: qq_connect-sunbenbao/springcloud
## Basic Information
- **Project Name**: springcloud
- **Description**: Springcloud Hoxton SR6 环境
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2020-08-17
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## Springcloud Hoxton SR6 环境搭建
### 一. 注册中心和配置中心 Nacos
- 服务发现和服务健康监测: 支持基于 DNS 和基于 RPC 的服务发现, 支持对服务的实时的健康检查, 阻止向不健康的主机或服务实例发送请求;
- 动态配置服务: 动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置;
- 动态DNS服务: 动态 DNS 服务支持权重路由, 让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单 DNS 解析服务;
- 服务及其元数据管理: 支持从微服务平台建设的视角管理数据中心的所有服务及元数据.
### 二. 服务网关 Gateway
- 基于 Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定 Predicate(断言)和 Filter(过滤器);
- 集成 CircuitBreaker的断路器功能;
- 集成 Spring Cloud 服务发现功能;
- 易于编写的 Predicate(断言)和 Filter(过滤器);
- 请求限流功能;
- 支持路径重写。
> * Route(路由): 路由是构建网关的基本模块, 它由ID, 目标URI, 一系列的断言和过滤器组成, 如果断言为 true 则匹配该路由;
> * Predicate(断言): 指的是 Java 8 的 Function Predicate. 输入类型是Spring框架中的 ServerWebExchange. 这使开发人员可以匹配 HTTP 请求中的所有内容, 例如请求头或请求参数, **如果请求与断言相匹配,则进行路由**;
> * Filter(过滤器): 指的是Spring框架中 GatewayFilter 的实例, 使用过滤器, **可以在请求被路由前后对请求进行修改**。
##### 自定义过滤器
- 自定义GatewayFilter有两种实现方式
1.直接实现GatewayFilter接口, 并在RouteLocatorBuilder加上配置
```java
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
// GatewayFilter 需要配置上加入到路由
return builder.routes()
.route(r -> r.path("/authFilter/**")
.filters(f -> f.filter(new AuthorizeGatewayFilter(stringRedisTemplate))
.addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
.uri("lb://web")
.order(0)
.id("customer_filter_router")
)
.build();
}
```
2.继承AbstractGatewayFilterFactory类, 并在配置文件配置
```yaml
- id: authorize_filter_router
uri: lb://web
order: -2
predicates:
- Path=/authorizeFilter/**
filters:
- name: Authorize
args:
withParams: true
```
- 实现GlobalFilter接口
不需要配置文件中配置, 系统初始化时加载, 作用在所有的路由上
最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
##### 查看路由配置
添加Spring Boot Actuator依赖并将 gateway 端点暴露
端点都在路径 /actuator/gateway/, 例如routes全路径/actuator/gateway/routes
| ID | HTTP Method | Description |
| ------------- | --------------- | -------------------- |
| globalfilters | GET | 展示所有的全局过滤器 |
| routefilters | GET | 展示所有的过滤器工厂(GatewayFilterFactory)|
| refresh | POST[无消息体] | 清空路由缓存 |
| routes | GET | 展示路由列表 |
| routes/{id} | GET | 展示指定id的路由信息 |
| routes/{id} | POST[消息体如下] | 新增一个路由 |
| routes/{id} | DELETE[无消息体] | 删除一个路由 |
其中,要想动态添加路由配置,只需发送POST请求,消息体如下:
```json
{
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/test"
}
}
],
"filters": [
{
"name": "AddRequestHeader",
"args": {
"_genkey_0": "X-Request-Foo",
"_genkey_1": "Bar"
}
}
],
"uri": "https://www.google.com",
"order": 0
}
```
##### 内置Gateway过滤器工厂
详细介绍 https://blog.csdn.net/ooyhao/article/details/102810320
### 三. 服务调用 OpenFeign
##### 配置Feign
添加 @EnableFeignClients 注解
```yaml
feign:
# 开启sentinel熔断
sentinel:
enabled: true
compression:
request:
# 是否对请求进行GZIP压缩
enabled: false
# 指定压缩的请求数据类型
mime-types: text/xml,application/xml,application/json
# 超过该大小的请求会被压缩
min-request-size: 2048
response:
# 是否对响应进行GZIP压缩
enabled: false
```
##### FeignClient打印请求日志
1. 配置FeignConfiguration
```java
@Configuration
public class FeignConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
//这里记录所有,根据实际情况选择合适的日志level
return Logger.Level.FULL;
}
}
```
2. 指定配置类
@FeignClient==> configuration 配置类
3. 修改日志级别
yml文件添加Feign接口日志级别为debug
```yaml
logging:
level:
com.verlet.web.fegin.NacosFeignService: debug
```
### 四. 熔断与限流 Sentinel
- 丰富的应用场景: 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀,可以实时熔断下游不可用应用;
- 完备的实时监控: 同时提供实时的监控功能。可以在控制台中看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况;
- 广泛的开源生态: 提供开箱即用的与其它开源框架/库的整合模块, 例如与 Spring Cloud、Dubbo、gRPC 的整合;
- 完善的 SPI 扩展点: 提供简单易用、完善的 SPI 扩展点. 您可以通过实现扩展点,快速的定制逻辑.
##### 限流功能
Sentinel Starter 默认为所有的 HTTP 服务提供了限流埋点, 没有指定使用默认的限流, 返回 429 Too Many Requests
###### 限流规则
> Sentinel目前的规则是存在客户端应用内存中的,重启之后设置的规则消失
使用配置文件配置流控规则, 使用Nacos配置中心(推荐)时是推模式, 会自动更新规则
- resource:资源名,即限流规则的作用对象
- count: 限流阈值
- grade: 限流阈值类型(0表示线程数, 1表示QPS), 默认QPS
- limitApp: 流控针对的调用来源,若为 default 则不区分调用来源(针对上级微服务)
- strategy: 调用关系限流策略(0表示直接, 1表示关联, 2表示链路), 默认直接
* 直接(默认):接口达到限流条件时,开启限流
* 关联:当关联的资源达到限流条件时,开启限流(适合做应用让步,保证关联的资源正常)
* 链路:当从某个接口过来的资源达到限流条件时,开启限流(针对上级接口和limi tApp相似,但是更加细粒度)
- controlBehavior: 流量控制效果(0表示快速失败, 1表示Warm Up, 2表示排队等待), 默认快速失败
* 快速失败:直接失败,抛出限流异常,不做任何额外的处理
* Warm Up: 从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,慢慢增大,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景
* 排队等待:让请求以匀速通过,单机阈值为每秒通过数量,其余的排队等待;设置一个超时时间,当请求超过超时时间还未处理,则丢弃
- clusterMode: 是否集群
- clusterConfig: 集群配置, 参考com.alibaba.csp.sentinel.slots.block.flow.ClusterFlowConfig
```json
[
{
"resource": "byResource",
"controlBehavior": 0,
"count": 1,
"grade": 1,
"limitApp": "default",
"strategy": 0
}
]
```
##### 熔断降级功能
Sentinel 支持对服务间调用进行保护,对故障应用进行熔断操作.
1. 服务请求熔断
```java
@SentinelResource 自定义处理异常, 没有指定使用Sentinel默认异常处理
blockHandler 五种规则处理方法
blockHandlerClass 处理类(默认当前类),注意对应的函数必需为 static 函数
defaultFallback 同时配置fallback,此方法会失效
fallback 发生Throwable执行的方法
fallbackClass 发生Throwable执行类(默认当前类),注意对应的函数必需为 static 函数
exceptionsToIgnore 忽略某些异常
```
fallback对应的异常是Throwable,blockHandler对应的BlockException,范围fallback > blockHandler
2. RestTemplate 熔断
使用@SentinelRestTemplate来包装下RestTemplate实例
```java
@Bean
@LoadBalanced
@SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
```
3. @FeignClient 熔断
feign启用sentinel熔断,并fallback或者fallbackFactory 参数配置熔断处理
```yaml
feign:
sentinel:
enabled: true
```
###### 降级规则
Sentinel提供降级规则有两个:
1. 平均响应时间(RT):当资源的平均响应时间超过阀值(单位ms)之后,资源进入准降级状态,如果接下来1S内持续进去5个请求,他们的RT都持续超过这个阀值,那么在接下来的窗口(单位s)之内,就会对这个方法进行服务降级。
> 注意Sentinel默认统计的RT上限是4900ms,超出此阀值的都会算作4900ms,若需要变更此上限可以通过启动配置项 -Dscp.sentinel.statistic.max.rt=xxx 来配置
2. 异常比例:当资源的每秒异常总数占通过量的比例值超过阀值之后,资源进入降级状态,即在接下来的时间窗口(单位s)之内,对这个方法的调用都会自动地返回。
##### 热点规则
热点参数流控规则是一种更加细粒度的流控规则,他允许将规则具体到参数上。
注意点,需要指定要资源,不是使用默认的路径资源。
1. 参数索引:需要限流的参数索引
2. 限流阀值:QPS 限流的阀值
3. 参数例外项:可以更加细粒度根据参数值来限流
##### 授权规则
根据资源的请求来源(流控应用)限制资源是否通过。
1. 配置白名单:只有请求来源于白名单内时才可通过
2. 配置黑名单:请求来源位于黑名单时才通过,其余的请求通过
流控应用,是来源标识,Sentinel提供了**RequestOriginParser**接口来处理来源。
只要Sentinel保护的接口资源被访问,就会调用此实现类去解析访问来源。
```java
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
// 返回来源标识
return httpServletRequest.getParameter("serviceName");
}
}
```
##### 系统规则
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体Load,RT,入口QPS,CPU使用率和线程数五个监控维度,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是引用整体维度的,而不是资源维度的,并且仅对入口流量(进入应用的流量)生效。
- Load(仅对Linux/Unix-like生效):当系统load1(平均一分钟)超过阀值,且系统当前的并发现场数超过系统容量时才会触发系统保护。系统容量有系统的maxQps * minRt计算的。设定参考值一般是:CPU cores*2.5。
- RT:当单台机器上所有入口流量的平均RT达到阀值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阀值即触发系统保护。
- 入口QPS:当单台机器上所有入口流量的QPS达到阀值即触发系统保护。
- CPU使用率:当单台机器上所有入口流量的CPU使用率达到阀值即触发系统保护。
##### Sentinel全局异常配置
实现Sentinel提供的**BlockExceptionHandler**接口
其中BlockException有五个异常的子类:
- AuthorityException
- DegradeException
- FlowException
- ParamFlowException
- SystemBlockException
##### 规则配置类
```java
// 规则类型
public enum RuleType {
// 控流规则
FLOW("flow", FlowRule.class),
// 降级规则
DEGRADE("degrade", DegradeRule.class),
// 热点参数限流规则
PARAM_FLOW("param-flow", ParamFlowRule.class),
// 系统规则
SYSTEM("system", SystemRule.class),
// 权限规则
AUTHORITY("authority", AuthorityRule.class),
// 网关控流规则
GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
// 网关API控流规则
GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
}
```

- FlowRule 控流规则配置类
- DegradeRule 降级规则配置类
- ParamFlowRule 热点参数限流规则配置类
- SystemRule 系统规则配置类
- AuthorityRule 权限规则配置类
##### 使用Resilience4j
详细使用地址 https://blog.csdn.net/zhxdick/article/details/106566509?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1
### 五. 服务链路追踪 Spring Cloud Sleuth
SpringCloud Sleuth主要功能就是在分布式系统中提供追踪解决方案。它大量借用了Google Dapper的设计, 先来了解一下Sleuth中的术语和相关概念。
- Trace:由一组Trace Id相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即TraceId),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
- Span:代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(SpanId)来标记它的开始、具体过程和结束。通过SpanId的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称。请求信息等元数据。
- Annotation:用它记录一段时间内的事件,内部使用的重要注释:
- cs(Client Send)客户端发出请求,开始一个请求的生命
- sr(Server Received)服务端接受到请求开始进行处理, sr - cs = 网络延迟(服务调用的时间)
- ss(Server Send)服务端处理完毕准备发送到客户端, ss - sr = 服务器上的请求处理时间
- cr(Client Reveived)客户端接受到服务端的响应,请求结束。 cr - sr = 请求的总时间
##### Sleuth 使用
添加 sleuth 依赖
```xml
org.springframework.cloud
spring-cloud-starter-sleuth
```
日志输出 [gateway,4591194b5502684d,4591194b5502684d,true]
可以看出 4591194b5502684d是TraceId,4591194b5502684d是SpanId,依次调用有个一个全局的TraceId,将调用链路串起来。
可以通过 Zipkin 将日志聚合,并进行可视化展示和全文检索。
##### Zipkin分布式追踪
Zipkin 是 Twitter 的一个开源项目,它基于Google Dapper实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。
Zipkin 的基础架构,它主要由 4 个核心组件构成:
- Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。
- Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。
- RESTful API: API 组件,它主要用来提供外部访问接口,比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。
- Web UI: UI 组件, 基于API组件实现的上层应用,通过UI组件用户可以方便而有直观地查询和分析跟踪信息。
###### Zipkin配置
添加 Zipkin依赖
```xml
org.springframework.cloud
spring-cloud-starter-zipkin
```
并添加配置文件
```yaml
spring:
zipkin:
baseUrl: http://127.0.0.1:9411
# 让 nacos 把它当成一个URL,而不要当成服务名
discoveryClientEnabled: false
sleuth:
sampler:
# 采样百分比
probability: 1.0
```
###### ZipKin数据持久化到MySql
首先我们需要创 ZipKin 指定的表,不过这些不需要我们主动的编写,我们可以通关官方文档拿到执行语句:[zipkin.sql](https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql)
接着在启动 Zipkin 的时候,加上链接数据库的命令就可以了。
```shell
java -jar zipkin-server-2.21.6-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 \
--MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=root
```
###### ZipKin数据持久化到Elasticsearch
在启动 Zipkin 的时候,添加 Elasticsearch 连接信息即可。
```shell
java -jar zipkin-server-2.21.6-exec.jar --STORAGE_TYPE=elasticsearch --ESHOST=localhost:9200
```
### 六. 安全保护 Spring Cloud Security
### 七. 监控中心 Spring Boot Admin
### 八. 分布式事务解决 Seata