Merge branch 'develop' into feature/v2.7.3

This commit is contained in:
dxfeng10
2023-07-01 23:51:57 +08:00
committed by GitHub
11 changed files with 398 additions and 265 deletions

View File

@@ -1,49 +1,52 @@
English | [简体中文](./README.md) English | [简体中文](./README.md)
<p align="center" > <p align="center" >
<a href="https://www.fizzgate.com"><img src="https://raw.githubusercontent.com/wiki/fizzgate/fizz-gateway-community/img/icon-color.png" width="70%"></a> <a href="https://www.fizzgate.com"><img src="https://www.fizzgate.com/fizz/nav-bar/logo.png?v=1" width="70%"></a>
</p> </p>
<p> <p>
<img alt="Version" src="https://img.shields.io/badge/version-2.7.2-blue.svg?cacheSeconds=2592000" /> <img alt="Version" src="https://img.shields.io/badge/version-2.7.2-blue.svg?cacheSeconds=2592000" />
<a href="http://www.fizzgate.com/fizz-gateway-community/" target="_blank"> <a href="http://www.fizzgate.com/fizz-gateway-node/" target="_blank">
<img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" /> <img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" />
</a> </a>
<a href="#" target="_blank"> <a href="#" target="_blank">
<img alt="License: GPL--3.0" src="https://img.shields.io/badge/License-GPL--3.0-yellow.svg" /> <img alt="License: AGPL--3.0" src="https://img.shields.io/badge/License-AGPL--3.0-yellow.svg" />
</a> </a>
<a href="https://github.com/fizzgate/fizz-gateway-community/actions" target="_blank"> <a href="https://github.com/fizzgate/fizz-gateway-node/actions" target="_blank">
<img alt="Java CI with Maven" src="https://github.com/fizzgate/fizz-gateway-community/workflows/Java%20CI%20with%20Maven/badge.svg?branch=master" /> <img alt="Java CI with Maven" src="https://github.com/fizzgate/fizz-gateway-node/workflows/Java%20CI%20with%20Maven/badge.svg?branch=master" />
</a> </a>
</p> </p>
- **latest QQ group**: 512164278 - **buissness and technology communication channel**:
<img src="https://www.fizzgate.com/fizz/footer/serviceCode.png" width="150px">
## What 's Fizz Gateway ## What 's FizzGate
An Aggregation API Gateway in Java . Fizz Gateway is a Java-based microservice gateway that can realize hot service aggregation, automatic authorization selection, online service script coding, online testing, high-performance routing, API audit management and other purposes. It has a powerful The custom plug-in system can be extended by youself, and provides a friendly graphical configuration interface, which can quickly help enterprises to manage API services, reduce middle layer glue code, reduce coding investment, and improve the stability and security of API services. An Aggregation API Gateway in Java . FizzGate is a Java-based microservice gateway that can realize hot service aggregation, automatic authorization selection, online service script coding, online testing, high-performance routing, API audit management and other purposes. It has a powerful The custom plug-in system can be extended by youself, and provides a friendly graphical configuration interface, which can quickly help enterprises to manage API services, reduce middle layer glue code, reduce coding investment, and improve the stability and security of API services.
## Demo ## Demo
http://demo.fizzgate.com/ https://demo.fizzgate.com/
account/password:`admin`/`Aa123!` In order to provide better services to everyone, the community version no longer provides any technical consultation. For the commercial version, please add Enterprise WeChat for business support.
health checking urlhttp://demo.fizzgate.com/admin/health account/password:Please contact the official enterprise WeChat to obtain
API accesshttp://demo.fizzgate.com/proxy/[Service Name]/[API Path] health checking urlhttps://demo.fizzgate.com/admin/health
## Fizz's Design API accesshttps://demo.fizzgate.com/proxy/[Service Name]/[API Path]
## FizzGate's Design
<img width="500" src="https://user-images.githubusercontent.com/184315/97130741-33a90d80-177d-11eb-8680-f589a36e44b3.png" /> <img width="500" src="https://user-images.githubusercontent.com/184315/97130741-33a90d80-177d-11eb-8680-f589a36e44b3.png" />
## Fizz's typical scene ## FizzGate's typical scene
<img width="90%" src="https://user-images.githubusercontent.com/6129661/216249866-71eb54de-d2e8-44ce-8e70-a1ca1f51553d.png" /> <img width="90%" src="https://user-images.githubusercontent.com/6129661/216249866-71eb54de-d2e8-44ce-8e70-a1ca1f51553d.png" />
## Product Features ## Product Features
- Cluster management: Fizz gateway nodes are stateless with configuration information that is automatically synchronized, and horizontal expansion of nodes and multi-cluster deployment are supported. - Cluster management: FizzGate nodes are stateless with configuration information that is automatically synchronized, and horizontal expansion of nodes and multi-cluster deployment are supported.
- Service aggregation: supports hot http/dubbo/grpc service aggregation capabilities, support front-end and back-end coding, and update API anytime and anywhere; - Service aggregation: supports hot http/dubbo/grpc service aggregation capabilities, support front-end and back-end coding, and update API anytime and anywhere;
- Load balancing: supports round-robin load balancing; - Load balancing: supports round-robin load balancing;
- Multiple Registration Center: supports discovery of back-end servers from the Eureka or Nacos registry; - Multiple Registration Center: supports discovery of back-end servers from the Eureka or Nacos registry;
@@ -64,7 +67,7 @@ API accesshttp://demo.fizzgate.com/proxy/[Service Name]/[API Path]
## Benchmarks ## Benchmarks
We compare FIZZ with the major gateway products on the market, using the same environment and conditions, and the test objects are under single node. The Mock interface simulates a 20ms latency with a packet size of about 2K. We compare FzzGate with the major gateway products on the market, using the same environment and conditions, and the test objects are under single node. The Mock interface simulates a 20ms latency with a packet size of about 2K.
- Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz * 4 - Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz * 4
- Linux version 3.10.0-957.21.3.el7.x86_64 - Linux version 3.10.0-957.21.3.el7.x86_64
@@ -74,20 +77,20 @@ We compare FIZZ with the major gateway products on the market, using the same en
| :------------------ | :------------------ | :-------: | :-------: | :-------: | :-------: | | :------------------ | :------------------ | :-------: | :-------: | :-------: | :-------: |
| Backend Service | direct access | 23540| 32.19 | 27325| 52.09 | | Backend Service | direct access | 23540| 32.19 | 27325| 52.09 |
| Traffic Gateway | kong <br/>v2.4.1 | 15662 | 50.87 | 17152 | 84.3 | | Traffic Gateway | kong <br/>v2.4.1 | 15662 | 50.87 | 17152 | 84.3 |
| Application Gateway | fizz-gateway-community <br/>v2.0.0 | 12206 | 65.76 | 12766 | 100.34 | | Application Gateway | fizz-gateway-node <br/>v2.0.0 | 12206 | 65.76 | 12766 | 100.34 |
| Application Gateway | spring-cloud-gateway <br/>v2.2.9 | 11323 | 68.57 | 10472 | 127.59 | | Application Gateway | spring-cloud-gateway <br/>v2.2.9 | 11323 | 68.57 | 10472 | 127.59 |
| Application Gateway | shenyu <br/>v2.3.0 | 9284 | 92.98 | 9939 | 148.61 | | Application Gateway | shenyu <br/>v2.3.0 | 9284 | 92.98 | 9939 | 148.61 |
## Version comparison ## Version comparison
- Fizz-gateway-community Community Edition - fizz-gateway-node Community Edition
- Fizz-manager-professionalManagement backend professional version (backend) - fizz-manager-professionalManagement backend professional version (backend)
- Fizz-admin-professionalManagement backend professional version (frontend) - fizz-admin-professionalManagement backend professional version (frontend)
| Fizz-gateway-community | Fizz-manager-professional | Fizz-admin-professional | | fizz-gateway-node | fizz-manager-professional | fizz-admin-professional |
| ---------------------- | ------------------------- | ----------------------- | | ---------------------- | ------------------------- | ----------------------- |
| v1.0.0 | v1.0.0 | v1.0.0 | | v1.0.0 | v1.0.0 | v1.0.0 |
| v1.1.0 | v1.1.0 | v1.1.0 | | v1.1.0 | v1.1.0 | v1.1.0 |
@@ -96,11 +99,11 @@ We compare FIZZ with the major gateway products on the market, using the same en
Starting from v1.3.0, the frontend and backend of the management backend are merged into one package Starting from v1.3.0, the frontend and backend of the management backend are merged into one package
- Fizz-gateway-community Community Edition - fizz-gateway-node Community Edition
- Fizz-manager-professionalManagement backend professional version - fizz-manager-professionalManagement backend professional version
| Fizz-gateway-community | Fizz-manager-professional | | fizz-gateway-node | fizz-manager-professional |
|------------------------|---------------------------| |------------------------|---------------------------|
| v1.3.0 | v1.3.0 | | v1.3.0 | v1.3.0 |
| ... | ... | | ... | ... |
@@ -127,7 +130,7 @@ Install the following dependent software:
Dependent installation can refer to detailed deployment tutorial Dependent installation can refer to detailed deployment tutorial
### Install Fizz ### Install FizzGate
#### 一、Install management backend #### 一、Install management backend
@@ -149,7 +152,7 @@ installation method 1: binary package:
Installation method 2: docker: Installation method 2: docker:
Download SQL script from page: https://github.com/fizzgate/fizz-gateway-community/releases/tag/{version} replace {version} with corresponding version number Download SQL script from page: https://github.com/fizzgate/fizz-gateway-node/releases/tag/{version} replace {version} with corresponding version number
For the first installation, execute the `fizz-manager-professional-{version}-mysql.sql` database script, upgrade from a low version to a high version, and choose to execute the corresponding upgrade script in the update directory For the first installation, execute the `fizz-manager-professional-{version}-mysql.sql` database script, upgrade from a low version to a high version, and choose to execute the corresponding upgrade script in the update directory
@@ -178,7 +181,7 @@ docker run --rm -d -p 8000:8000 \
After the service is started, visit http://{deployment machine IP address}:8000/#/login, and log in with the super administrator account `admin` password `Aa123!` After the service is started, visit http://{deployment machine IP address}:8000/#/login, and log in with the super administrator account `admin` password `Aa123!`
#### 二、Install fizz-gateway-community community edition #### 二、Install fizz-gateway-node community edition
Description: Description:
@@ -188,7 +191,7 @@ Description:
Installation method 1: binary package: Installation method 1: binary package:
1. Download the latest binary package of fizz-gateway-community and upzip to a directory, modify the configuration of the configuration center, registry, and redis in the application.yml configuration file (redis configuration needs to be consistent with the management backend). 1. Download the latest binary package of fizz-gateway-node and upzip to a directory, modify the configuration of the configuration center, registry, and redis in the application.yml configuration file (redis configuration needs to be consistent with the management backend).
2. Modify the apollo connection and JVM memory configuration of the boot.sh script 2. Modify the apollo connection and JVM memory configuration of the boot.sh script
3. Linux startup Execute `./boot.sh start` command to start the service, support start/stop/restart/status command 3. Linux startup Execute `./boot.sh start` command to start the service, support start/stop/restart/status command
4. Windows startup Execute `.\boot.cmd start` command to start the service, support start/stop/restart/status command 4. Windows startup Execute `.\boot.cmd start` command to start the service, support start/stop/restart/status command
@@ -196,13 +199,13 @@ Installation method 1: binary package:
Installation method 2: source code: Installation method 2: source code:
1. The latest code on the local clone warehouse, modify the configuration of the configuration center, registry, and redis in the application.yml configuration file (redis configuration needs to be consistent with the management backend) 1. The latest code on the local clone warehouse, modify the configuration of the configuration center, registry, and redis in the application.yml configuration file (redis configuration needs to be consistent with the management backend)
2. Execute the Maven command `mvn clean package install -DskipTests=true` package in the project root directory fizz-gateway-community 2. Execute the Maven command `mvn clean package install -DskipTests=true` package in the project root directory fizz-gateway-node
3. Execute the Maven command `mvn clean package -DskipTests=true` package in the project directory fizz-gateway-community/fizz-bootstrap 3. Execute the Maven command `mvn clean package -DskipTests=true` package in the project directory fizz-gateway-node/fizz-bootstrap
4. Enter fizz-gateway-community/fizz-bootstrap/target/fizz-gateway-community directory and Execute `./boot.sh start` command to start the service, support start/stop/restart/status command 4. Enter fizz-gateway-node/fizz-bootstrap/target/fizz-gateway-node directory and Execute `./boot.sh start` command to start the service, support start/stop/restart/status command
Installation method 3: docker: Installation method 3: docker:
1. Download docker imagedocker pull fizzgate/fizz-gateway-community:{version} 1. Download docker imagedocker pull fizzgate/fizz-gateway-node:{version}
2. Modify Redis configuration by env parameters and run with below docker command 2. Modify Redis configuration by env parameters and run with below docker command
```sh ```sh
docker run --rm -d -p 8600:8600 \ docker run --rm -d -p 8600:8600 \
@@ -210,88 +213,89 @@ docker run --rm -d -p 8600:8600 \
-e "aggregate.redis.port={your redis port}" \ -e "aggregate.redis.port={your redis port}" \
-e "aggregate.redis.password={your redis password}" \ -e "aggregate.redis.password={your redis password}" \
-e "aggregate.redis.database={your redis database}" \ -e "aggregate.redis.database={your redis database}" \
fizzgate/fizz-gateway-community:{version} fizzgate/fizz-gateway-node:{version}
``` ```
or using external configuration file and output log to host server by mount volume, configuration file could be achieved from source code or binary package, create fizz-gateway-community/config and fizz-gateway-community/logs directories in host server, place application.yml and log4j2-spring.xml configuration files to config folder, run with below docker command in fizz-gateway-community folder: or using external configuration file and output log to host server by mount volume, configuration file could be achieved from source code or binary package, create fizz-gateway-node/config and fizz-gateway-node/logs directories in host server, place application.yml and log4j2-spring.xml configuration files to config folder, run with below docker command in fizz-gateway-node folder:
```sh ```sh
cd fizz-gateway-community cd fizz-gateway-node
docker run --rm -d -p 8600:8600 \ docker run --rm -d -p 8600:8600 \
-v $PWD/config:/opt/fizz-gateway-community/config \ -v $PWD/config:/opt/fizz-gateway-node/config \
-v $PWD/logs:/opt/fizz-gateway-community/logs fizzgate/fizz-gateway-community:{version} -v $PWD/logs:/opt/fizz-gateway-node/logs fizzgate/fizz-gateway-node:{version}
``` ```
Finally visit the gateway, the address format is: http://127.0.0.1:8600/[Service name]/[API Path] Finally visit the gateway, the address format is: http://127.0.0.1:8600/[Service name]/[API Path]
## Official technical exchange group ## Official technical exchange group
Fizz官方技术交流①群已满 FizzGate官方技术交流①群(已满)
Fizz官方技术交流②群已满 FizzGate官方技术交流②群(已满)
Fizz官方技术交流③群512164278 FizzGate官方技术交流③群512164278
<img width="250" src="https://user-images.githubusercontent.com/184315/97130743-3572d100-177d-11eb-97c8-7599a22c7c04.png" /> <img width="250" src="https://user-images.githubusercontent.com/184315/97130743-3572d100-177d-11eb-97c8-7599a22c7c04.png" />
## Related acticles ## Related acticles
[服务器减少50%研发效率提高86%我们的管理型网关Fizz自研之路](https://www.infoq.cn/article/9wdfiOILJ0CYsVyBQFpl) [服务器减少50%研发效率提高86%我们的管理型网关FizzGate自研之路](https://www.infoq.cn/article/9wdfiOILJ0CYsVyBQFpl)
[简单易用的微服务聚合网关首选Fizz Gateway安装教程](https://my.oschina.net/linwaiwai/blog/4696224) [简单易用的微服务聚合网关首选FizzGate安装教程](https://my.oschina.net/linwaiwai/blog/4696224)
[大厂推荐使用的网关解密Fizz Gateway管理后台使用教程](https://my.oschina.net/linwaiwai/blog/4696124) [大厂推荐使用的网关解密FizzGate管理后台使用教程](https://my.oschina.net/linwaiwai/blog/4696124)
[架构师效率快的终极原因Fizz Gateway网关之服务编排](https://my.oschina.net/linwaiwai/blog/4696116) [架构师效率快的终极原因FizzGate网关之服务编排](https://my.oschina.net/linwaiwai/blog/4696116)
[高阶架构师支招Fizz Gateway的插件开发](https://my.oschina.net/linwaiwai/blog/4696131) [高阶架构师支招FizzGate的插件开发](https://my.oschina.net/linwaiwai/blog/4696131)
[高阶程序员必备技能Fizz Gateway网关的二次开发](https://my.oschina.net/linwaiwai/blog/4696133) [高阶程序员必备技能FizzGate网关的二次开发](https://my.oschina.net/linwaiwai/blog/4696133)
[Fizz网关入门教程-安装](https://zhuanlan.zhihu.com/p/501305059) [FizzGate网关入门教程-安装](https://zhuanlan.zhihu.com/p/501305059)
[Fizz网关入门教程-路由初体验](https://zhuanlan.zhihu.com/p/501381970) [FizzGate网关入门教程-路由初体验](https://zhuanlan.zhihu.com/p/501381970)
[Fizz网关入门教程-权限校验](https://zhuanlan.zhihu.com/p/501384396) [FizzGate网关入门教程-权限校验](https://zhuanlan.zhihu.com/p/501384396)
[Fizz网关入门教程-快速聚合多接口,提高页面数据的加载速度](https://zhuanlan.zhihu.com/p/501387154) [FizzGate网关入门教程-快速聚合多接口,提高页面数据的加载速度](https://zhuanlan.zhihu.com/p/501387154)
[Fizz网关入门教程-服务编排祭出终结BFF层的大杀器](https://zhuanlan.zhihu.com/p/501389075) [FizzGate网关入门教程-服务编排祭出终结BFF层的大杀器](https://zhuanlan.zhihu.com/p/501389075)
[企业级微服务API网关Fizz-常用插件介绍](https://zhuanlan.zhihu.com/p/513656382) [企业级微服务API网关FizzGate-常用插件介绍](https://zhuanlan.zhihu.com/p/513656382)
[企业级微服务API网关Fizz-如何自定义插件](https://zhuanlan.zhihu.com/p/513662893) [企业级微服务API网关FizzGate-如何自定义插件](https://zhuanlan.zhihu.com/p/513662893)
[企业级微服务API网关Fizz-服务编排内置函数](https://zhuanlan.zhihu.com/p/513404417) [企业级微服务API网关FizzGate-服务编排内置函数](https://zhuanlan.zhihu.com/p/513404417)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(上)-展开与合并](https://zhuanlan.zhihu.com/p/515056309) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(上)-展开与合并](https://zhuanlan.zhihu.com/p/515056309)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(中)-数据提取与数据关联](https://zhuanlan.zhihu.com/p/515070075) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(中)-数据提取与数据关联](https://zhuanlan.zhihu.com/p/515070075)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(下)-字段重命名&字段移除](https://zhuanlan.zhihu.com/p/515509832) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(下)-字段重命名&字段移除](https://zhuanlan.zhihu.com/p/515509832)
## Authorization instructions ## Authorization instructions
1. The fizz-gateway-community community version of the gateway core project is opened in the form of GNU V3 and can be used free of charge in non-commercial projects following the GNU protocol. 1. The fizz-gateway-node community version of the gateway core project is opened in the form of GNU V3 and can be used free of charge in non-commercial projects following the GNU protocol.
2. Management backend projects (fizz-manager-professional) as commercial versions only open binary packages [free download](https://wj.qq.com/s2/8682608/8fe2/), and For commercial projects, please contact us (sale@fizzgate.com) for authorization. 2. Management backend projects (fizz-manager-professional) as commercial versions only open binary packages [free download](https://wj.qq.com/s2/8682608/8fe2/), and For commercial projects, please contact us (sale@fizzgate.com) for authorization.
## System screenshot ## System screenshot
![homepage](https://user-images.githubusercontent.com/6129661/156333191-1b9901f5-e086-4514-84f0-4a74684fdf2d.png)
![aggr1](https://user-images.githubusercontent.com/6129661/156333163-e2aade71-081c-49f0-9c7b-deb19239be84.png) ![homepage](https://cdn.fizzgate.com/fizz/assets/img/manager_source_statistics_1.991ec114.png)
![aggr2](https://user-images.githubusercontent.com/6129661/156333175-770ac66d-0295-43b1-948a-a91d9a1922dd.png) ![aggr1](https://cdn.fizzgate.com/fizz/assets/img/manager_aggregate_add_2.72b385b5.png)
![route](https://user-images.githubusercontent.com/6129661/156333194-9a4051a8-c59c-493f-8dd9-f004c364b8c4.png) ![aggr2](https://cdn.fizzgate.com/fizz/assets/img/manager_aggregate_add_9.662f119e.png)
![plugin](https://user-images.githubusercontent.com/6129661/156333193-b0bdfae3-4660-42a0-93e3-118333c5b246.png) ![route](https://cdn.fizzgate.com/fizz/assets/img/route1.1fd8abd1.png)
![appid](https://user-images.githubusercontent.com/6129661/156333180-55d4167b-1eba-4fde-900d-6499f971b97f.png) ![plugin](https://cdn.fizzgate.com/fizz/assets/img/manager_plugin_add_2.e1b5a24e.png)
![breaker](https://user-images.githubusercontent.com/6129661/156333182-40986e36-0f80-46b7-aced-1c16406ba2ce.png) ![appid](https://cdn.fizzgate.com/fizz/assets/img/manager_app_id_add_2.49208bf6.png)
![flowcontrol](https://user-images.githubusercontent.com/6129661/156333189-0b209c2b-5026-4a6e-9880-9fc08ee72077.png) ![breaker](https://cdn.fizzgate.com/fizz/assets/img/component2.7e77c716.png)
![doc](https://user-images.githubusercontent.com/6129661/156333188-6a2dae42-24b2-48c6-b401-1b6bbd9f6030.png) ![flowcontrol](https://cdn.fizzgate.com/fizz/assets/img/manager_flow_control_rule_default_edit_2.130223a7.png)
![doc](https://cdn.fizzgate.com/fizz/assets/img/manager_interface_collection_preview_2.eee99e97.png)

182
README.md
View File

@@ -1,41 +1,51 @@
[English](./README.en-us.md) | 简体中文 [English](./README.en-us.md) | 简体中文
<p align="center" > <p align="center" >
<a href="https://www.fizzgate.com"><img src="https://raw.githubusercontent.com/wiki/fizzgate/fizz-gateway-community/img/icon-color.png" width="70%"></a> <a href="https://www.fizzgate.com"><img src="https://www.fizzgate.com/fizz/nav-bar/logo.png?v=1" width="70%"></a>
</p> </p>
<p> <p>
<img alt="Version" src="https://img.shields.io/badge/version-2.7.2-blue.svg?cacheSeconds=2592000" /> <img alt="Version" src="https://img.shields.io/badge/version-2.7.1-blue.svg?cacheSeconds=2592000" />
<a href="http://www.fizzgate.com/fizz-gateway-community/" target="_blank"> <a href="http://www.fizzgate.com/fizz-gateway-node/" target="_blank">
<img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" /> <img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" />
</a> </a>
<a href="#" target="_blank"> <a href="#" target="_blank">
<img alt="License: GPL--3.0" src="https://img.shields.io/badge/License-GPL--3.0-yellow.svg" /> <img alt="License: AGPL--3.0" src="https://img.shields.io/badge/License-AGPL--3.0-yellow.svg" />
</a> </a>
<a href="https://github.com/fizzgate/fizz-gateway-community/actions" target="_blank"> <a href="https://github.com/fizzgate/fizz-gateway-node/actions" target="_blank">
<img alt="Java CI with Maven" src="https://github.com/fizzgate/fizz-gateway-community/workflows/Java%20CI%20with%20Maven/badge.svg?branch=master" /> <img alt="Java CI with Maven" src="https://github.com/fizzgate/fizz-gateway-node/workflows/Java%20CI%20with%20Maven/badge.svg?branch=master" />
</a> </a>
</p> </p>
- **最新QQ交流**: 512164278 - **商务及技术交流**:
<img src="https://www.fizzgate.com/fizz/footer/serviceCode.png" width="150px">
## Fizz Gateway是什么 为了给大家提供更好的服务,社区版本不再提供任何技术咨询,商业版本请添加企业微信获取商业支持。
An Aggregation API Gateway in Java . Fizz Gateway 是一个基于 Java开发的微服务聚合网关是拥有自主知识产权的应用网关国产化替代方案能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的拥有强大的自定义插件系统可以自行扩展并且提供友好的图形化配置界面能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。 ## FizzGate是什么?
An Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关是拥有自主知识产权的应用网关国产化替代方案能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的拥有强大的自定义插件系统可以自行扩展并且提供友好的图形化配置界面能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。
## 官方网站
https://www.fizzgate.com/
备用地址https://www.fizzcrm.com/
## 演示环境Demo ## 演示环境Demo
http://demo.fizzgate.com/ https://demo.fizzgate.com/
账号/密码:`admin`/`Aa123!` 备用站点https://demo.fizzcrm.com/
健康检查地址http://demo.fizzgate.com/admin/health (线上版本请限制admin路径的外网访问) 账号/密码: 企业客户请联系官方企业微信获取
API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path] 健康检查地址https://demo.fizzgate.com/admin/health (线上版本请限制admin路径的外网访问)
## Fizz的设计 API地址https://demo.fizzgate.com/proxy/[服务名]/[API_Path]
## FizzGate的设计
<img width="500" src="https://user-images.githubusercontent.com/184315/97130741-33a90d80-177d-11eb-8680-f589a36e44b3.png" /> <img width="500" src="https://user-images.githubusercontent.com/184315/97130741-33a90d80-177d-11eb-8680-f589a36e44b3.png" />
## Fizz典型应用场景 ## FizzGate典型应用场景
<img width="90%" src="https://user-images.githubusercontent.com/6129661/216249866-71eb54de-d2e8-44ce-8e70-a1ca1f51553d.png" /> <img width="90%" src="https://user-images.githubusercontent.com/6129661/216249866-71eb54de-d2e8-44ce-8e70-a1ca1f51553d.png" />
@@ -44,7 +54,7 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
- API管理支持API定义后端服务的配置 - API管理支持API定义后端服务的配置
- 分组管理支持通过分组管理实现同一分组的API使用相关的配置 - 分组管理支持通过分组管理实现同一分组的API使用相关的配置
- 服务鉴权:通过插件可对服务进行应用访问权限、检验等链式的拦截策略; - 服务鉴权:通过插件可对服务进行应用访问权限、检验等链式的拦截策略;
- 集群管理Fizz网关节点是无状态的配置信息自动同步支持节点水平拓展和多集群部署。 - 集群管理FizzGate网关节点是无状态的,配置信息自动同步,支持节点水平拓展和多集群部署。
- 安全授权支持内置的key-auth, JWT, basic-auth授权方式并且可以方便控制。 - 安全授权支持内置的key-auth, JWT, basic-auth授权方式并且可以方便控制。
- 服务编排支持HTTP、Dubbo、gRPC、Soap协议热服务编排能力支持前后端编码支持JSON/XML输出随时随地更新API。 - 服务编排支持HTTP、Dubbo、gRPC、Soap协议热服务编排能力支持前后端编码支持JSON/XML输出随时随地更新API。
- 负载均衡支持round-robin负载均衡。 - 负载均衡支持round-robin负载均衡。
@@ -67,7 +77,7 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
## 基准测试 ## 基准测试
我们将Fizz与市面上主要的网关产品进行比较使用相同的环境和条件测试对象均为单个节点。Mock接口模拟20ms时延报文大小约2K。 我们将FizzGate与市面上主要的网关产品进行比较使用相同的环境和条件测试对象均为单个节点。Mock接口模拟20ms时延报文大小约2K。
- Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz * 4 - Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz * 4
- Linux version 3.10.0-957.21.3.el7.x86_64 - Linux version 3.10.0-957.21.3.el7.x86_64
@@ -77,19 +87,19 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
| :------------------ | :------------------ | :-------: | :-------: | :-------: | :-------: | | :------------------ | :------------------ | :-------: | :-------: | :-------: | :-------: |
| 后端服务 | 直接访问后端服务 | 23540| 32.19 | 27325| 52.09 | | 后端服务 | 直接访问后端服务 | 23540| 32.19 | 27325| 52.09 |
| 流量网关 | kong <br/>v2.4.1 | 15662 | 50.87 | 17152 | 84.3 | | 流量网关 | kong <br/>v2.4.1 | 15662 | 50.87 | 17152 | 84.3 |
| 应用网关 | fizz-gateway-community <br/>v2.0.0 | 12206 | 65.76 | 12766 | 100.34 | | 应用网关 | fizz-gateway-node <br/>v2.0.0 | 12206 | 65.76 | 12766 | 100.34 |
| 应用网关 | spring-cloud-gateway <br/>v2.2.9| 11323 | 68.57 | 10472 | 127.59 | | 应用网关 | spring-cloud-gateway <br/>v2.2.9| 11323 | 68.57 | 10472 | 127.59 |
| 应用网关 | shenyu <br/>v2.3.0| 9284 | 92.98 | 9939 | 148.61 | | 应用网关 | shenyu <br/>v2.3.0| 9284 | 92.98 | 9939 | 148.61 |
## 版本对照 ## 版本对照
- Fizz-gateway-community 社区版 - fizz-gateway-node 节点端
- Fizz-manager-professional管理后台专业版服务端 - fizz-manager-professional管理后台专业版服务端
- Fizz-admin-professional管理后台专业版前端 - fizz-admin-professional管理后台专业版前端
| Fizz-gateway-community | Fizz-manager-professional | Fizz-admin-professional | | fizz-gateway-node | fizz-manager-professional | fizz-admin-professional |
| ---------------------- | ------------------------- | ----------------------- | | ---------------------- | ------------------------- | ----------------------- |
| v1.0.0 | v1.0.0 | v1.0.0 | | v1.0.0 | v1.0.0 | v1.0.0 |
| v1.1.0 | v1.1.0 | v1.1.0 | | v1.1.0 | v1.1.0 | v1.1.0 |
@@ -98,21 +108,43 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
从v1.3.0开始管理后台的前端和服务端合并成一个包 从v1.3.0开始管理后台的前端和服务端合并成一个包
- Fizz-gateway-community 社区版 - fizz-gateway-node 节点端
- Fizz-manager-professional管理后台 - fizz-manager-professional管理后台
| Fizz-gateway-community | Fizz-manager-professional | | fizz-gateway-node | fizz-manager-professional |
|------------------------|---------------------------| |------------------------|---------------------------|
| v1.3.0 | v1.3.0 | | v1.3.0 | v1.3.0 |
| ... | ... | | v1.4.0 | v1.4.0 |
| v1.4.1 | v1.4.1 |
| v1.5.0 | v1.5.0 |
| v1.5.1 | v1.5.1 |
| v2.0.0 | v2.0.0 |
| v2.1.0 | v2.1.0 |
| v2.2.0 | v2.2.0 |
| v2.2.1 | v2.2.1 |
| v2.2.3 | v2.2.3 |
| v2.3.0 | v2.3.0 |
| v2.3.2 | v2.3.2 |
| v2.3.3 | v2.3.3 |
| v2.4.0 | v2.4.0 |
| v2.4.1 | v2.4.1 |
| v2.5.0 | v2.5.0 |
| v2.5.1 | v2.5.1 |
| v2.5.2 | v2.5.2 |
| v2.6.0 | v2.6.0 |
| v2.6.1 | v2.6.1 |
| v2.6.2 | v2.6.2 |
| v2.6.3 | v2.6.3 |
| v2.6.4 | v2.6.4 |
| v2.6.5 | v2.6.5 |
| v2.6.6 | v2.6.6 | | v2.6.6 | v2.6.6 |
| v2.7.0 | v2.7.0 | | v2.7.0 | v2.7.0 |
| v2.7.1 | v2.7.1 | | v2.7.1 | v2.7.1 |
| v2.7.2 | v2.7.2 | | v2.7.2 | v2.7.2 |
请根据社区版的版本下载对应的管理后台版本 请根据节点端的版本下载对应的管理后台版本
## 部署说明 ## 部署说明
@@ -129,7 +161,7 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
依赖的安装可参考详细部署教程 依赖的安装可参考详细部署教程
### 安装Fizz ### 安装FizzGate
#### 一、安装管理后台 #### 一、安装管理后台
@@ -151,7 +183,7 @@ API地址http://demo.fizzgate.com/proxy/[服务名]/[API_Path]
安装方式二v2.0.0或以上版本docker: 安装方式二v2.0.0或以上版本docker:
SQL脚本下载页https://github.com/fizzgate/fizz-gateway-community/releases/tag/{version} (把{version}替换为对应版本号) SQL脚本下载页https://github.com/fizzgate/fizz-gateway-node/releases/tag/{version} (把{version}替换为对应版本号)
首次安装执行`fizz-manager-professional-{version}-mysql.sql`数据库脚本从低版本升级至高版本选择执行update目录下对应升级脚本如有脚本则执行 首次安装执行`fizz-manager-professional-{version}-mysql.sql`数据库脚本从低版本升级至高版本选择执行update目录下对应升级脚本如有脚本则执行
@@ -180,7 +212,7 @@ docker run --rm -d -p 8000:8000 \
服务启动后访问 http://{部署机器IP地址}:8000/#/login,使用超级管理员账户`admin`密码`Aa123!`登录 服务启动后访问 http://{部署机器IP地址}:8000/#/login,使用超级管理员账户`admin`密码`Aa123!`登录
#### 二、安装fizz-gateway-community社区版 #### 二、安装fizz-gateway-node节点端
说明: 说明:
@@ -190,7 +222,7 @@ docker run --rm -d -p 8000:8000 \
安装方式一:二进制安装包 安装方式一:二进制安装包
1. 下载fizz-gateway-community的二进制安装包解压修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置 1. 下载fizz-gateway-node的二进制安装包解压修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置
2. 根据需要修改boot.sh脚本的apollo连接不使用apollo配置中心可跳过 2. 根据需要修改boot.sh脚本的apollo连接不使用apollo配置中心可跳过
3. Linux启动 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 3. Linux启动 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令
4. Windows启动 执行`.\boot.cmd start` 命令启动服务,支持 start/stop/restart/status命令 4. Windows启动 执行`.\boot.cmd start` 命令启动服务,支持 start/stop/restart/status命令
@@ -198,12 +230,12 @@ docker run --rm -d -p 8000:8000 \
安装方式二:源码安装: 安装方式二:源码安装:
1. 本地clone仓库上的最新代码修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置 1. 本地clone仓库上的最新代码修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置
2. 在项目根目录fizz-gateway-community下执行Maven命令`mvn clean package install -DskipTests=true` 2. 在项目根目录fizz-gateway-node下执行Maven命令`mvn clean package install -DskipTests=true`
3. 在项目目录fizz-gateway-community/fizz-bootstrap下执行Maven命令`mvn clean package -DskipTests=true` 3. 在项目目录fizz-gateway-node/fizz-bootstrap下执行Maven命令`mvn clean package -DskipTests=true`
4. 进入fizz-gateway-community/fizz-bootstrap/target/fizz-gateway-community目录,执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 4. 进入fizz-gateway-node/fizz-bootstrap/target/fizz-gateway-node目录,执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令
安装方式三v2.0.0或以上版本docker: 安装方式三v2.0.0或以上版本docker:
1. 下载对应版本的镜像docker pull fizzgate/fizz-gateway-community:{version} 1. 下载对应版本的镜像docker pull fizzgate/fizz-gateway-node:{version}
2. 通过环境变量方式修改redis配置其它配置同理并运行镜像 2. 通过环境变量方式修改redis配置其它配置同理并运行镜像
```sh ```sh
docker run --rm -d -p 8600:8600 \ docker run --rm -d -p 8600:8600 \
@@ -211,94 +243,82 @@ docker run --rm -d -p 8600:8600 \
-e "aggregate.redis.port={your redis port}" \ -e "aggregate.redis.port={your redis port}" \
-e "aggregate.redis.password={your redis password}" \ -e "aggregate.redis.password={your redis password}" \
-e "aggregate.redis.database={your redis database}" \ -e "aggregate.redis.database={your redis database}" \
fizzgate/fizz-gateway-community:{version} fizzgate/fizz-gateway-node:{version}
``` ```
或通过映射目录方式使用外部配置文件和输出日志到宿主机, 配置文件可从安装包或源码里获取在宿主机创建fizz-gateway-community/config和fizz-gateway-community/logs目录把application.yml和log4j2-spring.xml配置文件放置config下在fizz-gateway-community目录下运行镜像 或通过映射目录方式使用外部配置文件和输出日志到宿主机, 配置文件可从安装包或源码里获取在宿主机创建fizz-gateway-node/config和fizz-gateway-node/logs目录把application.yml和log4j2-spring.xml配置文件放置config下在fizz-gateway-node目录下运行镜像
```sh ```sh
cd fizz-gateway-community cd fizz-gateway-node
docker run --rm -d -p 8600:8600 \ docker run --rm -d -p 8600:8600 \
-v $PWD/config:/opt/fizz-gateway-community/config \ -v $PWD/config:/opt/fizz-gateway-node/config \
-v $PWD/logs:/opt/fizz-gateway-community/logs fizzgate/fizz-gateway-community:{version} -v $PWD/logs:/opt/fizz-gateway-node/logs fizzgate/fizz-gateway-node:{version}
``` ```
最后访问网关地址形式为http://127.0.0.1:8600/[服务名]/[API_Path] 最后访问网关地址形式为http://127.0.0.1:8600/[服务名]/[API_Path]
## 官方技术交流群
Fizz官方技术交流④群170145598 (推荐)
Fizz官方技术交流①群已满
Fizz官方技术交流②群已满
Fizz官方技术交流③群512164278
Fizz官方微信群请加入群之后再询问群主
## 相关文章 ## 相关文章
[服务器减少50%研发效率提高86%我们的管理型网关Fizz自研之路](https://www.infoq.cn/article/9wdfiOILJ0CYsVyBQFpl) [服务器减少50%研发效率提高86%我们的管理型网关FizzGate自研之路](https://www.infoq.cn/article/9wdfiOILJ0CYsVyBQFpl)
[简单易用的微服务聚合网关首选Fizz Gateway安装教程](https://my.oschina.net/linwaiwai/blog/4696224) [简单易用的微服务聚合网关首选FizzGate安装教程](https://my.oschina.net/linwaiwai/blog/4696224)
[大厂推荐使用的网关解密Fizz Gateway管理后台使用教程](https://my.oschina.net/linwaiwai/blog/4696124) [大厂推荐使用的网关解密FizzGate管理后台使用教程](https://my.oschina.net/linwaiwai/blog/4696124)
[架构师效率快的终极原因Fizz Gateway网关之服务编排](https://my.oschina.net/linwaiwai/blog/4696116) [架构师效率快的终极原因FizzGate网关之服务编排](https://my.oschina.net/linwaiwai/blog/4696116)
[高阶架构师支招Fizz Gateway的插件开发](https://my.oschina.net/linwaiwai/blog/4696131) [高阶架构师支招FizzGate的插件开发](https://my.oschina.net/linwaiwai/blog/4696131)
[高阶程序员必备技能Fizz Gateway网关的二次开发](https://my.oschina.net/linwaiwai/blog/4696133) [高阶程序员必备技能FizzGate网关的二次开发](https://my.oschina.net/linwaiwai/blog/4696133)
[Fizz网关入门教程-安装](https://zhuanlan.zhihu.com/p/501305059) [FizzGate网关入门教程-安装](https://zhuanlan.zhihu.com/p/501305059)
[Fizz网关入门教程-路由初体验](https://zhuanlan.zhihu.com/p/501381970) [FizzGate网关入门教程-路由初体验](https://zhuanlan.zhihu.com/p/501381970)
[Fizz网关入门教程-权限校验](https://zhuanlan.zhihu.com/p/501384396) [FizzGate网关入门教程-权限校验](https://zhuanlan.zhihu.com/p/501384396)
[Fizz网关入门教程-快速聚合多接口,提高页面数据的加载速度](https://zhuanlan.zhihu.com/p/501387154) [FizzGate网关入门教程-快速聚合多接口,提高页面数据的加载速度](https://zhuanlan.zhihu.com/p/501387154)
[Fizz网关入门教程-服务编排祭出终结BFF层的大杀器](https://zhuanlan.zhihu.com/p/501389075) [FizzGate网关入门教程-服务编排祭出终结BFF层的大杀器](https://zhuanlan.zhihu.com/p/501389075)
[企业级微服务API网关Fizz-常用插件介绍](https://zhuanlan.zhihu.com/p/513656382) [企业级微服务API网关FizzGate-常用插件介绍](https://zhuanlan.zhihu.com/p/513656382)
[企业级微服务API网关Fizz-如何自定义插件](https://zhuanlan.zhihu.com/p/513662893) [企业级微服务API网关FizzGate-如何自定义插件](https://zhuanlan.zhihu.com/p/513662893)
[企业级微服务API网关Fizz-服务编排内置函数](https://zhuanlan.zhihu.com/p/513404417) [企业级微服务API网关FizzGate-服务编排内置函数](https://zhuanlan.zhihu.com/p/513404417)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(上)-展开与合并](https://zhuanlan.zhihu.com/p/515056309) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(上)-展开与合并](https://zhuanlan.zhihu.com/p/515056309)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(中)-数据提取与数据关联](https://zhuanlan.zhihu.com/p/515070075) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(中)-数据提取与数据关联](https://zhuanlan.zhihu.com/p/515070075)
[Fizz企业级微服务API网关进阶系列教程-服务编排处理列表数据(下)-字段重命名&字段移除](https://zhuanlan.zhihu.com/p/515509832) [FizzGate企业级微服务API网关进阶系列教程-服务编排处理列表数据(下)-字段重命名&字段移除](https://zhuanlan.zhihu.com/p/515509832)
## 授权说明 ## 授权说明
1. 网关核心项目fizz-gateway-community社区版本以GNU v3的方式进行的开放在遵循GNU协议的个人非商业化项目中可以免费使用 1. 网关核心项目fizz-gateway-node节点端本以GNU v3的方式进行的开放任何商业使用都需要经过我们授权
2. 管理后台项目(fizz-manager-professional)作为商业版本仅开放二进制包 [免费下载](https://wj.qq.com/s2/8682608/8fe2/)而商业项目请注明公司名称联系我们sale@fizzgate.com进行授权了解商业授权规则请点击[商业授权规则](https://github.com/fizzgate/fizz-gateway-community/wiki/%E5%95%86%E4%B8%9A%E6%8E%88%E6%9D%83) 2. 管理后台项目(fizz-manager-professional)作为商业版本仅开放二进制包 [免费下载](https://wj.qq.com/s2/8682608/8fe2/)而商业项目请注明公司名称联系我们sale@fizzgate.com进行授权了解商业授权规则请点击[商业授权规则](https://github.com/fizzgate/fizz-gateway-node/wiki/%E5%95%86%E4%B8%9A%E6%8E%88%E6%9D%83)
3. 在选择Fizz Gateway之前我们强烈建议您先试用一下我们的DEMO站点试用我们的产品并且思考与自身的业务结合并且考虑产品推行落地方式在查阅我们的官网价格(https://www.fizzgate.com) 之后再进一步与我们联系。 3. 在选择FizzGate之前我们强烈建议您先试用一下我们的DEMO站点试用我们的产品并且思考与自身的业务结合并且考虑产品推行落地方式在查阅我们的官网价格(https://www.fizzgate.com) 之后再进一步与我们联系。
## 系统截图 ## 系统截图
![homepage](https://user-images.githubusercontent.com/6129661/156333191-1b9901f5-e086-4514-84f0-4a74684fdf2d.png) ![homepage](https://cdn.fizzgate.com/fizz/assets/img/manager_source_statistics_1.991ec114.png)
![aggr1](https://user-images.githubusercontent.com/6129661/156333163-e2aade71-081c-49f0-9c7b-deb19239be84.png) ![aggr1](https://cdn.fizzgate.com/fizz/assets/img/manager_aggregate_add_2.72b385b5.png)
![aggr2](https://user-images.githubusercontent.com/6129661/156333175-770ac66d-0295-43b1-948a-a91d9a1922dd.png) ![aggr2](https://cdn.fizzgate.com/fizz/assets/img/manager_aggregate_add_9.662f119e.png)
![route](https://user-images.githubusercontent.com/6129661/156333194-9a4051a8-c59c-493f-8dd9-f004c364b8c4.png) ![route](https://cdn.fizzgate.com/fizz/assets/img/route1.1fd8abd1.png)
![plugin](https://user-images.githubusercontent.com/6129661/156333193-b0bdfae3-4660-42a0-93e3-118333c5b246.png) ![plugin](https://cdn.fizzgate.com/fizz/assets/img/manager_plugin_add_2.e1b5a24e.png)
![appid](https://user-images.githubusercontent.com/6129661/156333180-55d4167b-1eba-4fde-900d-6499f971b97f.png) ![appid](https://cdn.fizzgate.com/fizz/assets/img/manager_app_id_add_2.49208bf6.png)
![breaker](https://user-images.githubusercontent.com/6129661/156333182-40986e36-0f80-46b7-aced-1c16406ba2ce.png) ![breaker](https://cdn.fizzgate.com/fizz/assets/img/component2.7e77c716.png)
![flowcontrol](https://user-images.githubusercontent.com/6129661/156333189-0b209c2b-5026-4a6e-9880-9fc08ee72077.png) ![flowcontrol](https://cdn.fizzgate.com/fizz/assets/img/manager_flow_control_rule_default_edit_2.130223a7.png)
![doc](https://user-images.githubusercontent.com/6129661/156333188-6a2dae42-24b2-48c6-b401-1b6bbd9f6030.png) ![doc](https://cdn.fizzgate.com/fizz/assets/img/manager_interface_collection_preview_2.eee99e97.png)

View File

@@ -14,11 +14,11 @@
<properties> <properties>
<!--<java.version>1.8</java.version> <!--<java.version>1.8</java.version>
<spring-framework.version>5.2.23.RELEASE</spring-framework.version> <spring-framework.version>5.2.24.RELEASE</spring-framework.version>
<spring-session-bom.version>Dragonfruit-SR3</spring-session-bom.version> <spring-session-bom.version>Dragonfruit-SR3</spring-session-bom.version>
<reactor-bom.version>Dysprosium-SR25</reactor-bom.version> <reactor-bom.version>Dysprosium-SR25</reactor-bom.version>
<lettuce.version>5.3.7.RELEASE</lettuce.version> <lettuce.version>5.3.7.RELEASE</lettuce.version>
<netty.version>4.1.91.Final</netty.version> <netty.version>4.1.93.Final</netty.version>
<httpcore.version>4.4.16</httpcore.version> <httpcore.version>4.4.16</httpcore.version>
<log4j2.version>2.17.2</log4j2.version> <log4j2.version>2.17.2</log4j2.version>
<slf4j.version>1.7.36</slf4j.version> <slf4j.version>1.7.36</slf4j.version>
@@ -32,7 +32,7 @@
<commons-codec.version>1.15</commons-codec.version> <commons-codec.version>1.15</commons-codec.version>
<commons-pool2.version>2.11.1</commons-pool2.version> <commons-pool2.version>2.11.1</commons-pool2.version>
<gson.version>2.8.9</gson.version> <gson.version>2.8.9</gson.version>
<netty-tcnative.version>2.0.59.Final</netty-tcnative.version> <netty-tcnative.version>2.0.61.Final</netty-tcnative.version>
<spring-cloud.version>2.2.9.RELEASE</spring-cloud.version> <spring-cloud.version>2.2.9.RELEASE</spring-cloud.version>
<snakeyaml.version>1.33</snakeyaml.version> <snakeyaml.version>1.33</snakeyaml.version>
<spring-data-releasetrain.version>Moore-SR13</spring-data-releasetrain.version>--> <spring-data-releasetrain.version>Moore-SR13</spring-data-releasetrain.version>-->

View File

@@ -56,11 +56,8 @@ import reactor.core.scheduler.Schedulers;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
/** /**
* @author Francis Dong * @author Francis Dong
@@ -160,6 +157,9 @@ public class AggregateFilter implements WebFilter {
clientInput.put("headers", headers); clientInput.put("headers", headers);
clientInput.put("params", MapUtil.toHashMap(request.getQueryParams())); clientInput.put("params", MapUtil.toHashMap(request.getQueryParams()));
clientInput.put("contentType", request.getHeaders().getFirst(CommonConstants.HEADER_CONTENT_TYPE)); clientInput.put("contentType", request.getHeaders().getFirst(CommonConstants.HEADER_CONTENT_TYPE));
Map<String, Object> pathParams = (Map<String, Object>) com.fizzgate.util.ThreadContext.get("pathParams");
clientInput.put("pathParams", pathParams == null ? Collections.emptyMap() : pathParams);
com.fizzgate.util.ThreadContext.remove("pathParams");
Mono<AggregateResult> result = null; Mono<AggregateResult> result = null;
MediaType contentType = request.getHeaders().getContentType(); MediaType contentType = request.getHeaders().getContentType();

View File

@@ -17,6 +17,25 @@
package com.fizzgate.filter; package com.fizzgate.filter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.fizzgate.config.AggregateRedisConfig; import com.fizzgate.config.AggregateRedisConfig;
import com.fizzgate.plugin.auth.ApiConfig; import com.fizzgate.plugin.auth.ApiConfig;
@@ -33,26 +52,8 @@ import com.fizzgate.util.Consts;
import com.fizzgate.util.NettyDataBufferUtils; import com.fizzgate.util.NettyDataBufferUtils;
import com.fizzgate.util.ThreadContext; import com.fizzgate.util.ThreadContext;
import com.fizzgate.util.WebUtils; import com.fizzgate.util.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
/** /**
* @author hongqiaowei * @author hongqiaowei
*/ */
@@ -88,6 +89,7 @@ public class CallbackFilter extends FizzWebFilter {
@Resource @Resource
private GatewayGroupService gatewayGroupService; private GatewayGroupService gatewayGroupService;
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String traceId = WebUtils.getTraceId(exchange); String traceId = WebUtils.getTraceId(exchange);
@@ -228,7 +230,7 @@ public class CallbackFilter extends FizzWebFilter {
if (body != null) { if (body != null) {
b.append(Consts.S.COMMA); b.append(Consts.S.COMMA);
// String bodyStr = body.toString(StandardCharsets.UTF_8); // String bodyStr = body.toString(StandardCharsets.UTF_8);
String bodyStr = body.toString(); String bodyStr = body.toString();
MediaType contentType = req.getHeaders().getContentType(); MediaType contentType = req.getHeaders().getContentType();
if (contentType != null && contentType.getSubtype().equalsIgnoreCase(json)) { if (contentType != null && contentType.getSubtype().equalsIgnoreCase(json)) {

View File

@@ -27,6 +27,7 @@ import com.fizzgate.fizz.input.InputType;
import com.fizzgate.util.Consts; import com.fizzgate.util.Consts;
import com.fizzgate.util.ReactorUtils; import com.fizzgate.util.ReactorUtils;
import com.fizzgate.util.UrlTransformUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.ThreadContext;
import org.noear.snack.ONode; import org.noear.snack.ONode;
@@ -50,6 +51,7 @@ import java.lang.ref.SoftReference;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static com.fizzgate.config.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE; import static com.fizzgate.config.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
import static com.fizzgate.util.Consts.S.FORWARD_SLASH; import static com.fizzgate.util.Consts.S.FORWARD_SLASH;
@@ -388,6 +390,47 @@ public class ConfigLoader {
ClientInputConfig cfg = (ClientInputConfig) input.getConfig(); ClientInputConfig cfg = (ClientInputConfig) input.getConfig();
return new AggregateResource(pipeline, input); return new AggregateResource(pipeline, input);
} }
} else {
String aggrMethodPath = null;
try {
for (Map.Entry<String, String> entry : aggregateResources.entrySet()) {
aggrMethodPath = entry.getKey();
boolean match = UrlTransformUtils.ANT_PATH_MATCHER.match(aggrMethodPath, key);
if (match) {
String configStr = aggregateResources.get(aggrMethodPath);
Input input = createInput(configStr);
Pipeline pipeline = createPipeline(configStr);
if (pipeline != null && input != null) {
Map<String, String> pathVariables = UrlTransformUtils.ANT_PATH_MATCHER.extractUriTemplateVariables(aggrMethodPath, key);
Map<String, Object> map = Collections.emptyMap();
if (!CollectionUtils.isEmpty(pathVariables)) {
map = pathVariables.entrySet().stream().filter(
e -> {
return e.getKey().indexOf('$') == -1;
}
)
.collect(
Collectors.toMap(
Map.Entry::getKey,
e -> {
return (Object) e.getValue();
}
)
);
}
com.fizzgate.util.ThreadContext.set("pathParams", map);
return new AggregateResource(pipeline, input);
} else {
LOGGER.warn("request {} match {}, input {} pipeline {}", key, aggrMethodPath, input, pipeline);
return null;
}
}
}
} catch (IOException e) {
LOGGER.warn("request {} match {}, create input or pipeline error", key, aggrMethodPath, e);
return null;
}
} }
return null; return null;
} }

View File

@@ -242,6 +242,7 @@ public class Pipeline {
inputRequest.put("method", clientInput.get("method")); inputRequest.put("method", clientInput.get("method"));
inputRequest.put("headers", clientInput.get("headers")); inputRequest.put("headers", clientInput.get("headers"));
inputRequest.put("params", clientInput.get("params")); inputRequest.put("params", clientInput.get("params"));
inputRequest.put("pathParams", clientInput.get("pathParams"));
stepContext.addFilePartMap((Map<String, FilePart>) clientInput.get("filePartMap")); stepContext.addFilePartMap((Map<String, FilePart>) clientInput.get("filePartMap"));
if (CONTENT_TYPE_XML.equals(config.getContentType()) || (StringUtils.isEmpty(config.getContentType()) if (CONTENT_TYPE_XML.equals(config.getContentType()) || (StringUtils.isEmpty(config.getContentType())

View File

@@ -25,7 +25,6 @@ import com.fizzgate.stats.TimeSlot;
import com.fizzgate.stats.TimeWindowStat; import com.fizzgate.stats.TimeWindowStat;
import com.fizzgate.util.JacksonUtils; import com.fizzgate.util.JacksonUtils;
import com.fizzgate.util.ResourceIdUtils; import com.fizzgate.util.ResourceIdUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -35,8 +34,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
/** /**
@@ -159,6 +157,8 @@ public class CircuitBreaker {
public final AtomicReference<State> stateRef = new AtomicReference<>(State.CLOSED); public final AtomicReference<State> stateRef = new AtomicReference<>(State.CLOSED);
public final AtomicBoolean noProbe = new AtomicBoolean(true);
public long stateStartTime; public long stateStartTime;
public CircuitBreaker() { public CircuitBreaker() {
@@ -262,7 +262,7 @@ public class CircuitBreaker {
} }
private boolean isResumeTraffic(long currentTimeWindow, FlowStat flowStat) { private boolean isResumeTraffic(long currentTimeWindow, FlowStat flowStat) {
long nThSecond = getStateDuration(currentTimeWindow); long nThSecond = getStateDuration(currentTimeWindow) / 1000;
GradualResumeTimeWindowContext ctx = gradualResumeTimeWindowContexts.get((int) nThSecond); GradualResumeTimeWindowContext ctx = gradualResumeTimeWindowContexts.get((int) nThSecond);
ResourceStat resourceStat = flowStat.getResourceStat(resource); ResourceStat resourceStat = flowStat.getResourceStat(resource);
return ctx.permit(resourceStat, currentTimeWindow); return ctx.permit(resourceStat, currentTimeWindow);
@@ -282,9 +282,20 @@ public class CircuitBreaker {
transit(s, State.CLOSED, currentTimeWindow, flowStat); transit(s, State.CLOSED, currentTimeWindow, flowStat);
} else if (s == State.OPEN && stateDuration > breakDuration) { } else if (s == State.OPEN && stateDuration > breakDuration) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, correct to CLOSED state", if (resumeStrategy == ResumeStrategy.IMMEDIATE) {
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration); LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, correct to CLOSED state",
transit(s, State.CLOSED, currentTimeWindow, flowStat); currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
transit(s, State.CLOSED, currentTimeWindow, flowStat);
} else if (resumeStrategy == ResumeStrategy.DETECTIVE) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, resume detective",
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
noProbe.set(true);
transit(s, State.RESUME_DETECTIVE, currentTimeWindow, flowStat);
} else if (resumeStrategy == ResumeStrategy.GRADUAL) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, resume gradual",
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
transit(s, State.RESUME_GRADUALLY, currentTimeWindow, flowStat);
}
} else if (s == State.RESUME_GRADUALLY && stateDuration > resumeDuration) { } else if (s == State.RESUME_GRADUALLY && stateDuration > resumeDuration) {
LOGGER.debug("current time window {}, {} last {} second in {} large than resume duration {}, correct to CLOSED state", LOGGER.debug("current time window {}, {} last {} second in {} large than resume duration {}, correct to CLOSED state",
@@ -293,36 +304,9 @@ public class CircuitBreaker {
} }
} }
/*public void correctCircuitBreakerStateAsError(long currentTimeWindow, FlowStat flowStat) {
if (stateRef.get() == State.CLOSED) {
long endTimeWindow = currentTimeWindow + 1000;
// TimeWindowStat timeWindowStat = flowStat.getTimeWindowStat(resource, endTimeWindow - monitorDuration, endTimeWindow);
TimeWindowStat timeWindowStat = flowStat.getTimeWindowStat(resource, stateStartTime, endTimeWindow);
long reqCount = timeWindowStat.getCompReqs();
long errCount = timeWindowStat.getErrors();
if (breakStrategy == BreakStrategy.TOTAL_ERRORS && reqCount >= minRequests && errCount >= totalErrorThreshold) {
LOGGER.debug("{} current time window {} request count {} >= min requests {} error count {} >= total error threshold {}, correct to OPEN state as error",
resource, currentTimeWindow, reqCount, minRequests, errCount, totalErrorThreshold);
transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat);
} else if (breakStrategy == BreakStrategy.ERRORS_RATIO && reqCount >= minRequests) {
BigDecimal errors = new BigDecimal(errCount);
BigDecimal requests = new BigDecimal(reqCount);
float p = errors.divide(requests, 2, RoundingMode.HALF_UP).floatValue();
if (p - errorRatioThreshold >= 0) {
LOGGER.debug("{} current time window {} request count {} >= min requests {} error ratio {} >= error ratio threshold {}, correct to OPEN state as error",
resource, currentTimeWindow, reqCount, minRequests, p, errorRatioThreshold);
transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat);
}
}
}
}*/
public boolean transit(State current, State target, long currentTimeWindow, FlowStat flowStat) { public boolean transit(State current, State target, long currentTimeWindow, FlowStat flowStat) {
if (stateRef.compareAndSet(current, target)) { if (stateRef.compareAndSet(current, target)) {
ResourceStat resourceStat = flowStat.getResourceStat(resource); ResourceStat resourceStat = flowStat.getResourceStat(resource);
/*AtomicLong circuitBreakNum = resourceStat.getTimeSlot(currentTimeWindow).getCircuitBreakNum();
circuitBreakNum.set(0);*/
resourceStat.getTimeSlot(currentTimeWindow).setCircuitBreakNum(0); resourceStat.getTimeSlot(currentTimeWindow).setCircuitBreakNum(0);
resourceStat.updateCircuitBreakState(currentTimeWindow, current, target); resourceStat.updateCircuitBreakState(currentTimeWindow, current, target);
LOGGER.debug("transit {} current time window {} from {} which start at {} to {}", resource, currentTimeWindow, current, stateStartTime, target); LOGGER.debug("transit {} current time window {} from {} which start at {} to {}", resource, currentTimeWindow, current, stateStartTime, target);
@@ -333,19 +317,25 @@ public class CircuitBreaker {
} }
public boolean permit(ServerWebExchange exchange, long currentTimeWindow, FlowStat flowStat) { public boolean permit(ServerWebExchange exchange, long currentTimeWindow, FlowStat flowStat) {
correctState(currentTimeWindow, flowStat);
if (stateRef.get() == State.CLOSED) { if (stateRef.get() == State.CLOSED) {
return permitCallInClosedState(currentTimeWindow, flowStat); return permitCallInClosedState(currentTimeWindow, flowStat);
} }
if (stateRef.get() == State.OPEN) { if (stateRef.get() == State.OPEN) {
return permitCallInOpenState(exchange, currentTimeWindow, flowStat);
}
if (stateRef.get() == State.RESUME_DETECTIVE) {
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow); flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
LOGGER.debug("{} current time window {} in {} which start at {}, reject current request", resource, currentTimeWindow, stateRef.get(), stateStartTime);
return false; return false;
} }
if (stateRef.get() == State.RESUME_DETECTIVE) {
if (noProbe.compareAndSet(true, false)) {
exchange.getAttributes().put(DETECT_REQUEST, this);
return true;
} else {
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
return false;
}
}
if (stateRef.get() == State.RESUME_GRADUALLY) { if (stateRef.get() == State.RESUME_GRADUALLY) {
return permitCallInResumeGraduallyState(currentTimeWindow, flowStat); return isResumeTraffic(currentTimeWindow, flowStat);
} }
return true; return true;
} }
@@ -353,13 +343,12 @@ public class CircuitBreaker {
private boolean permitCallInClosedState(long currentTimeWindow, FlowStat flowStat) { private boolean permitCallInClosedState(long currentTimeWindow, FlowStat flowStat) {
long endTimeWindow = currentTimeWindow + 1000; long endTimeWindow = currentTimeWindow + 1000;
// TimeWindowStat timeWindowStat = flowStat.getTimeWindowStat(resource, endTimeWindow - monitorDuration, endTimeWindow);
TimeWindowStat timeWindowStat = flowStat.getTimeWindowStat(resource, stateStartTime, endTimeWindow); TimeWindowStat timeWindowStat = flowStat.getTimeWindowStat(resource, stateStartTime, endTimeWindow);
long reqCount = timeWindowStat.getCompReqs(); long reqCount = timeWindowStat.getCompReqs();
long errCount = timeWindowStat.getErrors(); long errCount = timeWindowStat.getErrors();
if (breakStrategy == BreakStrategy.TOTAL_ERRORS && reqCount >= minRequests && errCount >= totalErrorThreshold) { if (breakStrategy == BreakStrategy.TOTAL_ERRORS && reqCount >= minRequests && errCount >= totalErrorThreshold) {
LOGGER.debug("{} current time window {} request count {} >= min requests {} error count {} >= total error threshold {}", LOGGER.debug("{} current time window {} request count {} >= min requests {} error count {} >= total error threshold {}, reject request",
resource, currentTimeWindow, reqCount, minRequests, errCount, totalErrorThreshold); resource, currentTimeWindow, reqCount, minRequests, errCount, totalErrorThreshold);
transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat); transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat);
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow); flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
@@ -370,7 +359,7 @@ public class CircuitBreaker {
BigDecimal requests = new BigDecimal(reqCount); BigDecimal requests = new BigDecimal(reqCount);
float p = errors.divide(requests, 2, RoundingMode.HALF_UP).floatValue(); float p = errors.divide(requests, 2, RoundingMode.HALF_UP).floatValue();
if (p - errorRatioThreshold >= 0) { if (p - errorRatioThreshold >= 0) {
LOGGER.debug("{} current time window {} request count {} >= min requests {} error ratio {} >= error ratio threshold {}", LOGGER.debug("{} current time window {} request count {} >= min requests {} error ratio {} >= error ratio threshold {}, reject request",
resource, currentTimeWindow, reqCount, minRequests, p, errorRatioThreshold); resource, currentTimeWindow, reqCount, minRequests, p, errorRatioThreshold);
transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat); transit(State.CLOSED, State.OPEN, currentTimeWindow, flowStat);
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow); flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
@@ -378,54 +367,11 @@ public class CircuitBreaker {
} }
} }
LOGGER.debug("{} current time window {} in {} which start at {}, permit current request", resource, currentTimeWindow, stateRef.get(), stateStartTime); LOGGER.debug("{} current time window {} in {} which start at {}, permit request", resource, currentTimeWindow, stateRef.get(), stateStartTime);
return true; return true;
} }
private boolean permitCallInOpenState(ServerWebExchange exchange, long currentTimeWindow, FlowStat flowStat) {
long stateDuration = getStateDuration(currentTimeWindow);
if (stateDuration > breakDuration) {
if (resumeStrategy == ResumeStrategy.IMMEDIATE) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, resume immediately",
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
transit(State.OPEN, State.CLOSED, currentTimeWindow, flowStat);
return true;
}
if (resumeStrategy == ResumeStrategy.DETECTIVE) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, resume detective",
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
if (transit(State.OPEN, State.RESUME_DETECTIVE, currentTimeWindow, flowStat)) {
exchange.getAttributes().put(DETECT_REQUEST, this);
return true;
}
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
return false;
}
if (resumeStrategy == ResumeStrategy.GRADUAL) {
LOGGER.debug("current time window {}, {} last {} second in {} large than break duration {}, resume gradual",
currentTimeWindow, resource, stateDuration, stateRef.get(), breakDuration);
transit(State.OPEN, State.RESUME_GRADUALLY, currentTimeWindow, flowStat);
return isResumeTraffic(currentTimeWindow, flowStat);
}
}
flowStat.getResourceStat(resource).incrCircuitBreakNum(currentTimeWindow);
LOGGER.debug("{} current time window {} in {} which start at {}, reject current request", resource, currentTimeWindow, stateRef.get(), stateStartTime);
return false;
}
private boolean permitCallInResumeGraduallyState(long currentTimeWindow, FlowStat flowStat) {
long stateDuration = getStateDuration(currentTimeWindow);
if (stateDuration > resumeDuration) {
LOGGER.debug("current time window {}, {} last {} second in {} large than resume duration {}, resume immediately",
currentTimeWindow, resource, stateDuration, stateRef.get(), resumeDuration);
transit(State.RESUME_GRADUALLY, State.CLOSED, currentTimeWindow, flowStat);
return true;
}
return isResumeTraffic(currentTimeWindow, flowStat);
}
@Override @Override
public String toString() { public String toString() {
return JacksonUtils.writeValueAsString(this); return JacksonUtils.writeValueAsString(this);

View File

@@ -101,7 +101,8 @@ public class CallbackServiceTests {
) )
); );
Mono<Void> vm = callbackService.requestBackends(exchange, headers, body, callbackConfig, Collections.EMPTY_MAP); // Mono<Void> vm = callbackService.requestBackends(exchange, headers, body, callbackConfig, Collections.EMPTY_MAP);
Mono<Void> vm = callbackService.requestBackends(exchange, headers, null, callbackConfig, Collections.EMPTY_MAP);
vm.subscribe(); vm.subscribe();
Thread.sleep(2000); Thread.sleep(2000);

View File

@@ -27,6 +27,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@TestPropertySource("/application.properties") @TestPropertySource("/application.properties")
@@ -108,4 +109,119 @@ public class CircuitBreakManagerTests {
Assertions.assertEquals(CircuitBreaker.State.OPEN, timeSlot.getCircuitBreakState().get()); Assertions.assertEquals(CircuitBreaker.State.OPEN, timeSlot.getCircuitBreakState().get());
Assertions.assertEquals(2, timeSlot.getCircuitBreakNum()); Assertions.assertEquals(2, timeSlot.getCircuitBreakNum());
} }
@Test
void detectiveResumeTest() throws InterruptedException {
FlowStat flowStat = new FlowStat(circuitBreakManager);
flowStat.cleanResource = false;
flowStat.createTimeSlotOnlyTraffic = false;
long currentTimeWindow = flowStat.currentTimeSlotId();
MockServerHttpRequest mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
MockServerWebExchange mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
String service = "xservice";
String path = "ypath";
CircuitBreaker cb = new CircuitBreaker();
cb.service = service;
cb.path = path;
cb.resource = ResourceIdUtils.buildResourceId(null, null, null, service, path);
cb.breakStrategy = CircuitBreaker.BreakStrategy.TOTAL_ERRORS;
cb.monitorDuration = 5 * 1000;
cb.minRequests = 100;
cb.totalErrorThreshold = 10;
cb.breakDuration = 2 * 1000;
cb.resumeStrategy = CircuitBreaker.ResumeStrategy.DETECTIVE;
cb.stateStartTime = currentTimeWindow;
Map<String, CircuitBreaker> circuitBreakerMap = circuitBreakManager.getResource2circuitBreakerMap();
circuitBreakerMap.put(cb.resource, cb);
ResourceStat resourceStat = flowStat.getResourceStat(cb.resource);
TimeSlot timeSlot = resourceStat.getTimeSlot(currentTimeWindow);
timeSlot.setCompReqs(200);
timeSlot.setErrors(11);
boolean permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertFalse(permit);
Assertions.assertEquals(CircuitBreaker.State.OPEN, cb.stateRef.get());
Thread.sleep(3000);
Assertions.assertEquals(CircuitBreaker.State.RESUME_DETECTIVE, cb.stateRef.get());
currentTimeWindow = flowStat.currentTimeSlotId();
mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertTrue(permit);
Assertions.assertEquals(CircuitBreaker.State.RESUME_DETECTIVE, cb.stateRef.get());
Assertions.assertFalse(cb.noProbe.get());
currentTimeWindow = flowStat.currentTimeSlotId();
mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertEquals(CircuitBreaker.State.RESUME_DETECTIVE, cb.stateRef.get());
Assertions.assertFalse(permit);
cb.transit(CircuitBreaker.State.RESUME_DETECTIVE, CircuitBreaker.State.CLOSED, currentTimeWindow, flowStat); // mock probe request success
currentTimeWindow = flowStat.currentTimeSlotId();
mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertEquals(CircuitBreaker.State.CLOSED, cb.stateRef.get());
Assertions.assertTrue(permit);
}
@Test
void gradualResumeTest() throws InterruptedException {
FlowStat flowStat = new FlowStat(circuitBreakManager);
flowStat.cleanResource = false;
flowStat.createTimeSlotOnlyTraffic = false;
long currentTimeWindow = flowStat.currentTimeSlotId();
MockServerHttpRequest mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
MockServerWebExchange mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
String service = "xservice";
String path = "ypath";
CircuitBreaker cb = new CircuitBreaker();
cb.service = service;
cb.path = path;
cb.resource = ResourceIdUtils.buildResourceId(null, null, null, service, path);
cb.breakStrategy = CircuitBreaker.BreakStrategy.TOTAL_ERRORS;
cb.monitorDuration = 5 * 1000;
cb.minRequests = 100;
cb.totalErrorThreshold = 10;
cb.breakDuration = 2 * 1000;
cb.resumeStrategy = CircuitBreaker.ResumeStrategy.GRADUAL;
cb.resumeDuration = 3 * 1000;
cb.stateStartTime = currentTimeWindow;
cb.initGradualResumeTimeWindowContext();
Map<String, CircuitBreaker> circuitBreakerMap = circuitBreakManager.getResource2circuitBreakerMap();
circuitBreakerMap.put(cb.resource, cb);
ResourceStat resourceStat = flowStat.getResourceStat(cb.resource);
TimeSlot timeSlot = resourceStat.getTimeSlot(currentTimeWindow);
timeSlot.setCompReqs(200);
timeSlot.setErrors(11);
boolean permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertFalse(permit);
Assertions.assertEquals(CircuitBreaker.State.OPEN, cb.stateRef.get());
Thread.sleep(3000);
Assertions.assertEquals(CircuitBreaker.State.RESUME_GRADUALLY, cb.stateRef.get());
currentTimeWindow = flowStat.currentTimeSlotId();
mockServerHttpRequest = MockServerHttpRequest.get("/xxx").build();
mockServerWebExchange = MockServerWebExchange.from(mockServerHttpRequest);
permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
Assertions.assertTrue(permit);
for (int i = 0; i < 68; i++) {
permit = circuitBreakManager.permit(mockServerWebExchange, currentTimeWindow, flowStat, service, path);
}
Assertions.assertFalse(permit);
}
} }

View File

@@ -6,11 +6,11 @@
<properties> <properties>
<!--<java.version>1.8</java.version>--> <!--<java.version>1.8</java.version>-->
<spring-boot.version>2.2.13.RELEASE</spring-boot.version> <spring-boot.version>2.2.13.RELEASE</spring-boot.version>
<spring-framework.version>5.2.23.RELEASE</spring-framework.version> <spring-framework.version>5.2.24.RELEASE</spring-framework.version>
<reactor-bom.version>Dysprosium-SR25</reactor-bom.version> <reactor-bom.version>Dysprosium-SR25</reactor-bom.version>
<lettuce.version>5.3.7.RELEASE</lettuce.version> <lettuce.version>5.3.7.RELEASE</lettuce.version>
<nacos.cloud.version>2.2.7.RELEASE</nacos.cloud.version> <nacos.cloud.version>2.2.7.RELEASE</nacos.cloud.version>
<netty.version>4.1.91.Final</netty.version> <netty.version>4.1.93.Final</netty.version>
<httpcore.version>4.4.16</httpcore.version> <httpcore.version>4.4.16</httpcore.version>
<log4j2.version>2.17.2</log4j2.version> <log4j2.version>2.17.2</log4j2.version>
<slf4j.version>1.7.36</slf4j.version> <slf4j.version>1.7.36</slf4j.version>
@@ -22,7 +22,7 @@
<r2dbc-mysql.version>0.8.2</r2dbc-mysql.version> <r2dbc-mysql.version>0.8.2</r2dbc-mysql.version>
<reflections.version>0.9.11</reflections.version> <reflections.version>0.9.11</reflections.version>
<commons-pool2.version>2.11.1</commons-pool2.version> <commons-pool2.version>2.11.1</commons-pool2.version>
<netty-tcnative.version>2.0.59.Final</netty-tcnative.version> <netty-tcnative.version>2.0.61.Final</netty-tcnative.version>
<spring-cloud.version>2.2.9.RELEASE</spring-cloud.version> <spring-cloud.version>2.2.9.RELEASE</spring-cloud.version>
<snakeyaml.version>1.33</snakeyaml.version> <snakeyaml.version>1.33</snakeyaml.version>
<spring-data-releasetrain.version>Moore-SR13</spring-data-releasetrain.version> <spring-data-releasetrain.version>Moore-SR13</spring-data-releasetrain.version>