随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel
以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
在前面我们通过以下章节对Sentinel
有了基础的了解:
Sentinel:分布式系统的流量防卫兵 | Spring Cloud 19
Sentinel:资源与规则定义 | Spring Cloud 20
Sentinel:原理深入浅出解读 | Spring Cloud 21
Sentinel:流量控制规则定义详解 | Spring Cloud 22
Spring Boot/Cloud集成Sentinel实现流量控制 | Spring Cloud 23
Spring Boot/Cloud集成Sentinel实现流量控制 (二) | Spring Cloud 24
现在开始我们正式学习Sentinel
在Spring Boot/Cloud
中的集成使用。
书接上回,本节进行对以下部分进行集成演示:
知识点,当应用的 ApplicationContext
中存在对应的Bean
的类型时,会进行自动化设置:
存在Bean的类型 | 操作 | 作用 |
---|---|---|
UrlCleaner | WebCallbackManager.setUrlCleaner(urlCleaner) | 资源清理(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下) |
UrlBlockHandler | WebCallbackManager.setUrlBlockHandler(urlBlockHandler) | 自定义限流处理逻辑 |
RequestOriginParser | WebCallbackManager.setRequestOriginParser(requestOriginParser) | 设置来源信息 |
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel
的来源访问控制(黑白名单控制)的功能。
来源访问控制根据资源的请求来源(origin
)限制资源是否通过:
调用方信息通过
ContextUtil.enter(resourceName, origin)
方法中的origin
参数传入。
来源访问控制规则(AuthorityRule
)非常简单,主要有以下配置项:
resource
:资源名,即限流规则的作用对象。limitApp
:对应的黑名单/白名单,不同 origin
用 , 分隔,如 appA,appB
。strategy
:限制模式,AUTHORITY_WHITE
为白名单模式,AUTHORITY_BLACK
为黑名单模式,默认为白名单模式。以上篇文章的
sentinel-nacos-consumer
模块为基础进行扩展。
Sentinel
提供多样化的 SPI
接口用于提供扩展的能力。
其中包括:初始化过程扩展,供 InitFunc SPI
接口,添加自定义的一些初始化逻辑,如动态规则源注册。
com/gm/sentinel_nacos_consumer/init/FileDataSourceInit.java
:
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import java.net.URLDecoder;
import java.util.List;public class FileDataSourceInit implements InitFunc {@Overridepublic void init() throws Exception {loadAuthorityRule();loadFlowRule();}private String encodeJson(T t) {return JSON.toJSONString(t);}private void loadAuthorityRule() throws Exception {ClassLoader classLoader = getClass().getClassLoader();String authorityRulePath = URLDecoder.decode(classLoader.getResource("rules/AuthorityRule.json").getFile(), "UTF-8");ReadableDataSource> ds = new FileRefreshableDataSource<>(authorityRulePath, source -> JSON.parseObject(source, new TypeReference>() {}));// 将可读数据源注册至 AuthorityRuleManager.AuthorityRuleManager.register2Property(ds.getProperty());WritableDataSource> wds = new FileWritableDataSource<>(authorityRulePath, this::encodeJson);// 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.// 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.WritableDataSourceRegistry.registerAuthorityDataSource(wds);}private void loadFlowRule() throws Exception {ClassLoader classLoader = getClass().getClassLoader();String flowRulePath = URLDecoder.decode(classLoader.getResource("rules/FlowRule.json").getFile(), "UTF-8");ReadableDataSource> ds = new FileRefreshableDataSource<>(flowRulePath, source -> JSON.parseObject(source, new TypeReference>() {}));// 将可读数据源注册至 FlowRuleManager.FlowRuleManager.register2Property(ds.getProperty());WritableDataSource> wds = new FileWritableDataSource<>(flowRulePath, this::encodeJson);// 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.// 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.WritableDataSourceRegistry.registerFlowDataSource(wds);}
}
本地文件数据源会定时轮询文件的变更,读取规则。这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel
控制台推送规则。以本地文件数据源为例,推送过程如下图所示:
首先 Sentinel
控制台通过 API
将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。使用 pull
模式的数据源时一般不需要对 Sentinel
控制台进行改造。
这种实现方法好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性。
src/main/resources/META-INF/services/com.alibaba.csp.sentinel.init.InitFunc
:
com.gm.sentinel_nacos_consumer.init.FileDataSourceInit
利用上文提到的知识点,自定义RequestOriginParser
实现设置来源信息。
com/gm/sentinel_nacos_consumer/component/CustomRequestOriginParser.java
:
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Component
public class CustomRequestOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {String origin = httpServletRequest.getParameter("origin");if (!StringUtils.isEmpty(origin)) {return origin;}return httpServletRequest.getRemoteHost();}
}
授权规则src/main/resources/rules/AuthorityRule.json
:
[{"resource":"message","limitApp":"127.0.0.1","strategy":0
}]
流量控制规则src/main/resources/rules/FlowRule.json
:
[]
利用上文提到的知识点,自定义UrlCleaner
满足如:/urlCleaner/:id
的 URL
都归到 /urlCleaner/*
资源下。
com/gm/sentinel_nacos_consumer/component/CustomUrlCleaner.java
:
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.UrlCleaner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;@Slf4j
@Component
public class CustomUrlCleaner implements UrlCleaner {@Value("#{'${url-cleaner.list}'.split(',')}")private List list;@Overridepublic String clean(String s) {log.info(s);if (StringUtils.isBlank(s)) {return s;}for (String url : list) {if (s.startsWith(url)) {return url + "*";}}return s;}
}
原 com/gm/sentinel_nacos_consumer/controller/ConsumerController.java
新增用于测试资源清理的请求:
/*** 测试UrlCleaner自定义实现URL归类** @param value* @return*/@RequestMapping(value = "say/{value}", method = RequestMethod.GET)public String say(@PathVariable String value) {return value;}/*** 测试UrlCleaner自定义实现URL归类** @param value* @return*/@RequestMapping(value = "clear/{value}", method = RequestMethod.GET)public String clear(@PathVariable String value) {return value;}
调整配置文件src/main/resources/bootstrap.yml
新增要处理的资源清理请求:
url-cleaner:list: /clean/,/say/
先访问:http://127.0.0.1:3000/sayHelloDirect 测试功能是否正常访问:
再次访问:http://192.168.1.82:3000/sayHelloDirect 验证黑白名单控制是否生效:
通过Sentinel
控制台将原本地规则文件设置的限制模式strategy
由白名单切换至黑名单:
再次访问:http://192.168.1.82:3000/sayHelloDirect 验证黑白名单控制是否生效:
验证 Sentinel
控制台推送推着是否已保存至本地文件:
注意文件目录为:
target/classes/rules/AuthorityRule.json
先访问:http://127.0.0.1:3000/say/hello 测试功能是否正常访问:
通过Sentinel
控制台资源清理效果: