阿里熔断限流Sentinel研究
1. 阿里熔断限流Sentinel研究
1.1. 功能特点
- 丰富的应用场景:例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

开源生态

Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
1.2. 快速开始
1.2.1. 公网接入
根据该步骤,建立demo
控制台效果图



1.3. 手动接入
- 引入pom
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.2</version>
</dependency>
定义资源:也就是对哪个资源进行流量控制,现在已经提供了注解形式,所以新的接入直接用注解,
@SentinelResource- 关于SentinelResource注解,这里列出几个好用和必填的参数,具体参考这里
1.3.1. apollo接入
由于我的系统使用的是apollo管理配置,所以我用apollo来管理规则,官方也提供了apollo的接入说明,然后我想到需要自动提交规则,而不是自己手动去配,又找到了官方的推送例子,可是该例子还是存在问题的,或者说要运行该例子需要对apollo的开放设置有进一步了解
期间我遇到了401问题,是因为需要apollo授权第三方应用,配置token后才能起效;
之后又遇到400问题,是因为openItemDTO.setDataChangeCreatedBy("apollo");和namespaceReleaseDTO.setReleasedBy("apollo");该配置项,例子并不是这么写的,需要将参数改成apollo才行
下面给出完整配置,结合apollo读取配置
@Configuration
@ConditionalOnProperty(name = "sentinel.enabled",havingValue = "true")
@Slf4j
public class SentinelAspectConfiguration {
@Autowired
private ApolloOpenApiClient apolloOpenApiClient;
@Autowired(required = false)
private IRuleManage ruleManage;
@Value("${appId:}")
private String appId;
/**
* 已有配置,可直接使用
*/
@Value("${profile:}")
private String env;
/**
* 没有profile属性配置,则必须配置env
*/
@Value("${env:pro}")
private String envReal;
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
pushlish();
return new SentinelResourceAspect();
}
private void pushlish(){
List<FlowRule> flowRules = null;
if (ruleManage != null) {
flowRules = ruleManage.getFlowRules();
}
if (appId == null) {
return;
}
String flowDataId = appId+"-flow-rules";
String degradeDataId = appId+"-degrade-rules";
if("".equals(env)){
env = envReal;
}
env = env.toUpperCase();
//代码级别的规则,初始化加载,可不实现IRuleManage接口
setRules(flowRules, flowDataId);
//流控
flowConfig(flowDataId);
//降级
degradeConfig(degradeDataId);
}
private void degradeConfig(String degradeDataId) {
//读取
String namespaceName = "application";
String defaultFlowRules = "[]";
ReadableDataSource<String, List<DegradeRule>> degradeRuleDataSource = new ApolloDataSource<>(namespaceName,
degradeDataId, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
}));
DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
//写入配置
WritableDataSource<List<DegradeRule>> wds = new WritableDataSource<List<DegradeRule>>() {
@Override
public void write(List<DegradeRule> rules) throws Exception {
setRules(rules, degradeDataId);
}
@Override
public void close() throws Exception {
log.info("WritableDataSource DegradeRule close");
}
};
WritableDataSourceRegistry.registerDegradeDataSource(wds);
}
private void flowConfig(String flowDataId) {
//读取
String namespaceName = "application";
String defaultFlowRules = "[]";
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ApolloDataSource<>(namespaceName,
flowDataId, defaultFlowRules, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
//写入配置
WritableDataSource<List<FlowRule>> wds = new WritableDataSource<List<FlowRule>>() {
@Override
public void write(List<FlowRule> rules) throws Exception {
setRules(rules, flowDataId);
}
@Override
public void close() throws Exception {
log.info("WritableDataSource FlowRule close");
}
};
WritableDataSourceRegistry.registerFlowDataSource(wds);
}
private void setRules(List rules, String flowDataId) {
if (rules != null && rules.size() > 0) {
// Increase the configuration
OpenItemDTO openItemDTO = new OpenItemDTO();
openItemDTO.setKey(flowDataId);
openItemDTO.setValue(JSON.toJSONString(rules));
openItemDTO.setComment("Program auto-join");
openItemDTO.setDataChangeCreatedBy("apollo");
apolloOpenApiClient.createOrUpdateItem(appId, env, "default", "application", openItemDTO);
// Release configuration
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setEmergencyPublish(true);
namespaceReleaseDTO.setReleaseComment("Modify or add configurations");
namespaceReleaseDTO.setReleasedBy("apollo");
namespaceReleaseDTO.setReleaseTitle("Modify or add configurations");
apolloOpenApiClient.publishNamespace(appId, env, "default", "application", namespaceReleaseDTO);
}
}
}
和
@Configuration
@EnableApolloConfig(value = "application", order = 10)
public class AppBaseConfig {
@Value("${apollo.token}")
private String token;
@Value("${apollo.portalUrl}")
private String portalUrl;
@Value("${sentinel.project.name:}")
private String projectName;
@Value("${spring.application.name:}")
private String applicationName;
@Value("${sentinel.console.server:}")
private String consoleServer;
@Value("${sentinel.heartbeatClient:}")
private String heartbeatClient;
@Bean
@ConditionalOnProperty(name = "sentinel.enabled",havingValue = "true")
public ApolloOpenApiClient apolloOpenApiClient() {
System.setProperty(AppNameUtil.APP_NAME, "".equals(projectName) ? applicationName : projectName);
System.setProperty(TransportConfig.CONSOLE_SERVER, consoleServer);
if (!"".equals(heartbeatClient)) {
String[] split = heartbeatClient.split(":");
System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP, split[0].trim());
System.setProperty(TransportConfig.SERVER_PORT, split[1].trim());
}
ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder()
.withPortalUrl(portalUrl)
.withToken(token)
.build();
return client;
}
}
1.4. 控制台修改规则apollo写入
- 这个功能是可以有的,只是官方文档我没找到,我直接debug源码查看哪里可以把apollo写入加进去,果然发现它是提供了写入接口的
- 写入接口为
WritableDataSource,参考上面的完整代码
1.5. 控制台
- 下载启动控制台,下载地址
- 启动命令
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

