mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
3.0.0
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
> 运行环境:JDK8,Maven3,[Nacos](https://nacos.io/zh-cn/docs/what-is-nacos.html),Mysql
|
||||
|
||||
- 安装并启动Nacos,[安装教程](https://nacos.io/zh-cn/docs/quick-start.html)
|
||||
- 执行Mysql脚本`sop.sql`
|
||||
- 执行Mysql脚本`sop.sql`(Mysql版本5.6+),5.6以下运行`sop-mysql5.6以下版本.sql`
|
||||
- IDE安装lombok插件,然后打开项目(IDEA下可以打开根pom.xml,然后open as project)
|
||||
- 启动网关:打开sop-gateway下的`application-dev.properties`
|
||||
1. 修改数据库`username/password`
|
||||
@@ -22,4 +22,28 @@
|
||||
|
||||
登录账号:admin/123456
|
||||
|
||||
## 启动文档中心
|
||||
|
||||
文档中心代码在sop-website工程中
|
||||
|
||||
- 确保注册中心、网关、微服务正常启动
|
||||
- 修改sop-website下的application-dev.properties相关配置
|
||||
- 运行WebsiteServerApplication.java
|
||||
- 访问http://localhost:8083
|
||||
|
||||
## 基本配置
|
||||
|
||||
在`sop-gateway`下的application-dev.properties配置,各项配置说明如下
|
||||
|
||||
```properties
|
||||
# 忽略验证,设置true,则所有接口不会进行签名校验,默认false
|
||||
sop.api-config.ignore-validate=false
|
||||
# 是否对结果进行合并,默认true
|
||||
sop.api-config.merge-result=true
|
||||
# 显示返回sign,默认true
|
||||
sop.api-config.show-return-sign=true
|
||||
# 是否开启限流功能,默认true
|
||||
sop.api-config.open-limit=true
|
||||
# 请求超时时间,默认5分钟,即允许在5分钟内重复请求,默认300
|
||||
sop.api-config.timeout-seconds=300
|
||||
```
|
@@ -1,92 +1,16 @@
|
||||
# 使用SpringCloudGateway
|
||||
|
||||
SOP默认网关是使用Spring Cloud Zuul,您也可以切换成Spring Cloud Gateway,完整代码见`spring-cloud-gateway`分支。
|
||||
|
||||
如果您的系统并发量不大,建议使用zuul,因为zuul的功能更全面,有新功能会优先实现在zuul上。
|
||||
|
||||
- SOP中 Spring Cloud Zuul 和 Spring Cloud Gateway功能对比
|
||||
|
||||
| 功能 | Spring Cloud Zuul | Spring Cloud Gateway |
|
||||
| ----- | ---- | ----------------------- |
|
||||
| 签名验证|√ | √ |
|
||||
| 统一异常处理|√ | √ |
|
||||
| 统一返回内容|√ | √ |
|
||||
| session管理|√ | √ |
|
||||
| 秘钥管理|√ | √ |
|
||||
| 微服务端自动验证(JSR-303)|√ | √ |
|
||||
| 文件上传|√ | √ |
|
||||
| 文件下载|√ | √ |
|
||||
| 接口限流|√ | √ |
|
||||
| 文档整合|√ | √ |
|
||||
| 应用授权|√ | √ |
|
||||
| 监控日志|√ | √ |
|
||||
| 支持nacos|√ | √ |
|
||||
| 网关动态修改参数|√ | √ |
|
||||
|
||||
使用Spring Cloud Gateway步骤如下:
|
||||
|
||||
- 打开sop-gateway/pom.xml,注释spring cloud zuul依赖,打开Spring Cloud Gateway依赖
|
||||
修改`sop-gateway/pom.xml`配置,artifactId部分改成`sop-bridge-gateway`即可
|
||||
|
||||
```xml
|
||||
<!-- ↓↓↓ 使用spring cloud zuul ↓↓↓
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||
<groupId>com.gitee.sop</groupId>
|
||||
<!-- 使用zuul作为网关 -->
|
||||
<!--<artifactId>sop-bridge-zuul</artifactId>-->
|
||||
<!-- 使用spring cloud gateway作为网关 -->
|
||||
<artifactId>sop-bridge-gateway</artifactId>
|
||||
<version>对应版本</version>
|
||||
</dependency>
|
||||
-->
|
||||
<!-- ↑↑↑ 使用spring cloud zuul ↑↑↑ -->
|
||||
|
||||
|
||||
<!-- ↓↓↓ 使用spring cloud gateway,处于beta阶段,推荐使用zuul ↓↓↓ -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- ↑↑↑ 使用spring cloud gateway ↑↑↑ -->
|
||||
```
|
||||
|
||||
- 打开启动类`SopGatewayApplication.java`, 注释zuul相关注解
|
||||
|
||||
```java
|
||||
package com.gitee.sop.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
//import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||
|
||||
// 开启网关功能
|
||||
//@EnableZuulProxy
|
||||
@SpringBootApplication
|
||||
public class SopGatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SopGatewayApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
- 禁用ZuulConfig类,注释掉@Configuration注解即可
|
||||
|
||||
```java
|
||||
//@Configuration
|
||||
public class ZuulConfig extends AlipayZuulConfiguration {...}
|
||||
```
|
||||
|
||||
- 启用GatewayConfig类,打开@Configuration注释
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class GatewayConfig extends AlipayGatewayConfiguration {...}
|
||||
```
|
||||
|
||||
修改完毕,重启sop-gateway
|
||||
|
@@ -4,43 +4,60 @@
|
||||
|
||||
## 使用预发布
|
||||
|
||||
假设网关工程在阿里云负载均衡有两台服务器,域名分别为:
|
||||
SOP中预发布的思路如下:
|
||||
|
||||
假设网关工程sop-gateway在阿里云负载均衡有两台服务器,域名分别为:
|
||||
|
||||
|域名|说明|
|
||||
|:---- |:---- |
|
||||
|open1.domain.com |网关服务器1 |
|
||||
|openpre.domain.com | 网关服务器2,作为预发布请求入口|
|
||||
|
||||
线上网关入口为`http://open.domain.com/api`,请求网关`http://open.domain.com/api`会负载均衡到这两台服务器
|
||||
SLB对外域名为:`open.domain.com`,即开放平台入口为:`http://open.domain.com`
|
||||
|
||||
访问`open.domain.com`会负载均衡到`open1.domain.com`和`openpre.domain.com`这两台实例
|
||||
|
||||
如果单独从`openpre.domain.com`访问,则会访问到预发布微服务。
|
||||
|
||||
SOP开启预发布步骤如下:
|
||||
|
||||
修改网关工程配置文件,指定预发布域名
|
||||
|
||||
```properties
|
||||
# 预发布网关域名
|
||||
# 预发布网关域名,多个用英文逗号(,)隔开
|
||||
pre.domain=openpre.domain.com
|
||||
```
|
||||
|
||||
重启网关
|
||||
|
||||
微服务启动参数添加:`--spring.cloud.nacos.discovery.metadata.env=pre`(eureka下是:`--eureka.instance.metadata-map.env=pre`)。
|
||||
建议线上配两套启动脚本,其中预发布启动脚本添加启动参数`--eureka.instance.metadata-map.env=pre`
|
||||
|
||||
登录SOP-Admin,在服务列表中点击预发布,然后预发布请求地址变成:`http://openpre.domain.com/api`。
|
||||
从`openpre.domain.com`请求进来的用户都会进预发布服务器,其它情况都走非预发布服务器。
|
||||
微服务启动参数添加:`--spring.cloud.nacos.discovery.metadata.env=pre`(eureka下是:`--eureka.instance.metadata-map.env=pre`)。
|
||||
建议线上配两套启动脚本,其中预发布启动脚本添加启动参数`--spring.cloud.nacos.discovery.metadata.env=pre`
|
||||
|
||||
登录SOP-Admin,在服务列表中点击预发布。
|
||||
|
||||
从`openpre.domain.com`请求进来的用户都会进预发布服务器,从SLB域名进来请求路由到非预发服务器
|
||||
|
||||
## 使用灰度发布
|
||||
|
||||
灰度发布可允许指定的用户访问灰度服务器,其它用户还是走正常流程。
|
||||
|
||||
微服务启动参数添加:`--spring.cloud.nacos.discovery.metadata.env=gray`(eureka下是:`--eureka.instance.metadata-map.env=gray`)。
|
||||
登录SOP-Admin,前往`服务列表`。
|
||||
|
||||
登录SOP-Admin,前往服务列表。
|
||||
|
||||
- 先设置灰度参数,指定灰度用户和灰度接口
|
||||
- 先设置灰度参数,指定灰度appId和灰度接口
|
||||
- 服务器实例开启灰度
|
||||
|
||||
|
||||
参考类:
|
||||
|
||||
- PreEnvGrayFilter.java
|
||||
- EnvironmentServerChooser.java
|
||||
- LoadBalanceServerChooser.java 预发布/灰度发布服务实例选择
|
||||
|
||||
### 自定义判断灰度用户
|
||||
|
||||
默认根据`appId`和`IP`来判断灰度用户,如果要通过其它维度来判断是否是灰度用户,可实现GrayUserBuilder接口,
|
||||
然后在springboot main方法中调用如下方法
|
||||
|
||||
```java
|
||||
ApiConfig.getInstance().addGrayUserBuilder(new XXGrayUserBuilder());
|
||||
```
|
||||
参考:com.gitee.sop.gatewaycommon.loadbalancer.builder.AppIdGrayUserBuilder.java
|
92
doc/docs/files/90014_原理分析之预发布灰度发布.md
Normal file
92
doc/docs/files/90014_原理分析之预发布灰度发布.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# 原理分析之预发布灰度发布
|
||||
|
||||
SOP网关采用`自定义负载均衡策略`来实现对预发布/灰度发布服务器实例的选择。
|
||||
|
||||
spring cloud gateway默认的负载均衡实现类在:`org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.java`中
|
||||
|
||||
这个类主要做了几件事情:
|
||||
|
||||
1. 解析出请求路径中的scheme
|
||||
2. 如果scheme不是以`lb`协议开头直接跳过
|
||||
3. 如果scheme以`lb`协议开头,则说明需要进行负载均衡,选出一台微服务实例
|
||||
4. 将`lb`协议解析成`http://ip:port`,继续向下请求
|
||||
|
||||
其中第4步是由`org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient`来完成的,
|
||||
我们只要分别继承`LoadBalancerClientFilter`和`RibbonLoadBalancerClient`,然后重写其中的方法就能完成自定义负载均衡。
|
||||
|
||||
SOP中的重写类是:`SopLoadBalancerClientFilter`和`SopLoadBalancerClient`,核心代码委托给了`LoadBalanceServerChooser`处理,核心代码如下:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 选择服务器
|
||||
*
|
||||
* @param serviceId serviceId,仅gateway网关有作用
|
||||
* @param exchange 请求上下文
|
||||
* @param loadBalancer loadBalancer
|
||||
* @param superChooser 父类默认的选择
|
||||
* @param serverChooserFunction 执行选择操作
|
||||
* @return 返回服务器实例,没有选到则返回null
|
||||
*/
|
||||
public R choose(
|
||||
String serviceId
|
||||
, T exchange
|
||||
, ILoadBalancer loadBalancer
|
||||
, Supplier<R> superChooser
|
||||
, Function<List<Server>, R> serverChooserFunction) {
|
||||
// 获取所有服务实例
|
||||
List<Server> servers = loadBalancer.getReachableServers();
|
||||
|
||||
// 存放预发服务器
|
||||
List<Server> preServers = new ArrayList<>(4);
|
||||
// 存放灰度发布服务器
|
||||
List<Server> grayServers = new ArrayList<>(4);
|
||||
// 存放非预发服务器
|
||||
List<Server> notPreServers = new ArrayList<>(4);
|
||||
|
||||
for (Server server : servers) {
|
||||
// 获取实例metadata
|
||||
Map<String, String> metadata = getMetadata(serviceId, server);
|
||||
// 是否开启了预发模式
|
||||
if (this.isPreServer(metadata)) {
|
||||
preServers.add(server);
|
||||
} else if (this.isGrayServer(metadata)) {
|
||||
grayServers.add(server);
|
||||
} else {
|
||||
notPreServers.add(server);
|
||||
}
|
||||
}
|
||||
notPreServers.addAll(grayServers);
|
||||
// 如果没有开启预发布服务和灰度发布,直接用默认的方式
|
||||
if (preServers.isEmpty() && grayServers.isEmpty()) {
|
||||
return superChooser.get();
|
||||
}
|
||||
// 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
|
||||
if (this.isRequestFromPreDomain(exchange)) {
|
||||
return serverChooserFunction.apply(preServers);
|
||||
}
|
||||
// 如果是灰度请求,则认为是灰度用户,选出灰度服务器
|
||||
if (this.isRequestGrayServer(exchange)) {
|
||||
return serverChooserFunction.apply(grayServers);
|
||||
}
|
||||
|
||||
// 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器
|
||||
// 注意:这里允许走灰度服务器,如果不允许走,注释notPreServers.addAll(grayServers);这行
|
||||
return serverChooserFunction.apply(notPreServers);
|
||||
}
|
||||
```
|
||||
|
||||
其业务逻辑如下:
|
||||
|
||||
1. 选出`serviceId`对应的所有服务器实例
|
||||
2. 将服务器实例进行分类,分别放进`预发布List`,`灰度List`,`非预发布List`中
|
||||
3. 如果`预发布List`,`灰度List`都为空,表示没有开启任何预发/灰度服务,直接使用父类的负载均衡策略
|
||||
4. 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器
|
||||
5. 如果是灰度请求,则认为是灰度用户,选出灰度服务器
|
||||
6. 最后剩下的是正常用户,正常用户不能走预发环境
|
||||
|
||||
## 参考类
|
||||
|
||||
- com.gitee.sop.gatewaycommon.gateway.filter.SopLoadBalancerClientFilter
|
||||
- com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient
|
||||
- com.gitee.sop.gatewaycommon.gateway.loadbalancer.GatewayLoadBalanceServerChooser
|
||||
|
23
doc/docs/files/90099_2.x升3.x注意事项.md
Normal file
23
doc/docs/files/90099_2.x升3.x注意事项.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 2.x升3.x注意事项
|
||||
|
||||
升级到3.x后`本地访问接口`方式会有不同。
|
||||
|
||||
```java
|
||||
@ApiMapping(value = "alipay.story.get")
|
||||
public StoryResult getStory(StoryParam param) {
|
||||
StoryResult story = new StoryResult();
|
||||
story.setId(1L);
|
||||
story.setName("海底小纵队(alipay.story.get1.0), port:" + environment.getProperty("server.port") + ", param:" + param);
|
||||
return story;
|
||||
}
|
||||
```
|
||||
|
||||
- 2.x版本访问方式:
|
||||
|
||||
`http://localhost:2222/alipay.story.get/?name=Jim&version=1.0`
|
||||
|
||||
- 3.x版本访问方式:
|
||||
|
||||
`http://localhost:2222/alipay.story.get/1.0/?name=Jim`
|
||||
|
||||
3.x版本中把版本号融合在了url中,如果这个功能没有用到,可以放心升级。
|
112
doc/docs/files/90999_网关性能测试.md
Normal file
112
doc/docs/files/90999_网关性能测试.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# 网关性能测试
|
||||
|
||||
**测试环境**
|
||||
|
||||
> 注意:记得关闭限流功能
|
||||
|
||||
- 测试工具:[wrk](https://github.com/wg/wrk),[安装教程](https://www.cnblogs.com/quanxiaoha/p/10661650.html)
|
||||
- 服务器:CentOS7(虚拟机,宿主机:macbookpro),内存:2G,CPU:1,核数:2核
|
||||
- 运行环境:Java8、Mysql-5.7、Nacos-1.1.3
|
||||
- 运行参数:`-verbose:gc -XX:+PrintGCDetails -XX:+PrintHeapAtGC -Xloggc:gc-zuul.log \
|
||||
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn512m -Xss256k -XX:SurvivorRatio=8\
|
||||
-XX:+UseConcMarkSweepGC`
|
||||
|
||||
- zuul配置:
|
||||
|
||||
```properties
|
||||
# 不校验时间,这样一个链接可以一直进行测试
|
||||
sop.api-config.timeout-seconds=0
|
||||
sop.restful.enable=true
|
||||
|
||||
logging.level.com.gitee=info
|
||||
|
||||
# zuul调优
|
||||
zuul.host.max-per-route-connections=5000
|
||||
zuul.host.max-total-connections=5000
|
||||
zuul.semaphore.max-semaphores=5000
|
||||
|
||||
ribbon.ReadTimeout=5000
|
||||
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=13000
|
||||
|
||||
logging.file=sop-gateway.log
|
||||
```
|
||||
|
||||
以上配置仅针对zuul,Spring Cloud Gateway没有做优化配置
|
||||
|
||||
CentOS允许最大连接数
|
||||
```
|
||||
$ ulimit -n
|
||||
65535
|
||||
```
|
||||
|
||||
## 调用开放接口
|
||||
|
||||
- wrk命令:
|
||||
|
||||
```
|
||||
wrk -t8 -c200 -d30s "http://10.1.31.227:8081/?charset=utf-8&biz_content=%7B%22name%22%3A%22%E8%91%AB%E8%8A%A6%E5%A8%83%22%2C%22id%22%3A%221%22%7D&method=alipay.story.get&format=json&sign=RjK%2FThnzAJQOw%2BfoVLS18PgWZAR%2B25SI2XdONFhS%2BmS8vsv2jNT3rygFoh%2ByX1AJbMgIEfcBzkQyqrs29jjd5dcwHVkcf7vxXshyfcEgl0fbMF6Ihycnz7rqSqkW3lzAWx4NuWUfkPnTX8Ffuf%2BhYRaI0NCpNv%2FV300HvsvmUjS6ZzS4YHaT1peSq0agfUhwRPd97aYMnUwRZDzxNfc5wuXA7OQ1o%2FPYIuIb%2FajVfwNP5ysitc%2FKtYEqt9rNAuzkcFmsw71d2RRnrPLsDN%2BuBXnIEh482f%2FbMj2Rj4%2FMq%2B0PEtlTRbg3rYnxyfowymfX%2BNmI4gNRUt70D4a%2FL3Qiug%3D%3D&app_id=2019032617262200001&sign_type=RSA2&version=1.0×tamp=2020-01-19+13%3A34%3A12"
|
||||
```
|
||||
|
||||
- Spring Cloud Gateway测试结果
|
||||
|
||||
```
|
||||
8 threads and 200 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 139.74ms 69.39ms 617.14ms 69.82%
|
||||
Req/Sec 182.12 55.74 343.00 66.24%
|
||||
43391 requests in 30.09s, 11.96MB read
|
||||
Requests/sec: 1441.96
|
||||
Transfer/sec: 406.96KB
|
||||
```
|
||||
|
||||
- Spring Cloud Zuul测试结果
|
||||
|
||||
```
|
||||
8 threads and 200 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 230.14ms 331.27ms 2.00s 86.98%
|
||||
Req/Sec 141.69 51.04 323.00 66.99%
|
||||
33945 requests in 30.09s, 9.88MB read
|
||||
Socket errors: connect 0, read 0, write 0, timeout 385
|
||||
Requests/sec: 1128.05
|
||||
Transfer/sec: 336.15KB
|
||||
```
|
||||
|
||||
## 调用restful请求
|
||||
|
||||
- wrk命令:
|
||||
|
||||
```
|
||||
wrk -t8 -c200 -d30s "http://10.1.31.227:8081/rest/story-service/food/getFoodById?id=2"
|
||||
```
|
||||
|
||||
线程数为 8,模拟 200 个并发请求,持续 30 秒
|
||||
|
||||
- Spring Cloud Gateway测试结果
|
||||
|
||||
```
|
||||
8 threads and 200 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 120.14ms 58.30ms 513.85ms 67.47%
|
||||
Req/Sec 210.47 54.26 770.00 69.37%
|
||||
50301 requests in 30.10s, 7.53MB read
|
||||
Requests/sec: 1670.97
|
||||
Transfer/sec: 256.21KB
|
||||
```
|
||||
|
||||
|
||||
- Spring Cloud Zuul测试结果
|
||||
|
||||
```
|
||||
8 threads and 200 connections
|
||||
Thread Stats Avg Stdev Max +/- Stdev
|
||||
Latency 185.86ms 285.65ms 1.99s 88.55%
|
||||
Req/Sec 167.75 55.60 460.00 68.05%
|
||||
40070 requests in 30.09s, 6.65MB read
|
||||
Socket errors: connect 0, read 0, write 0, timeout 466
|
||||
Requests/sec: 1331.81
|
||||
Transfer/sec: 226.50KB
|
||||
```
|
||||
|
||||
|
||||
综上所述,Spring Cloud Gateway在没有优化的情况下,压测表现比zuul好,但zuul的数据表现也不差,但是出现超时现象,总的来说还是Spring Cloud Gateway具有优势。
|
Reference in New Issue
Block a user