前言
在 Spring Cloud 体系中, 熔断降级我们会使用 Hystrix 框架, 限流通常会在 Zuul 中进行处理, Zuul 中没有自带限流的功能, 我们可以自己做限流或者集成第三方开源的限流框架. 最新一代的网关 Spring Cloud Gateway 则自带了限流的功能.
有没有那么一个框架能够把熔断跟限流都给做了, 以前没有, 但是现在有了, 我这属于自问自答哈! 这个框架就是阿里最新开源的 Sentinel.
第一眼见到 Sentinel 有一种很熟悉的感觉, 似曾相识啊! Redis 里面集群的那个哨兵模式不就是 Sentinel 嘛. 后来我才发现我错了, 大错特错, 这是一个新的框架, 潜力 + 实力 = 阿里开源.
Sentinel 是什么?
本段介绍来源于 Sentinel GitHub 主页介绍
随着微服务的流行, 服务和服务之间的稳定性变得越来越重要. Sentinel 以流量为切入点, 从流量控制, 熔断降级, 系统负载保护等多个维度保护服务的稳定性.
Sentinel 具有以下特征:
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀 (即突发流量控制在系统容量可以承受的范围), 消息削峰填谷, 集群流量控制, 实时熔断下游不可用应用等.
完备的实时监控: Sentinel 同时提供实时的监控功能. 您可以在控制台中看到接入应用的单台机器秒级数据, 甚至 500 台以下规模的集群的汇总运行情况.
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架 / 库的整合模块, 例如与 Spring Cloud,Dubbo,gRPC 的整合. 您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel.
完善的 SPI 扩展点: Sentinel 提供简单易用, 完善的 SPI 扩展接口. 您可以通过实现扩展接口来快速地定制逻辑. 例如定制规则管理, 适配动态数据源等.
Sentinel 的主要特性:
Sentinel 的开源生态:
初次见面的我们
先来简单的体验下 Sentinel 吧, 在你的 Maven 项目中增加 Sentinel 的依赖:
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-core</artifactId>
- <version>1.4.1</version>
- </dependency>
Sentinel 中需要限流的称之为资源, 对资源进行处理, 下面来看最简单的一段代码:
- public static void main(String[] args) {
- initFlowRules();
- while (true) {
- Entry entry = null;
- try {
- entry = SphU.entry("HelloWorld");
- /* 您的业务逻辑 - 开始 */
- System.out.println("hello world");
- /* 您的业务逻辑 - 结束 */
- } catch (BlockException e1) {
- /* 流控逻辑处理 - 开始 */
- System.out.println("block!");
- /* 流控逻辑处理 - 结束 */
- } finally {
- if (entry != null) {
- entry.exit();
- }
- }
- }
- }
- private static void initFlowRules(){
- List<FlowRule> rules = new ArrayList<>();
- FlowRule rule = new FlowRule();
- rule.setResource("HelloWorld");
- rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
- // Set limit QPS to 20.
- rule.setCount(20);
- rules.add(rule);
- FlowRuleManager.loadRules(rules);
- }
第一行中初始化限流的规则, 创建了一个资源叫 HelloWorld, 设置了这个资源的 QPS 为 20.
在业务开始前使用 SphU.entry(); 方法标识开始, 结束使用 entry.exit();, 如果触发了流控逻辑就会抛出 BlockException 异常让用户自行处理.
代码运行之后, 我们可以在日志 ~/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:
- |--timestamp-|------date time----|-resource-|p |block|s |e|rt
- 1529998904000|2018-06-26 15:41:44|HelloWorld|20|0 |20|0|0
- 1529998905000|2018-06-26 15:41:45|HelloWorld|20|5579 |20|0|728
- 1529998906000|2018-06-26 15:41:46|HelloWorld|20|15698|20|0|0
- 1529998907000|2018-06-26 15:41:47|HelloWorld|20|19262|20|0|0
- 1529998908000|2018-06-26 15:41:48|HelloWorld|20|19502|20|0|0
- 1529998909000|2018-06-26 15:41:49|HelloWorld|20|18386|20|0|0
p: 通过的请求,
block: 被阻止的请求
s: 成功执行完成的请求个数
e: 用户自定义的异常
rt: 平均响应时长.
我是 Mac 系统, 日志是在这个目录下, Windows 我没试过, 应该也在用户的主目录下
上面这个列子是官方的示列, 如果你觉得没有看到你想要的效果, 因为一直在循环, 也不知道有没有限流成功, 我们可以稍微改动一下进行测试就知道了.
将 while 循环改成 for 循环, 次数为 10000 次, 只输出一句话, 不做任何限制, 执行完成的时间大概在 40 毫秒左右.
- long startTime = System.currentTimeMillis();
- for (int i = 0; i < 10000; i++) {
- System.out.println("hello world");
- }
- long endTime = System.currentTimeMillis();
- System.out.println(endTime - startTime);
下面加上限流的逻辑, 执行完成的时间基本上就超过 100 毫秒了, 可见限流起了作用.
- for (int i = 0; i < 10000; i++) {
- Entry entry = null;
- try {
- entry = SphU.entry("HelloWorld");
- // 资源中的逻辑.
- System.out.println("hello world");
- } catch (BlockException e1) {
- System.out.println("blocked!");
- } finally {
- if (entry != null) {
- entry.exit();
- }
- }
- }
- long endTime = System.currentTimeMillis();
- System.out.println(endTime - startTime);
欢迎加入我的知识星球, 一起交流技术, 免费学习猿天地的课程 ( http://cxytiandi.com/course )
PS: 目前星球中正在星主的带领下组队学习 Sentinel, 等你哦!
来源: http://www.bubuko.com/infodetail-2975255.html