登录名密码都是sentinel
1.6. 工作原理
1.7. 问题
1.7.1. 将控制台部署在公网,本机启动连接出现错误日志
2019-07-23 14:57:33.256 ERROR 14788 --- [pool-2-thread-1] c.a.c.s.dashboard.metric.MetricFetcher : Failed to fetch metric from <http://172.16.100.141:8721/metric?startTime=1563865044000&endTime=1563865050000&refetch=false> (ConnectionException: Connection refused: no further information)
说明发送了内网地址,导致fetch拉取埋点信息不通
我通过System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP, split[0].trim());设置心跳地址为外网地址解决这个问题
本质上是因为控制台主动通过接口来客户端拉信息,但若是访问不通,也是没辙,所以本地测试部在服务器上的控制台,除非外网映射
1.7.2. 部署上去后发现可以访问通,且项目注册进来了,但没有任何调用信息,且没有任何规则信息
我的这个问题基础是因为我部署到docker上的,之后debug源码,发现控制台调用客户端的地址是我根本没配过的,深入后发现如下代码段
Runnable serverInitTask = new Runnable() {
int port;
{
try {
port = Integer.parseInt(TransportConfig.getPort());
} catch (Exception e) {
port = DEFAULT_PORT;
}
}
@Override
public void run() {
boolean success = false;
ServerSocket serverSocket = getServerSocketFromBasePort(port);
if (serverSocket != null) {
CommandCenterLog.info("[CommandCenter] Begin listening at port " + serverSocket.getLocalPort());
socketReference = serverSocket;
executor.submit(new ServerThread(serverSocket));
success = true;
port = serverSocket.getLocalPort();
} else {
CommandCenterLog.info("[CommandCenter] chooses port fail, http command center will not work");
}
if (!success) {
port = PORT_UNINITIALIZED;
}
TransportConfig.setRuntimePort(port);
executor.shutdown();
}
};
new Thread(serverInitTask).start();
该代码段的作用是为客户端在分配一个socketServer,之后的信息交互都是通过该服务提供的端口来提供;
这样一来客户端需要额外提供一个端口了,而我的docker只暴露了1个服务端口,所以不可避免的会出现问题,以上是我到目前的思路,正在验证中
至于端口如何决定,它是用了一个简单的技巧,若设置了csp.sentinel.api.port配置项,则会取该配置端口,若没有设,则是默认端口8719;但如果你用的是官网的启动方式,那8719应该是被控制台占用了,所以进入小技巧getServerSocketFromBasePort方法,内容如下
private static ServerSocket getServerSocketFromBasePort(int basePort) {
int tryCount = 0;
while (true) {
try {
ServerSocket server = new ServerSocket(basePort + tryCount / 3, 100);
server.setReuseAddress(true);
return server;
} catch (IOException e) {
tryCount++;
try {
TimeUnit.MILLISECONDS.sleep(30);
} catch (InterruptedException e1) {
break;
}
}
}
return null;
}
它会循环尝试端口是否被占用,每个端口尝试三次,若被占用则取下一个+1端口,一直到可用的端口返回;所以如果我们的客户端应用放到了docker,而开放的端口只有一个,那就获取不了信息了
这里csp.sentinel.api.port配置项很容易理解成客户端的端口地址,因为启动也不会报错啥的,会误让我们误会这个参数可以不填,虽然文档上写着必填,但本地测试的时候可没影响-_-||,所有都注意了,这个配置项是必填的
- 还要注意一点,因为是socket连接,两边端口要一致,所以docker端口号映射需要一样
阿里熔断限流Sentinel研究的更多相关文章
- 微服务熔断限流Hystrix之流聚合
简介 上一篇介绍了 Hystrix Dashboard 监控单体应用的例子,在生产环境中,监控的应用往往是一个集群,我们需要将每个实例的监控信息聚合起来分析,这就用到了 Turbine 工具.Turb ...
- Envoy熔断限流实践(二)Rainbond基于RLS服务全局限流
Envoy 可以作为 Sevice Mesh 微服务框架中的代理实现方案,Rainbond 内置的微服务框架同样基于 Envoy 实现.本文所描述的全局限速实践也是基于 Envoy 已有的方案所实现. ...
- Envoy熔断限流实践(一)基于Rainbond插件实现熔断
Envoy 可以作为 Sevice Mesh 微服务框架中的代理实现方案,Rainbond 内置的微服务框架同样基于 Envoy 实现.本文所描述的熔断实践基于 Rainbond 特有的插件机制实现. ...
- 微服务熔断限流Hystrix之Dashboard
简介 Hystrix Dashboard是一款针对Hystrix进行实时监控的工具,通过Hystrix Dashboard可以直观地看到各Hystrix Command的请求响应时间,请求成功率等数据 ...
- Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结
在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...
- Spring Cloud alibaba网关 sentinel zuul 四 限流熔断
spring cloud alibaba 集成了 他内部开源的 Sentinel 熔断限流框架 Sentinel 介绍 官方网址 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentine ...
- Dubbo使用Sentinel来对服务进行降级与限流
一.Sentinel 是什么 Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定 ...
- Spring Cloud Alibaba基础教程:使用Sentinel实现接口限流
最近管点闲事浪费了不少时间,感谢网友libinwalan的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一 ...
- Spring Cloud Alibaba | Sentinel: 服务限流高级篇
目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...
随机推荐
- CNCF LandScape Summary
CNCF Cloud Native Interactive Landscape 1. App Definition and Development 1. Database Vitess:itess i ...
- JavaScript词法作用域—你不知道的JavaScript上卷读书笔记(一)
前段时间在每天往返的地铁上抽空将 <你不知道的JavaScript(上卷)>读了一遍,这本书很多部分写的很是精妙,对于接触前端时间不太久的人来说,就好像是叩开了JavaScript的另一扇 ...
- 网络协议 11 - Socket 编程(下)
之前我们基本了解了网络通信里的大部分协议,一直都是在“听”的过程.很多人都会觉得,好像看懂了,但关了页面回忆起来,好像又什么都没懂.这次咱们就“真枪实弹”的码起来,再用一个“神器”-网络分析系统详细跟 ...
- 【BigData】Java基础_构造方法的使用
需求描述 实现上图需求,根据输入的三个人的信息,分别计算出这个三个客户的平均年龄和最大年龄 涉及知识点: ①构造方法 ②字符串切割 ③对象数组 代码实现 代码结构图: package cn.test. ...
- 几句话总结一个算法之DQN
DQN利用深度学习对Q-learning的一个扩展,回顾上篇文章,Q-learning的核心在于Q(s,a)的建模.如果状态s非常复杂,很难通过一张表来存储所有的状态. 深度学习正好可以自动提取s的特 ...
- 第2课 auto类型推导(1)
第2课 auto类型推导(1) 一.auto类型推导 (一)与模板类型推导映射关系 1.auto类型推导与模板类型推导可以建立一一映射关系,它们之间存在双向的算法变换.auto扮演模板中T的角色,而变 ...
- 技嘉Z390 AORUS MASTER+酷睿I9超频5.0GHz教程
注:调整每项值的时候,需要手动用键盘输入数字,按回车确定.(只按回车并不会出现选择项) Core i9-9900K也出来了一段时间了,这个号称“地表最强游戏U”也成了很多人最新的目标.网上也有大佬表示 ...
- .NET技术webconfig加密操作
webconfig 加密 aspnet_regiis.exe -pef secion physical_directory -prov provider section表示要加密的配置节 phy ...
- Python【每日一问】29
问: [基础题]:给一个不多于 5 位的正整数,要求:一.求它是几位数,二.逆序印出各位数字[提高题]:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加 ...
- putty常用配置修改
1.修改putty默认的颜色方案 初次使用putty时,发现默认的配色的方案看得非常难受,特别是黑色背景,深蓝色的字体,根本看不清楚,下面介绍如何更改默认的配色方案: (1)下载配置文件 首先下载注册 ...