前面已經(jīng)講了:微服務整合Sentinel持久化到nacos勿锅。
這里我們說下網(wǎng)關整合sentinel帕膜,網(wǎng)關用的gateway。sentinel官網(wǎng)這里也介紹了網(wǎng)關流控的一些內容溢十。
在前面講微服務整合sentinel持久化到nacos時垮刹,我們把測試代碼中sentinel和nacos交互的類拷貝到了rule模塊中。
在網(wǎng)關gateway中也需要添加類似的代碼张弛。
首先我們看一下官網(wǎng)的介紹:
什么意思荒典?
-
路由維度:也就是我們在gateway網(wǎng)關中配置的路由酪劫,如果觸發(fā)sentinel能夠識別到,并支持添加規(guī)則寺董。
這個路由配置可以在sentinel中發(fā)現(xiàn)覆糟。
-
自定義api維度:我們可以像官方給出的那樣,提前自定義api組遮咖,也可以被sentinel識別滩字,然后添加規(guī)則。我們更多的會用這個御吞,但是我們一般不會提前寫在代碼中麦箍,而是在web頁面自定義api組。官網(wǎng)例子:
說這么多陶珠,主要是想告訴大家挟裂,gateway整合sentinel的時候,不像在微服務中那樣(在微服務中揍诽,sentinel可以直接識別到url粒度的資源话瞧,然后在這些url資源上添加規(guī)則,nacos只需要處理規(guī)則)寝姿,有2個地方需要自己改動:
- 自定義的api資源組交排,需要和nacos交互
- 針對以上資源做的規(guī)則(也包括路由維度的資源),需要和nacos交互
1. sentinel-board后臺源碼修改
注意:這次修改饵筑,是在上次微服務整合sentinel修改完成之后的埃篓,所以是包含上次的修改的。
參考上次sentinel修改的代碼:微服務整合Sentinel持久化到nacos
1.1 添加一些常量根资,用于在nacos中規(guī)則名字的后綴架专、組別:
// 添加 gateway 后綴
public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gateway-api-group";
public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-flow-rules";
上次移過來的nacos的類中:com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil
1.2 nacos的連接中添加bean
上次可以看出,nacos中保存的是json字符串玄帕,是由一些entity直接轉的部脚。上次移過來的,里面只處理了微服務規(guī)則實體和json字符串互轉裤纹。我們現(xiàn)在要添加的是gateway的api組實體委刘、流控規(guī)則實體和json互轉。
/** 新增gateway使用的entity和json串互轉 **/
@Bean
public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() {
return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class);
}
@Bean
public Converter<List<ApiDefinitionEntity>, String> gatewayApiEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<ApiDefinitionEntity>> gatewayApiEntityDecoder() {
return s -> JSON.parseArray(s, ApiDefinitionEntity.class);
}
1.3 添加規(guī)則和api組
對接nacos的實現(xiàn)類
這個就是參考上次的微服務對接nacos的類寫的鹰椒,entity換一下就行锡移,4個,com.alibaba.csp.sentinel.dashboard.rule.gateway
包下:
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
@Component("gatewayApiNacosProvider")
public class GatewayApiNacosProvider implements DynamicRuleProvider<List<ApiDefinitionEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<ApiDefinitionEntity>> converter;
@Override
public List<ApiDefinitionEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
@Component("gatewayApiNacosPublisher")
public class GatewayApiNacosPublisher implements DynamicRulePublisher<List<ApiDefinitionEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<ApiDefinitionEntity>, String> converter;
@Override
public void publish(String app, List<ApiDefinitionEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app+ NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules));
}
}
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
@Component("gatewayFlowRuleNacosProvider")
public class GatewayFlowRuleNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<GatewayFlowRuleEntity>> converter;
@Override
public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
@Component("gatewayFlowRuleNacosPublisher")
public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<GatewayFlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules));
}
}
GatewayApiNacosProvider
:從nacos中讀取已保存的api分組
GatewayApiNacosPublisher
:保存gateway中api分組到nacos
GatewayFlowRuleNacosProvider
:讀取nacos中保存的流控規(guī)則的
GatewayFlowRuleNacosPublisher
:保存gateway中流控規(guī)則到nacos
1.4 修改conrtoller漆际,調用上一步添加的實現(xiàn)類
要修改的內容在com.alibaba.csp.sentinel.dashboard.controller.gateway
包下面淆珊,2個controller:
1.4.1 GatewayApiController
-
注入我們自己的實現(xiàn)類
-
-
保存的時候有一個中間的小方法,我們重寫一下
-
// 重寫保存規(guī)則的方法奸汇,通過新加的實現(xiàn)類保存到nacos
private void publishApis(String app) {
List<ApiDefinitionEntity> apis = repository.findAllByApp(app);
try {
rulePublisher.publish(app, apis);
} catch (Exception e) {
logger.error("推送apis到nacos異常");
}
}
-
修改查
-
-
修改增
-
-
修改刪和改 2處
和增一樣施符,找到地方改
-
1.4.2 GatewayFlowRuleController
-
注入我們自己的實現(xiàn)類
-
-
重寫小方法
-
// 重寫保存規(guī)則的方法往声,通過新加的實現(xiàn)類保存到nacos
private void publishApis(String app) {
List<GatewayFlowRuleEntity> apis = repository.findAllByApp(app);
try {
rulePublisher.publish(app, apis);
} catch (Exception e) {
logger.error("推送流控規(guī)則到nacos異常");
}
}
-
修改增刪改查
-
2. gateway網(wǎng)關服務
2.1 引入jar包
pom.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.zrb.test</groupId>
<artifactId>sentinel-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>gateway-sentinel-server</artifactId>
<version>1.0.0</version>
<name>gateway-sentinel-server</name>
<description>gateway網(wǎng)關</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- openfein -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringCloud在Hoxton.M2版本之后不再使用Ribbon而是使用spring-cloud-loadbalancer,需要自己引入 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<!--nacos客戶端 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--sentinel依賴-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
</dependencies>
<build>
<finalName>gateway-sentinel-server</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 配置文件
application.yml
文件:
# 1.server
server:
port: 8000
# 2.log
logging:
level:
'[org.springframework.cloud.gateway]': info
'[org.springframework.jdbc.core]': debug
# 3.spring
spring:
# 服務名稱必須帶上戳吝,不然nacos服務列表中沒有浩销,也不會有注冊成功的信息
application:
name: gateway-server
# 統(tǒng)一設置返回的時間格式
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: NON_NULL
cloud:
nacos:
config:
import-check:
enabled: false
# server-addr: 192.168.50.89:8848
# file-extension: yaml
discovery:
server-addr: 192.168.50.89:8848
sentinel:
transport:
dashboard: 192.168.50.89:8080
port: 8723
datasource:
gw-flow:
nacos:
server-addr: 192.168.50.89:8848
namespace:
groupId: SENTINEL_GROUP
dataId: ${spring.application.name}-gateway-flow-rules
dataType: json
rule-type: gw-flow
gw-api-group:
nacos:
server-addr: 192.168.50.89:8848
namespace:
groupId: SENTINEL_GROUP
dataId: ${spring.application.name}-gateway-api-group
dataType: json
rule-type: gw-api-group
# gateway
gateway:
discovery:
locator:
enabled: false
lowerCaseServiceId: true
routes:
# 自定義路由 ID
- id: user_route
# 采用 LoadBalanceClient 方式請求,以 lb:// 開頭骨坑,后面的是注冊在 Nacos 上的服務名
uri: lb://user-demo
# Predicate 斷言撼嗓,主要作用是匹配用戶的請求路徑柬采,有很多種用法
predicates:
# 路徑匹配欢唾,一般是指要走網(wǎng)關時要寫的路徑地址
- Path=/api/**
filters:
# 指路由到其他服務時去掉path中幾層路徑,如值為1粉捻,則去掉1層礁遣,即去掉/api
- StripPrefix=1
2.3 加上官方文檔中給的config類
這個可以不用加了,加了會沖突肩刃。順著提示找了一下祟霍,com.alibaba.cloud.sentinel.gateway.scg.SentinelSCGAutoConfiguration
中已經(jīng)有了,而且默認就是開啟了:
所以這類不用加了
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
@Configuration
public class GatewayConfig {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
}
2.4 啟動語句添加配置
網(wǎng)關類型的配置:-Dcsp.sentinel.app.type=1
java -Dcsp.sentinel.app.type=1 -jar *.jar
3. nacos中添加配置文件
分別添加api組和流控規(guī)則的配置文件
4. 測試
將sentinel-dashboard和gateway以及user服務打包啟動盈包。
4.1 添加api組
4.2 添加流控規(guī)則
4.3 請求測試
修改完規(guī)則重啟或者等一分鐘沸呐,避免不必要的麻煩
參考文章:https://blog.csdn.net/admin_15082037343/article/details/130530211