Sentinel实战

这篇具有很好参考价值的文章主要介绍了Sentinel实战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、Sentinel简介

Sentinel是阿里开源的面向服务流量治理的框架,官方原文是Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

Sentinel有两个重要的基本概念:

资源

资源就是需要进行流量管理的事物,可以是服务名也可以是接口地址URL等,如果你想根据某个接口进行限流,那资源就是该接口。

规则

规则就是进行流量管理的规则,比如用哪种限流算法,是根据QPS限流还是根据线程数限流等。

更多可以查看官方介绍https://sentinelguard.io/zh-cn/docs/introduction.html。

二、需求背景

微服务网关一般都会有限流的功能,防止后端服务被瞬时超高流量击垮,刚好之前开源的ship-gate网关支持自定义插件,那么就可以通过给ship-gate增加限流功能来学习Sentinel。

完整需求如下:

ship-gate需要支持服务(如订单服务)维度的限流,限流方式包括根据QPS和线程数这两种,本次改造内容全部在ship-server子模块。

三、编码实现

ship-server是基于Spring WebFlux实现的,Sentinel提供的有开源框架的适配sentinel-spring-webflux-adapter模块,但是看了下其实现与现有的设计不兼容,于是决定用原生的核心库sentinel-core。
同时ship-gate也需要Sentinel的控制台功能监控限流情况,所以pom文件需要引入以下依赖:

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.6</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.6</version>
        </dependency>
  1. 配置类增加限流配置
/**
 * Created by 2YSP on 2020/12/27
 */
@ConfigurationProperties(prefix = "ship.gate")
public class ServerConfigProperties {
    /**
     * 负载均衡算法,默认轮询
     */
    private String loadBalance = LoadBalanceConstants.ROUND;
    /**
     * 网关超时时间,默认3s
     */
    private Long timeOutMillis = 3000L;
    /**
     * 缓存刷新间隔,默认10s
     */
    private Long cacheRefreshInterval = 10L;

    /**
     * 限流方式QPS或THREAD,默认QPS
     */
    private String rateLimitType = "QPS";
    /**
     * 限流数量
     */
    private Integer rateLimitCount;
    
    // 省略getter setter方法
}    

ShipPluginEnum增加对应枚举

public enum ShipPluginEnum {
    /**
     * DynamicRoute
     */
    DYNAMIC_ROUTE("DynamicRoute", 2, "动态路由插件"),
    /**
     * Auth
     */
    AUTH("Auth", 1, "鉴权插件"),

    RATE_LIMIT("RateLimit", 0, "限流插件");

    private String name;

    private Integer order;

    private String desc;

    ShipPluginEnum(String name, Integer order, String desc) {
        this.name = name;
        this.order = order;
        this.desc = desc;
    }

    // 省略getter方法
}

注意: order越小越先执行(与Spring规则一致),限流插件最先执行所以定义为0

2.新建RateLimitPlugin类,继承AbstractShipPlugin

/**
 * @Author: Ship
 * @Description:
 * @Date: Created in 2020/12/29
 */
public class RateLimitPlugin extends AbstractShipPlugin {

    private final Logger logger = LoggerFactory.getLogger(RateLimitPlugin.class);

    private static Map<String, Integer> rateLimitTypeMap = new HashMap<>();

    static {
        rateLimitTypeMap.put(ServerConstants.LIMIT_BY_QPS, RuleConstant.FLOW_GRADE_QPS);
        rateLimitTypeMap.put(ServerConstants.LIMIT_BY_THREAD, RuleConstant.FLOW_GRADE_THREAD);
    }

    public RateLimitPlugin(ServerConfigProperties properties) {
        super(properties);
    }

    @Override
    public Integer order() {
        return ShipPluginEnum.RATE_LIMIT.getOrder();
    }

    @Override
    public String name() {
        return ShipPluginEnum.RATE_LIMIT.getName();
    }

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, PluginChain pluginChain) {
        String appName = pluginChain.getAppName();
        initFlowRules(appName);
        if (SphO.entry(appName)) {
            // 务必保证finally会被执行
            try {
                /**
                 * 被保护的业务逻辑
                 */
                return pluginChain.execute(exchange, pluginChain);
            } finally {
                SphO.exit();
            }
        }
        throw new ShipException(ShipExceptionEnum.REQUEST_LIMIT_ERROR);
    }

    private void initFlowRules(String resource) {
        Assert.hasText(properties.getRateLimitType(), "config ship.gate.rateLimitType required!");
        Assert.notNull(properties.getRateLimitCount(), "config ship.gate.rateLimitCount required!");
        List<FlowRule> list = new ArrayList<>();
        FlowRule flowRule = new FlowRule();
        flowRule.setResource(resource);
        flowRule.setGrade(rateLimitTypeMap.get(properties.getRateLimitType()));
        flowRule.setCount(properties.getRateLimitCount().doubleValue());
        list.add(flowRule);
        FlowRuleManager.loadRules(list);
    }
}

