介绍:
什么是热点?故名思意 热点就是经常访问的数据,对于一个系统而言,常常需要知道哪些数据是冷数据,哪些是热数据,然后进行相对各个热点的优化措施。
举个例子:
某某热点,某某新闻 出来了一个什么大事,震惊!一男子.......,像这种一个热点 访问量和并发量是非常特别特别高的,然后我们就可以使用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 再访问服务方法