1. 阿里熔断限流Sentinel研究

1.1. 功能特点

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

开源生态

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

1.2. 快速开始

1.2.1. 公网接入

  • 根据该步骤,建立demo

  • 控制台效果图

1.3. 手动接入

  1. 引入pom
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.2</version>
</dependency>
  1. 定义资源:也就是对哪个资源进行流量控制,现在已经提供了注解形式,所以新的接入直接用注解,@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写入

  1. 这个功能是可以有的,只是官方文档我没找到,我直接debug源码查看哪里可以把apollo写入加进去,果然发现它是提供了写入接口的
  2. 写入接口为WritableDataSource,参考上面的完整代码

1.5. 控制台

  1. 下载启动控制台,下载地址
  2. 启动命令java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

登录名密码都是sentinel

1.6. 工作原理

  1. 官方说明

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研究的更多相关文章

  1. 微服务熔断限流Hystrix之流聚合

    简介 上一篇介绍了 Hystrix Dashboard 监控单体应用的例子,在生产环境中,监控的应用往往是一个集群,我们需要将每个实例的监控信息聚合起来分析,这就用到了 Turbine 工具.Turb ...

  2. Envoy熔断限流实践(二)Rainbond基于RLS服务全局限流

    Envoy 可以作为 Sevice Mesh 微服务框架中的代理实现方案,Rainbond 内置的微服务框架同样基于 Envoy 实现.本文所描述的全局限速实践也是基于 Envoy 已有的方案所实现. ...

  3. Envoy熔断限流实践(一)基于Rainbond插件实现熔断

    Envoy 可以作为 Sevice Mesh 微服务框架中的代理实现方案,Rainbond 内置的微服务框架同样基于 Envoy 实现.本文所描述的熔断实践基于 Rainbond 特有的插件机制实现. ...

  4. 微服务熔断限流Hystrix之Dashboard

    简介 Hystrix Dashboard是一款针对Hystrix进行实时监控的工具,通过Hystrix Dashboard可以直观地看到各Hystrix Command的请求响应时间,请求成功率等数据 ...

  5. Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结

    在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...

  6. Spring Cloud alibaba网关 sentinel zuul 四 限流熔断

    spring cloud alibaba 集成了 他内部开源的 Sentinel 熔断限流框架 Sentinel 介绍 官方网址 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentine ...

  7. Dubbo使用Sentinel来对服务进行降级与限流

    一.Sentinel 是什么 Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定 ...

  8. Spring Cloud Alibaba基础教程:使用Sentinel实现接口限流

    最近管点闲事浪费了不少时间,感谢网友libinwalan的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一 ...

  9. Spring Cloud Alibaba | Sentinel: 服务限流高级篇

    目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...

随机推荐

  1. 01-Eigen的安装

    Ubuntu下: 使用的IDE是Kdevelop.(使用别的也可以) 安装Kdevelop的方法见: http://www.cnblogs.com/alexYuin/p/8989228.html 1. ...

  2. 前端之CSS(上)

    CSS CSS 简介 ## CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染 ...

  3. USACO Roadblock

    洛谷 P2176 [USACO14FEB]路障Roadblock 洛谷传送门 JDOJ 2406: USACO 2014 Feb Silver 2.Roadblock JDOJ传送门1 JDOJ 24 ...

  4. 修改MyEclipse/Eclipse左侧文字大小(MacOS/Windows)

    一.Windows 首先找到 Eclipse/MyEclipse 的安装目录,然后找到如下目录: \plugins\org.eclipse.ui.themes_1.1.200.v20160815-05 ...

  5. JavaScript遍历

  6. 如何更新GitHub上的代码?

    更新github上的代码 一.克隆代码 1.先是把自己GitHub上的代码克隆到本地(下载到本地) 步骤1.随便创建一个新文件夹(用来存放下载下来的代码) 步骤2.在文件夹中打开cmd 输入下载指令下 ...

  7. 洛谷 P1816 忠诚 题解

    P1816 忠诚 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨,财 ...

  8. 安装OpenIMSCore的SIP测试客户端 utcimsclient

    环境 Ubuntu16.04,Vmvare12(win10). 下载 & 解压 //utcimsclient 下载地址 : https://liquidtelecom.dl.sourcefor ...

  9. C#内存泄露与资源释放 经验总结

    本文链接:http://blog.csdn.net/yokeqi/article/details/41083939 C#相比其他语言,拥有强大的垃圾回收机制,但并不是这样,你就可以对内存管理放任不管, ...

  10. 【计算机视觉】stitching_detail算法介绍

    已经不负责图像拼接相关工作,有技术问题请自己解决,谢谢. 一.stitching_detail程序运行流程 1.命令行调用程序,输入源图像以及程序的参数 2.特征点检测,判断是使用surf还是orb, ...