因为如果请求被限流了,RateLimitPlugin会抛出异常,为了处理这种异常需要增加全局异常处理配置

类似SpringMVC框架,只需要实现WebExceptionHandler接口,然后在配置类注册对应的bean即可。

ShipExceptionHandler

public class ShipExceptionHandler implements WebExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger(ShipExceptionHandler.class);

    @Override
    public Mono<Void> handle(ServerWebExchange serverWebExchange, Throwable throwable) {
        logger.error("ship server exception msg:{}", throwable.getMessage());
        if (throwable instanceof ShipException) {
            ShipException shipException = (ShipException) throwable;
            return ShipResponseUtil.doResponse(serverWebExchange, new ApiResult(shipException.getCode(), shipException.getErrMsg()));
        }
        String errorMsg = "system error";
        if (throwable instanceof IllegalArgumentException) {
            errorMsg = throwable.getMessage();
        }
        return ShipResponseUtil.doResponse(serverWebExchange, new ApiResult(5000, errorMsg));
    }
}

配置类WebConfig

/**
 * @Author: Ship
 * @Description:
 * @Date: Created in 2020/12/25
 */
@Configuration
@EnableWebFlux
@EnableConfigurationProperties(ServerConfigProperties.class)
public class WebConfig {

    @Bean
    public PluginFilter pluginFilter(@Autowired ServerConfigProperties properties) {
        return new PluginFilter(properties);
    }

    /**
     * set order -2 to before DefaultErrorWebExceptionHandler(-1) ResponseStatusExceptionHandler(0)
     * @return
     */
    @Order(-2)
    @Bean
    public ShipExceptionHandler shipExceptionHandler(){
        return new ShipExceptionHandler();
    }

}

注意: 这里踩了一个小坑,开始发现自己写的WebExceptionHandler不生效,请求错误响应还是原来的格式,后来发现需要添加@order注解指定bean注入的优先级比默认的小

  1. 插件责任链注册插件RateLimitPlugin
/**
 * @Author: Ship
 * @Description:
 * @Date: Created in 2020/12/25
 */
public class PluginFilter implements WebFilter {

    private ServerConfigProperties properties;

    public PluginFilter(ServerConfigProperties properties) {
        this.properties = properties;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String appName = parseAppName(exchange);
        if (CollectionUtils.isEmpty(ServiceCache.getAllInstances(appName))) {
            throw new ShipException(ShipExceptionEnum.SERVICE_NOT_FIND);
        }
        PluginChain pluginChain = new PluginChain(properties, appName);
        pluginChain.addPlugin(new DynamicRoutePlugin(properties));
        pluginChain.addPlugin(new AuthPlugin(properties));
        pluginChain.addPlugin(new RateLimitPlugin(properties));
        return pluginChain.execute(exchange, pluginChain);
    }

    private String parseAppName(ServerWebExchange exchange) {
        RequestPath path = exchange.getRequest().getPath();
        String appName = path.value().split("/")[1];
        return appName;
    }
}

最后,Sentinel控制台支持JVM参数和sentinel.properties文件两种配置方式,方便起见在resource目录增加sentinel.properties配置文件,内容如下:

project.name=ship-server
csp.sentinel.dashboard.server=127.0.0.1:8080

至此,代码已经写完了,下面进入测试环节。

四、测试总结

  1. 启动nacos
  2. 启动ship-admin,ship-gate-example工程
  3. 在t_plugin表插入限流插件
INSERT INTO `ship`.`t_plugin`(`id`, `name`, `code`, `description`, `created_time`) VALUES (3, '限流', 'RateLimit', '限流插件', '2023-04-16 11:06:39');

然后t_app_plugin表增加插件配置(插件管理这块暂时没有后台功能后面考虑增加)

通过nacos控制台查看实例详情,发现服务实例的插件配置已经有了。

Sentinel实战

  1. 在application.yml增加限流配置后就可以启动ship-server工程了
ship:
  gate:
    load-balance: round
    time-out-millis: 3000
    cache-refresh-interval: 10
    rate-limit-type: QPS
    rate-limit-count: 4

