Sentinel在消息网关的实践

Sentinel在消息网关的实践

前言

  1. Sentinel 是面向分布式服务架构的轻量级流量控制框架,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保护服务的稳定性。
  2. 想到流量控制我们就知道漏斗,令牌两种限流方式,及google RateLimite的限流组件。
  3. 想到熔断降级,SpringCould Hystrix大家玩微服务都应该知道。实践过没?深入研究过没?学习难度?
  4. 详细对比下Sentinel与Hystrix 特征
对比内容 Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 不支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix
学习难度 中国人开发,中文文档 外国思维
  1. 看完上面的简单介绍,请移步到官方文档 https://github.com/alibaba/Sentinel/wiki/介绍 同浏览一篇,再看下面实践。

场景应用

  1. 对同一个手机号,30秒内发送短信条数不超过10条,采用热点参数限流组件来实现

  2. 热点参数限流 热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

     商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
     用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
    
  3. 代码如下:

        //对第一个参数设置限制
        ParamFlowRule rule = new ParamFlowRule("mobileNo")
                .setParamIdx(0)
                .setCount(5);
// 针对 int 类型的参数 PARAM_B,单独设置限流 QPS 阈值为 10,而不是全局的阈值 5.
//        ParamFlowItem item = new ParamFlowItem().setObject(String.valueOf(PARAM_B))
//                .setClassType(int.class.getName())
//                .setCount(10);
//        rule.setParamFlowItemList(Collections.singletonList(item));

        ParamFlowRuleManager.loadRules(Collections.singletonList(rule));

  1. 设置规则代码,对参数0的每个值的qps不超过5.
 /**
     * Here we prepare different parameters to validate flow control by parameters.
     */
    private static final String[] params = new String[]{
            "13632634458",
            "15982099035",
//            "15982099035",
//            "15982099035",
//            "15140553376",
//            "15982099035",
//            "18292800909",
//            "18608037915",
//            "13547882172",
//            "13547882172",
//            "18581853266",
//            "18581853266",
//            "18581853266",
//            "15982099035",
//            "15982099035",
//            "18628201097",
//            "13826281991",
//            "13659282837",
//            "13680234325",
//            "18628201097",
//            "18628201097",
//            "13826281991",
//            "18581853266",
//            "13659282837",
//            "18581853266",
//            "18628201097",
//            "18581853266",
//            "18581853266",
//            "13680234325",
//            "18581853266",
//            "18581853266",
    };


    @RequestMapping(value = "/getParam")
        @ResponseBody
        //  @SentinelResource(value = "methodA", blockHandler = "exceptionHandler", fallback = "")
        public String getTwoCache(HttpServletRequest request) {
            Entry entry = null;
            try {
                String param = generateParam();
                entry = SphU.entry("mobileNo", EntryType.IN, 1, param);
                // Add pass for parameter.
                log.info("抢购成功:" + param);
            } catch (BlockException e1) {
                log.info("熔断了" + e1.getMessage());
                return "error";
            } catch (Exception e2) {
                // biz exception
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }

            return "ok";
        }


     private String generateParam() {
            int i = ThreadLocalRandom.current().nextInt(0, params.length);
            return params[i];
        }

  1. 通过sentinel-dashboard可以知道,只启用两个手机号,/getParam的qps应该为10 qps。如图:


  1. 通过图片可以看mobileNo的qps为10.
  2. 遗憾的是规则采用是1秒时间窗口内获取的qps,对于10秒内该请求数量,还是不够完美。可以自己设计。

滑动时间窗口

  1. 熔断降级采用的错误数,错误率,响应时间,限流的qps都是基于滑动时间窗口。
  2. 我们在流水式计算也经常遇到时间窗口这个概念,在报警系统我们也许选择一个窗口时间。背后原理是一致的滑动时间窗口
  3. 滑动时间窗口它有两个属性,一个是Window size,一个是Advance interval。Window size指定了窗口的大小,也即每次计算最小数据集的大小。而Advance interval定义输出的时间间隔。一个典型的应用场景是,每隔5秒钟输出一次过去1个小时内网站的PV或者UV


  1. 举例:监控系统定义最小时间WindowSize=30s,意思把单位时间30s数据值进行聚合。Advancenterval:为我们获取3分内的时间窗口数据算qps。滑动时间窗口意思已当时间点向前找Advancenterval时间内有效数据。
  2. 时间窗口在kafkaStream,Flink等广泛应用

自定义分布式滑动时间窗口

  1. 定义最小时间WindowSize=30s,采用redis hash数据结构实现窗口,key为窗口标识id,例如01-01 21:01:00.数据属性放入Hash结构。
  2. 利用redis HINCRBY命令为哈希表 key 中的域 field 的值加上增量 increment,很容为数据聚合。
  3. 我们的间隔时间为Advancenterval 可以考虑为1-5分钟,key采用LRU设置大于Advancenterval的失效时间自动过期。
  4. 一个分布式滑动时间窗口已done。

参考

  1. kafkaStream时间窗口详细介绍 http://www.jasongj.com/kafka/kafka_stream/
  2. 限流降级神器「sentinel」基于滑动时间窗口 https://mp.weixin.qq.com/s/B1_7Kb_CxeKEAv43kdCWOA
  3. Sentinel GitHub

你可能感兴趣的:(软件架构)