sentinel集群限流

1、概述

1.1、背景

第三方接口有限流,需要根据第三方的限流提前控制流量,防止调用第三方接口被限流。

1.2、目的

研究sentinel中间件的限流是否符合我们需要的业务场景。主要从以下几个方面考虑:

1、限流需要支持集群(分布式服务下,需要支持多节点的限流)

2、限流规则的持久化(不同三方接口限流规则不一致,需要限流的方法繁多且规则不一致,规则最好支持数据库的持久化)

3、限流参数的灵活性(限流的方法可以通过参数来自定义,比如大部分三方接口是根据应用id来进行限流,另外关注限流的时间窗口可配置)

4、限流之后的异常处理(异常处理要支持自定义,比如对于三方接口的异常处理,我们需要进行休眠操作,而不是直接失败)

针对以上四点,着重看一下sentinel这这些方面是否有比较友好的支持:

项目地址:https://gitee.com/ershuai8614/sentinel.git

2、嵌入式集群流控

2.1 、通过控制台添加规则

2.1.1、项目配置启动

sentinel本身就是支持集群的,由于官网文档已经对集群流控已经介绍的比较详细(官方文档:https://sentinelguard.io/zh-cn/docs/cluster-flow-control.html),这里不再赘述,下面主要讲解集群限流在项目中的应用。

down下来上面的项目地址,我们需要启动两个项目,一个是sentinel的控制台(控制台中可以手动对限流的规则进行自定义,只不过这些规则只在内存中,不能持久化),另一个是sentinel的嵌入式集群测试demo。

1)找到sentinel-dashboard中的DashboardApplication,启动的jvm参数:-Dserver.port=8088

2)找到sentinel-demo中 sentinel-demo-cluster中 sentinel-demo-cluster-embedded项目中的ClusterDemoApplication

同一个项目分别启动三个项目,jvm启动参数分别如下:

-Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded -Dserver.port=8083 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dcsp.sentinel.api.port=8283

-Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded -Dserver.port=8084 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dcsp.sentinel.api.port=8284

-Dcsp.sentinel.log.use.pid=true -Dproject.name=sentinle.cluster.demo.embedded -Dserver.port=8085 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dcsp.sentinel.api.port=8285

启动参数解释如下:

-Dcsp.sentinel.log.use.pid=true                            --若在本地启动多个 Demo 示例,需要加上此启动参数,否则控制台显示监控会不准确

-Dproject.name                                                     --指定项目名称

-Dserver.port=8083                                               --指定启动项目端口号

-Dcsp.sentinel.dashboard.server=localhost:8088  --指定seneinel控制台的地址和端口(与sentinel控制台启动的端口保持一致)

-Dcsp.sentinel.api.port=8283                                --指定控制台监控客户端API 的端口

两个项目启动之后,我们打开控制台(默认账号密码为sentinel/sentinel),发现此时控制台没有相关的项目配置,我们需要先分别调用一下配置了限流的接口,localhost:8083/hello/world ,localhost:8084/hello/world ,localhost:8085/hello/world  (hello的接口在项目中加了限流的注解)

sentinel的接口限流相关配置实现类是懒加载的,在第一次调用后,限流相关的资源以及配置信息才会在控制台显示。

控制台的机器列表(我们分别启动了三个服务,刚好对应上)

2.1.2、集群配置

因为我们研究的是集群留空,所以在给接口配置流控规则之前,需要先配置集群信息

