使用SpringCloud Alibaba 的 Sentinel 实现限流操作

介绍:

什么是热点?故名思意 热点就是经常访问的数据,对于一个系统而言,常常需要知道哪些数据是冷数据,哪些是热数据,然后进行相对各个热点的优化措施。

举个例子:

        某某热点,某某新闻 出来了一个什么大事,震惊!一男子.......,像这种一个热点 访问量和并发量是非常特别特别高的,然后我们就可以使用sentinel的热点规则对参数下标为0的参数name为  "震惊!一男子......."去配置一个限流的规则。

热点参数限流会统计访问时携带的参数,然后根据定义的规则进行参数级别的限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

如何启动sentinel

sentinel.jar链接:https://pan.baidu.com/s/1f1fEQGVXxleZUsVp_K7vJQ 
提取码:ahua

下载好之后,找到下载好的目录(目录尽量不要有中文哦)

再cmd命令中启动 

先cd到该目录:

cd 目录路径

启动

java -jar sentinel-dashboard-1.7.2.jar

 效果:

再访问:localhost:8080

 账号就是sentinel,密码也是

目标:

对热点参数name为 “震惊!一男子.......” 进行限流操作

实现:

热点参数限流

局部使用

就是我们在规定时间内请求是否有某个参数并发多少次

假设:

如果我的客户端请求带参数name 一秒内不能并发2次

下面是实现:

首先在我们在我们的controller写一段查询新闻的方法

package com.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 查找新闻
     * SentinelResource注解:标识资源名称
     * @param name
     * @param content
     * @return
     */
    @GetMapping("/selectNews")
    @SentinelResource("selectNews")
    public String selectNews(@RequestParam(required = false) String name,@RequestParam(required = false) String content){
        return "新闻:"+name+",内容:"+content;
    }


}

然后去sentinel控制台制定热点限流规则

 上面配置是说:

我下标为0的参数也就是我们的name 一秒钟最多只能并发2

请求:http://localhost:9001/sentinel/selectNews?name=hello

你访问一下没关系

 接下来在一秒内用咱们单身一万年的手速连续范围三次该方法:

 注意:测试一定要带热点参数去测试才会出效果哟~

相信大家都看到了结果,但是人家并发3次咱们不可能报一个错误给人家吧,不友好 所以我们可以让人家去访问一个降级的方法 去解决这一问题:

修改后的代码如下:

package com.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 查找新闻
     * SentinelResource注解:标识资源名称
     * @param name
     * @param content
     * @return
     */
    @GetMapping("/selectNews")
    @SentinelResource(value = "selectNews",blockHandler = "blockHandler")
    public String selectNews(@RequestParam(required = false) String name,@RequestParam(required = false) String content){
        return "新闻:"+name+",内容:"+content;
    }
    
    public String blockHandler(String name, String content, BlockException e){
        e.printStackTrace();
        return "并发量过高 请稍后再试......";
    }

}

注意事项:blockHandler方法参数列表里面的参数必须与绑定的方法保持一致,并且需要带参数BlockException

在以我们单身一万年的手速 并发3次

 看效果:

 这爽多了!

那我们再去限定请求的热点参数

咱们再sentinel客户端删除这个限流规则,重新创建一个

 这样就可以限制我们搜索 “震惊!一男子...”啦!!!

并发三次:http://localhost:9001/sentinel/selectNews?name=震惊!一男子...

效果实现,成功限流!!!

全局使用

这里我们可以优化一下,就是将限流方法抽取到另外一个单独的类中,该类专门用来放降级的方法,controller层然后只需要通过@SentinelResource注解的blockHandlerClass方法就可以实现调用另外一个类的降级方法啦

具体操作来了!!!

我们再写一个类(BlockHandler)专门用于放降级方法

package com.sentinel.controller.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;

/**
 * @author: shenwang
 * Date: 2021/7/19
 */
public class BlockHandler {
    public static String handleBlock(String name,String content,BlockException blockException){
        blockException.printStackTrace();
        return "限流了......(全局使用测试)";
    }
}

