前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Springboot使用Sentinel限流,集成zookeeper完成规则的持久化

Springboot使用Sentinel限流,集成zookeeper完成规则的持久化

作者头像
天涯泪小武
发布2019-07-04 10:17:10
2.8K0
发布2019-07-04 10:17:10
举报
文章被收录于专栏:SpringCloud专栏SpringCloud专栏

上一篇简单介绍了sentinel限流的基本配置和使用,这一篇我们来稍微深入一点,看看如何将zookeeper继承进来,用以保存添加的流控规则。

上一篇中我们启动了dashboard.jar,然后在客户端中指定了dashboard的地址。之后启动项目,随便访问个接口,之后就能在dashboard的界面上看到相应的请求了,并且能在控制台上添加一些规则,保存后客户端就能生效了。

基于内存的推送

那么它的内部原理是什么呢?来简单了解一下。

从官方文档可以看到,客户端在引入了Sentinel后,并指定dashboard的地址,启动后,将会在客户端启动一个http服务,默认占用8719端口。由于我们是引入的SpringCloud的模块,就已经包含了下面的引入。

引入这个transport模块的原因就是为了接收dashboard推送过来的配置规则。可以看看官方文档的介绍,默认就是“原始模式”。所谓的原始模式,就是指客户端启动web服务,连上dashboard后,在dashboard配置的规则,由dashboard发起http请求来修改。修改后的规则,直接保存在客户端内存中,并即时生效。

这种方式原理简单,一般用于入门测试使用,生产环境不能用。基于内存存储,在客户端重启后,所有规则都会丢失,需要重新配置。而且不适用于客户端多个实例,因为彼此之间不共享规则,倘若启动多个实例,需要多次重复配置。很明显,这不是我们想要的那种结果。

官方提供了三种模式,上面的“原始模式”、“pull模式”、“push模式”。pull模式就是搞个文件存着,隔一会去请求一下,看看有没有变化,如果变了,就更新到内存,很明显这种模式存在延迟,也不建议上生产。那就来看看“push模式”吧。

基于zookeeper的推送

从上面可以看到,要想能持久化规则的存储,并且在多个实例间共享,就需要一个第三方的存储。让dashboard对规则的修改能及时存储到第三方并及时通知客户端完成修改。官方给了三种示例推荐,Apollo、Nacos、Zookeeper,它们的使用类似,我们以zookeeper为例来看看怎么使用。

客户端pom文件添加zookeeper的依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-zookeeper</artifactId>
        </dependency>

然后客户端修改获取规则的地方为从zookeeper获取规则。

import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @author wuweifeng wrote on 2019/7/1.
 */
@Component
public class ZookeeperSentinelConfig {
    @Value("${spring.application.name}")
    private String appName;


    @PostConstruct
    public void loadRules() {
        final String remoteAddress = "127.0.0.1:2181";
        final String path = "/sentinel_rule_config/" + appName;

        ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ZookeeperDataSource<>(remoteAddress, path,
                source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
                }));
        FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
    }
}

这一步很简单,大家自行去下载个zookeeper的安装文件,启动即可。在方法里指定zookeeper的地址和要监听变化的path,然后注册一下就好了。客户端到这里就完毕了。

重新启动客户端后,就会变成从zookeeper的固定path里获取rule规则。之后对该path做的变化,都会即时更新到客户端,并应用新的规则。

这里我们测试一下:

@RestController
public class TestController {

    @GetMapping(value = "/hello")
    public String hello() {
        return "Hello Sentinel";
    }

    @GetMapping(value = "/test")
    @SentinelResource(value = "TestResource", blockHandler = "handleException")
    public String test() {
        return "Hello TestResource";
    }

    // Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
    public String handleException(BlockException ex) {
        return "handleException";
    }
}

上面是一个简单的Controller,里面定义了一个resource。之后,我们通过对zookeeper的path推送该resource的规则,来测试是否生效。

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

/**
 * @author wuweifeng wrote on 2019/7/1.
 */
public class ZookeeperConfigSender {
    private static final int RETRY_TIMES = 3;
    private static final int SLEEP_TIME = 1000;

    public static void main(String[] args) throws Exception {
        final String remoteAddress = "localhost:2181";
        final String rule = "[\n"
                + "  {\n"
                + "    \"resource\": \"TestResource\",\n"
                + "    \"controlBehavior\": 0,\n"
                + "    \"count\": 1.0,\n"
                + "    \"grade\": 1,\n"
                + "    \"limitApp\": \"default\",\n"
                + "    \"strategy\": 0\n"
                + "  }\n"
                + "]";

        CuratorFramework zkClient = CuratorFrameworkFactory.newClient(remoteAddress, new ExponentialBackoffRetry
                (SLEEP_TIME, RETRY_TIMES));
        zkClient.start();
        String appName = "your-app-name";
        String path = "/sentinel_rule_config/" + appName;
        Stat stat = zkClient.checkExists().forPath(path);
        if (stat == null) {
            zkClient.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path, null);
        }
        zkClient.setData().forPath(path, rule.getBytes());

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        zkClient.close();
    }
}

这就是测试代码,运行后,就会往zookeeper写入一个rule,设置名为TestResource的qps为1,并应用到客户端。无论启动多少个客户端实例,都会生效这个rule。

看到这里,其实已经完成了基于push的动态规则功能了,可以通过zkui这种zookeeper界面工具,或者通过代码来查询、修改zookeeper里的rule配置(json)来完成对客户端规则的控制。

那么可能有人会问了,dashboard呢?用那个界面操作不是更方便吗?

事实上,对客户端的限流,与dashboard没一点关系,只用zookeeper就能完成了。那么这时,你再启动dashboard,当然也是能用的,因为客户端的web服务还是启动着的,也能接收到来自于dashboard的推送。只是来自于dashboard的在客户端重启后会失效,在zookeeper里的会仍然存在。

那么我们应该改造一下dashboard,让在界面上的操作也推送到zookeeper里去,这样就方便多了。

在GitHub上下载Sentinel的源码,里面有dashboard的工程,我们来修改一下它的代码就好了。

先修改一下pom文件,把scope注释掉。

找到rule包,添加个zookeeper文件夹,里面有4个类。

可以直接从工程的test测试代码里,直接把zookeeper包抄过去就行,并把rule下原来的FlowRuleApiProvider和FlowRuleApiPublisher给注释掉。

test源码里已经提供了基于三种中间件的配置代码了,抄过去就行。

抄过去后,修改一下RULE_ROOT_PATH,保持和客户端配置的是一致的。

之后找到Controller包下的v2包,如果你设置的FlowRuleZookeeperProvider和publisher两个bean有名字,可以在autowired时指定为你设置的名字,或者用@Resource。

最后修改一下sidebar.html,将原来的flowV1改为如图。

这样就ok了。

重新启动dashboard项目,重启客户端。这样dashboard就已经和zookeeper关联起来了,dashboard的操作就由原来的操作客户端的api,变成了操作zookeeper。你所有在dashboard界面上做的配置,都会存储到zookeeper中,并实时推送到客户端。客户端重启后,dashboard不受影响。这样就完成了多实例共享流控规则。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年07月02日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于内存的推送
  • 基于zookeeper的推送
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档