1、应用内机器指的就是嵌入模式,嵌入模式下(token和client均可以分摊流量,而外部指定机器指的是独立模式,具体看官方集群流控文档:https://sentinelguard.io/zh-cn/docs/cluster-flow-control.html)

2、选择token和client机器组成流控的集群,最大允许qps为1

配置完成之后我们可以点击tokenClient列表查看全部client客户端

这里需要注意的是,我们需要手动编辑一下client客户端的配置,默认客户端和服务端请求超时时间是20ms,这里改成2000ms,不然后面测试流控可能会出问题。

2.1.3、流控规则配置

在配置完集群信息之后我们在簇点链路列表给sayHello资源添加流控的规则(需要给三台服务均添加流控规则)

1、资源名指的就是需要进行流量限制的接口名

2、针对来源是可以对调用该接口的来源进行限流配置,默认default全部

3、阈值类型有 qps和并发线程数,我们这里选qps,集群阈值填1,表示1s只能有一个请求,集群阈值模式可以选单机均摊和总体阈值,单机均摊会根据服务的总连接数计算总的阈值,而总体阈值是针对于整个集群而言,这里我们选总体阈值,失败退化是指token服务不可用之后自动转换成单机限流。

规则添加完成之后,找到com.alibaba.csp.sentinel.demo.cluster.ClusterDemoTest,分别调用者三个接口,返现在1s之内,只有第一个接口可以响应成功,后面两个服务响应会失败。

初步来看,sentinel集群限流是支持的。但是上面我们是通过控制台手动添加规则,在文章的开始我们也说明了,我们的业务场景需要支持规则持久化,最好是能通过db的方式来读取我们的规则。下面我们来看sentinel的规则持久化相关的支持。

2.2、sentinel流控规则持久化

官方文档说明:https://sentinelguard.io/zh-cn/docs/dynamic-rule-configuration.html

从官方文档上可以看出,sentinel对规则的持久化只适配了nacos,我们可以通过nacos来定义需要限流的资源和具体限流的规则。同样是以嵌入集群模式下为例,我们来尝试不再使用sentinel控制台实现相关的规则定义,而是采用读取nacos中的配置来动态加载资源规则。

同样是在sentinel-demo中 sentinel-demo-cluster中 sentinel-demo-cluster-embedded项目中,官方已经为我们适配了nacos的限流规则。采用spi的机制,代码入口在 com.alibaba.csp.sentinel.demo.cluster.init.DemoClusterInitFunc

以上是主要的代码逻辑,每个方法点进去都可以看到,基本就是从nacos中读取相关配置然后注入到扩展的接口点中去。我们着重看一下nacos都有哪些配置属性

我这里建了一个nacos的命名空间sentinle.cluster.demo.embedded ,id为  0fa80e91-7804-446a-99a4-ae5a82f841cb(代码里需要对应)

主要是以上四条配置,Data id 都是项目启动时指定的项目名称 project.name   加上指定的后缀组成,分别是流控规则、集群相关的配置、热点规则以及客户端配置。Group也指定的SENTINEL_GROUP.

下面分别来看一下 这四个配置的内容、

sentinle.cluster.demo.embedded-flow-rules

[

    {

        "resource":"sayHello",             --需要限流的资源名称

        "grade":1,                     --限流阈值类型,QPS 或线程数模式,默认为QPS

        "count":60,                    --限流阈值

        "strategy":0,                   --调用关系限流策略:直接、链路、关联,默认直接

        "controlBehavior":0,             --流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流,默认直接拒绝

        "clusterMode":true,              --标识是否为集群限流配置

        "clusterConfig":{

            "flowId":9959231232121334,     --全局唯一的规则 ID,由集群限流管控端分配

            "thresholdType":1,          --阈值模式,默认(0)为单机均摊,1 为全局阈值

            "fallbackToLocalWhenFail":true, --在 client 连接失败或通信失败时,是否退化到本地的限流模式

            "strategy":0,              --调用关系限流策略:直接、链路、关联,默认直接

            "windowIntervalMs":1000       --滑动窗口时间,默认1s

        }

    }

]

sentinle.cluster.demo.embedded-param-rules

[

    {

        "resource":"sayHello",

        "grade":1,

        "paramIdx":0,                    --参数索引位置

        "count":1,                      --阈值

        "durationInSec":60,                --统计窗口时间长度(单位为秒)

        "controlBehavior":0,

        "clusterMode":true,

        "clusterConfig":{

            "flowId":9959231435454,

            "thresholdType":1,

            "fallbackToLocalWhenFail":true,

            "strategy":0,

            "windowIntervalMs":1000

        }

    }

]

sentinle.cluster.demo.embedded-cluster-map

[

    {

        "machineId":"192.168.244.168@8283",    --token服务器地址@api监控端口

        "ip":"192.168.244.168",           --token服务器ip 

        "port":18730,                   --token服务器暴露给sentinel控制台的端口  

        "clientSet":[

            "192.168.244.168@8284",       --client 端地址、端口

            "192.168.244.168@8285"

        ]

    }

]

sentinle.cluster.demo.embedded-client-config

{

     "requestTimeout":2000    --client请求服务端超时时间,单位ms

}

配置好以上nacos配置后,指定nacos的命名空间和地址即可。项目启动之后,我们发现,在sentinel控制台中已经存在了和我们之前手动添加的规则一样的配置,而这些配置就是我们在nacos中的配置(具体规则的正确性可自行测试)

通过以上分析,我们可以看出sentinel已经适配了nacos的规则持久化, 如果我们需要,完全可以自己通过spi机制实现一个基于db的规则持久化,和nacos不同的仅仅只是规则来源的不同而已。

2.3、热点参数限流

上面我们分析了sentinel对集群、规则持久化的支持,下面来看一下规则定义的灵活性,文章开始已经提到,最好是能能够根据接口参数来限流,这一部分属于sentinel的热点参数限流,官方文档:https://sentinelguard.io/zh-cn/docs/parameter-flow-control.html

对比以上两种设置发现,对于单机的热点规则是可以支持设置统计窗口时长的,但是对于集群模式下的热点规则,则设置不了统计窗口时长的。

我们可以通过上面的测试用来进行验证,之前我们再nacos上配置了流控规则是1s60的qps,热点参数限制的是第一个参数,60s内qps为1。

以下测试用例,在每次请求完成之后,线程休眠1s,发现并没有抛出限流的异常,说明我们设置的60s 的时间统计窗口是无效的,对于集群热点参数流控来说,只能默认统计时间窗口是1s。

3、独立集群模式

3.1、nacos配置

这里就不在演示通过控制台来配置规则,我们直接通过nacos来进行限流规则的配置。

创建一个  sentinle.cluster.demo.alone 的nacos命名空间,我这里创建的id为:f412be2f-04f1-4a50-9bb2-c60bf8593776(后面在代码中用到),分别有以下配置:

1、appA-flow-rules:

[

    {

        "resource":"sayHello",             --需要限流的资源名称

        "grade":1,                     --限流阈值类型,QPS 或线程数模式,默认为QPS

        "count":60,                    --限流阈值

        "strategy":0,                   --调用关系限流策略:直接、链路、关联,默认直接

        "controlBehavior":0,             --流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流,默认直接拒绝

        "clusterMode":true,              --标识是否为集群限流配置

        "clusterConfig":{

            "flowId":9959231232121334,     --全局唯一的规则 ID,由集群限流管控端分配

            "thresholdType":1,          --阈值模式,默认(0)为单机均摊,1 为全局阈值

            "fallbackToLocalWhenFail":true, --在 client 连接失败或通信失败时,是否退化到本地的限流模式

            "strategy":0,              --调用关系限流策略:直接、链路、关联,默认直接

            "windowIntervalMs":1000       --滑动窗口时间,默认1s

        }

    }

]

2、cluster-server-namespace-set:

[

    "appA"

]

3、appA-cluster-map:

[

    {

        "machineId":"192.168.244.168@8788",    --token服务器地址@api监控端口

        "ip":"192.168.244.168",            --token服务器ip 

        "port":11111,                   --token服务器暴露给sentinel控制台的端口  

        "clientSet":[

            "192.168.244.168@8281",       --client 端地址、端口

            "192.168.244.168@8282"

        ]

    }

]

4、cluster-server-transport-config:

{

    "port":11111,

    "idleSeconds":600

}

5、appA-cluster-client-config:

{

    "requestTimeout":2000

}

6、appA-param-rules

[

    {

        "resource":"sayHello",

        "grade":1,

        "paramIdx":0,                    --参数索引位置

        "count":1,                      --阈值

        "durationInSec":60,                --统计窗口时间长度(单位为秒)

        "controlBehavior":0,

        "clusterMode":true,

        "clusterConfig":{

            "flowId":9959231435454,

            "thresholdType":1,

            "fallbackToLocalWhenFail":true,

            "strategy":0,

            "windowIntervalMs":1000

        }

    }

]

3.2、项目启动:

1)token服务端启动