这里配置了QPS限制在4以内,相当于每秒最多4个请求通过。

  1. 官网下载sentinel-dashboard.jar(下载地址:https://github.com/alibaba/Sentinel/releases),然后
    打开命令行输入java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar启动。

  2. 游览器访问http://localhost:8080/#/login(默认账号密码都是sentinel),就可以看到后台界面了。
    Sentinel实战
    因为ship-server还没收到请求,所以左侧菜单栏开始不会显示配置的projectName,相当于懒加载的原理。

  3. 使用wrk压测工具对接口进行压测,命令如下:

wrk -c 100 -t 20 -d 60s http://localhost:9000/order/user/test

IDEA控制台日志如下

Sentinel实战

Sentinel实战

第一张图说明触发了限流的保护机制,第二张图说明QPS确实被限制到了4以内,看日志打印的频率猜测用的是固定窗口计数器算法实现的,测试成功。

同时在Sentinel控制台也能看到监控数据

Sentinel实战

总结:

Sentinel还具备其他很强大的功能,需要慢慢摸索,Sentinel控制台有一个把配置推送到注册中心,然后服务监听流量规则配置的方案有时间看下怎么玩,如果觉得这篇文章对您有用希望可以点个赞让更多人看到😉。

参考文档:

https://sentinelguard.io/zh-cn/docs/dashboard.html

https://docs.spring.io/spring-framework/docs/5.1.7.RELEASE/spring-framework-reference/web-reactive.html#webflux-exception-handler文章来源地址https://www.toymoban.com/news/detail-417229.html

到了这里,关于Sentinel实战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud实战 |分布式系统的流量控制、熔断降级组件Sentinel如何使用

    专栏集锦,大佬们可以收藏以备不时之需 Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏:https://blog.csdn.net/superdangbo/category_9271502.html tensorflow专栏:https://blog.csdn.net/superdangbo/category_869

    2024年02月04日
    浏览(75)
  • 深入理解Sentinel系列-1.初识Sentinel

    👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家 📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦 🍂博主正在努力完成2023计划中:源码溯源,一探究竟 📝联

    2024年02月04日
    浏览(40)
  • 初始Sentinel(Sentinel的简单介绍及项目整合)

    前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章将详细介绍Sentinel的概念,优点,与Hystrix的对比以及微服务中整合Sentinel,后续文章将详细介绍Sentinel的细节部分。 如果文章有什么需要改进的地方还请大佬不吝赐教 👏👏。 小威在此先感谢各位大佬

    2024年02月05日
    浏览(41)
  • 【sentinel】漏桶算法在Sentinel中的应用

    漏桶算法,又称leaky bucket。 从图中我们可以看到,整个算法其实十分简单。首先,我们有一个固定容量的桶,有水流进来,也有水流出去。对于流进来的水来说,我们无法预计一共有多少水会流进来,也无法预计水流的速度。但是对于流出去的水来说,这个桶可以固定水流出

    2024年02月07日
    浏览(44)
  • 【Sentinel】Sentinel与gateway的限流算法

    线程隔离有两种方式实现: 线程池隔离(Hystrix默认采用) 信号量隔离(Sentinel默认采用) 服务I需要远程调用服务A、服务B,则创建两个线程池,分别用来处理服务I–服务A,和服务I–服务B的请求。和线程池隔离不同的是,信号量隔离比较轻量级,就维护一个计数器就好,不

    2024年02月09日
    浏览(53)
  • Sentinel dashboard的使用;Nacos保存Sentinel限流规则

    Nacos环境搭建 Nacos注册中心的使用 Nacos配置中心的使用 Sentinel 容灾中心的使用 Sentinel · alibaba/spring-cloud-alibaba Wiki · GitHub github地址:Sentinel/sentinel-dashboard at master · alibaba/Sentinel · GitHub 创建sentinel-dashboard的启动脚本,并添加如下信息: 目录: 注意:sentinel-dashboard默认会在87

    2024年02月15日
    浏览(38)
  • Spring Cloud Gateway集成Sentinel 1.8.6及Sentinel Dashboard

    一、安装sentinel 1.下载地址:sentinel v1.8.6 2.启动sentinel dashboard,执行以下命令: java -Dcsp.sentinel.log.dir=D:xxxsentinellogs -Dserver.port=9217 -Dcsp.sentinel.dashboard.server=localhost:9217 -Dcsp.sentinel.heartbeat.client.ip=localhost -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboar

    2024年02月11日
    浏览(48)
  • SpringCloud Alibaba - Sentinel 高级玩法,修改 Sentinel-dashboard 源码,实现 push 模式

    目录 一、规则持久化 1.1、什么是规则持久化 1.1.1、使用背景 1.1.2、规则管理的三种模式 a)原始模式 b)pull 模式 c)push 模式 1.2、实现 push 模式 1.2.1、修改 order-service 服务,使其监听 Nacos 配置中心 1.2.2、修改 Sentinel-dashboard 源码,配置 nacos 数据源 1.2.3、修改 Sentinel-dashboard

    2024年02月07日
    浏览(43)
  • 如何使用Sentinel做流量控制?此文将附代码详细介绍Sentinel几种限流模式

    前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章将详细介绍Sentinel的两种限流模式,由于篇幅原因,后续文章将详细介绍Sentinel的其他三种。 如果文章有什么需要改进的地方还请大佬不吝赐教 👏👏。 小威在此先感谢各位大佬啦~~🤞🤞 🏠个人主页

    2024年02月05日
    浏览(40)
  • Sentinel降级规则

    官方文档 熔断降级概述 除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个

    2024年02月08日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包