再去修改咱们的controller层

在这里我们将该类的降级方法给注释掉,再使用@SentinelResource注解的blockHandlerClass方法指定我们刚刚创建的那个类BlockHandler

package com.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.sentinel.controller.handler.BlockHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 查找新闻
     * SentinelResource注解:标识资源名称
     * @param name
     * @param content
     * @return
     */
    @GetMapping("/selectNews")
    @SentinelResource(value = "selectNews",blockHandlerClass = BlockHandler.class,blockHandler = "handleBlock")
    public String selectNews(@RequestParam(required = false) String name,@RequestParam(required = false) String content){
        return "新闻:"+name+",内容:"+content;
    }

    /*public String blockHandler(String name, String content, BlockException e){
        e.printStackTrace();
        return "并发量过高 请稍后再试......";
    }*/

}

测试一下:

测试成功!

fallback属性 

fallback属性有点类似于异常捕获,当咱们的服务报错 我们是不能使用blockHandler 指定的降级方法的 那我该服务怎么去预防一个报错呢?

fallback属性也可以帮你指定一个降级方法,使用fallback绑定 如果该方法报错,则调用它指定的降级方法

修改controller层代码:

package com.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.sentinel.controller.handler.BlockHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 查找新闻
     * SentinelResource注解:标识资源名称
     * @param name
     * @param content
     * @return
     */
    @GetMapping("/selectNews")
    @SentinelResource(value = "selectNews",
            blockHandlerClass = BlockHandler.class,blockHandler = "handleBlock",
            fallback = "fallbackHandler")
    public String selectNews(@RequestParam(required = false) String name,@RequestParam(required = false) String content){
        //制造异常
        int num=1/0;
        return "新闻:"+name+",内容:"+content;
    }

    /*public String blockHandler(String name, String content, BlockException e){
        e.printStackTrace();
        return "并发量过高 请稍后再试......";
    }*/


    public String fallbackHandler(String name,String content){
        return "该方法出现异常.....";
    }
}

测试一下:

悟了吗 孩子

fallback的全局使用

当然咱们的fallback也是可以去优化的 也可以单独抽取出来放在一个类上,再用@SentinelResource注解的fallbackClass指定你降级方法的类就好啦!

再创建一个类 用于放出现异常的降级方法,代码如下:

package com.sentinel.controller.handler;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
public class ExceptionHandler {
    public static String fallbackHandler(String name,String content){
        return "该方法出现异常(全局使用)";
    }
}

再修改controller层代码:

package com.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.sentinel.controller.handler.BlockHandler;
import com.sentinel.controller.handler.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: shenwang
 * Date: 2021/7/17
 */
@RestController
@RequestMapping("/sentinel")
public class SentinelController {

    /**
     * 查找新闻
     * SentinelResource注解:标识资源名称
     * @param name
     * @param content
     * @return
     */
    @GetMapping("/selectNews")
    @SentinelResource(value = "selectNews",
            blockHandlerClass = BlockHandler.class,blockHandler = "handleBlock",
            fallbackClass = ExceptionHandler.class,fallback = "fallbackHandler")
    public String selectNews(@RequestParam(required = false) String name,@RequestParam(required = false) String content){
        //制造异常
        int num=1/0;
        return "新闻:"+name+",内容:"+content;
    }

    /*public String blockHandler(String name, String content, BlockException e){
        e.printStackTrace();
        return "并发量过高 请稍后再试......";
    }*/


    /*public String fallbackHandler(String name,String content){
        return "该方法出现异常.....";
    }*/
}

废话不多说,直接看结果:

主要事项:

fallback指定的降级方法需要参数对应

blockHandler指定的降级方法 不仅需要参数对应且需要另带参数BlockException

重启服务后,需要访问该服务的某个方法,该服务才能重新在nacos和sentinel上

启动顺序:先开启nacos,然后是sentinel 再访问服务方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值