找到 com.alibaba.csp.sentinel.demo.cluster.ClusterServerDemo 启动,注释掉传输配置,因为已经在nacos中配置过。

jvm启动参数如下:-Dserver.port=8720 -Dproject.name=appA -Dcsp.sentinel.dashboard.server=127.0.0.1:8088 -Dcsp.sentinel.api.port=8788 -Dcsp.sentinel.log.use.pid=true

2)客户端启动:(此客户端是本人基本嵌入式模式copy过来的,为了方便测试两种集群模式,sentinel官网项目没有独立模式的客户端)

找到com.alibaba.csp.sentinel.demo.cluster.ClusterClientDemo 同一个项目启动两次,jvm启动参数如下:

-Dserver.port=8721 -Dproject.name=appA -Dcsp.sentinel.dashboard.server=127.0.0.1:8088 -Dcsp.sentinel.api.port=8281 -Dcsp.sentinel.log.use.pid=true

-Dserver.port=8722 -Dproject.name=appA -Dcsp.sentinel.dashboard.server=127.0.0.1:8088 -Dcsp.sentinel.api.port=8282 -Dcsp.sentinel.log.use.pid=true

启动完成之后,先调用接口 http://localhost:8721/hello/world    http://localhost:8721/hello/world

后打开控制台,查看机器列表,分别有三台服务已连接,一个为token服务器,另外两台为客户端。

簇点链路资源如下:

流控规则如下(两个客户端均有此流控规则):

热点规则如下(两个客户端均有此配置):

找到com.alibaba.csp.sentinel.demo.cluster.ClusterDemoTest 测试类,验证以上规则是否生效。

通过独立模式集群限流发现,集群限流生效,但是同样对于热点参数中配置的时间窗口没有作用。

对比sentinel的嵌入式集群和独立模式集群,我们发现。两种集群的区别是:

同样两种集群都有共同的缺陷,就是token server不支持高可用,用于生产环境需要注意此点。

嵌入式集群:作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。

独立集群:token服务器不参与资源请求的限流,它只负责向客户端发放token,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。

4、限流之后的异常处理

sentinel对于限流之后的自异常处理也是支持的,可以直接定义限流异常处理的方法,和异常处理的类

5、总结

通过以上对sentinel的学习,我们发现sentinel对以下4点的支持如下

1、限流需要支持集群(分布式服务下,需要支持多节点的限流)    ---支持

2、限流规则的持久化(不同三方接口限流规则不一致,需要限流的方法繁多且规则不一致,规则最好支持数据库的持久化)  --支持

3、限流参数的灵活性(限流的方法可以通过参数来自定义,比如大部分外三方接口是根据应用id来进行限流,另外关注限流的时间窗口可配置)   --集群限流时时间窗口不可配置

4、限流之后的异常处理(异常处理要支持自定义,比如对于三方接口的异常处理,我们需要进行休眠操作,而不是直接失败) --支持

你可能感兴趣的:(sentinel集群限流)