Sentinel不利用控制台基于注解限流,热点参数限流

徐锦洪  金牌会员 | 2024-6-13 16:56:23 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 507|帖子 507|积分 1521

目录
一、maven依赖
二、控制台
三、基于注解限流
四、热点参数限流
五、利用JMeter验证


一、maven依赖

需要注意,利用的版本需要和你的SpringBoot版本匹配!!
Spring-Cloud直接添加如下依赖即可,baba已经帮你指定好版本了。
当然可以点进去spring-cloud-starter-alibaba-sentinel搜索sentinel-core对应的版本
  1. <dependency>
  2.     <groupId>com.alibaba.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>
复制代码
假如是SpringBoot的话,需要手动导入包。
我这里利用的是SpringBoot Version 2.2.5.RELEASE,对应的版本是1.7.1 (你要根据自己SpringBoot版本查询对应版本,假如版本不对应的话根本用不了)
  1. <sentinel.version>1.7.1</sentinel.version>
  2. <!--sentinel核心包-->
  3. <dependency>
  4.     <groupId>com.alibaba.csp</groupId>
  5.     <artifactId>sentinel-core</artifactId>
  6. <version>${sentinel.version}</version>
  7. </dependency>
  8. <!--sentinel注解支持模块-->
  9. <dependency>
  10.     <groupId>com.alibaba.csp</groupId>
  11.     <artifactId>sentinel-annotation-aspectj</artifactId>
  12.     <version>${sentinel.version}</version>
  13. </dependency>
  14. <!--sentinel与控制台交互-->
  15. <dependency>
  16.     <groupId>com.alibaba.csp</groupId>
  17.     <artifactId>sentinel-transport-simple-http</artifactId>
  18. <version>${sentinel.version}</version>
  19. </dependency>
复制代码
二、控制台

这里也介绍下控制台的利用方法,但我的项目是没运维给我安装这个东西,就没法用它。。
下载地址:Release v1.7.1 · alibaba/Sentinel · GitHub
利用命令启动jar包
   java -jar sentinel-dashboard-17.1.jar
  前端访问:localhost:8080, 账号密码 默认都是 sentinel
但是但是!!!!!!!界面是空的!!!!!!!!!

启动命令需要指定你的项目标端口,以及名称才行:
   java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.api.port=8998 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar
  以下是各个命令的介绍:
-Dserver.port=9000  运行端口
-Dcsp.sentinel.dashboard.server=localhost:9000  浏览器访问地址
-Dproject.name=sentinel-dashboard     项目名称
-Dcsp.sentinel.api.port=8092  sentinel客户端端口
-Dsentinel.dashboard.auth.username=username,设置用户名
-Dsentinel.dashboard.auth.password=password,设置访问密码


三、基于注解限流

我的项目没法利用控制台举举措态修改规则,只能在数据库表里面写好规则,系统启动的时候举行读取(当然可以动态修改规则无须重启)
1、maven引入依赖:
  1. <!--sentinel核心包-->
  2. <dependency>
  3.     <groupId>com.alibaba.csp</groupId>
  4.     <artifactId>sentinel-core</artifactId>
  5.     <version>${sentinel.version}</version>
  6. </dependency>
  7. <!--sentinel注解支持模块-->
  8. <dependency>
  9.     <groupId>com.alibaba.csp</groupId>
  10.     <artifactId>sentinel-annotation-aspectj</artifactId>
  11.     <version>${sentinel.version}</version>
  12. </dependency>
复制代码
2、创建SentinelConfig类,启用注解
  1. import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. @Slf4j
  6. @Configuration
  7. public class SentinelConfig {
  8.     @Bean
  9.     public SentinelResourceAspect sentinelResourceAspect() {
  10.         return new SentinelResourceAspect();
  11.     }
  12. }
复制代码
3、创建表 system_sentinel_config 规则设置表
  1. DROP TABLE IF EXISTS `system_sentinel_config`;
  2. CREATE TABLE `system_sentinel_config` (
  3.     `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  4.     `module_name` varchar(100) NOT NULL COMMENT '资源名称',
  5.     `resource` varchar(100) NOT NULL COMMENT '资源名称(唯一), 对应{@link SentinelResName}',
  6.     `desc` varchar(100) NOT NULL COMMENT '资源描述',
  7.     `grade` tinyint(1) NOT NULL DEFAULT 1 COMMENT '阈值类型, 0: 线程数, 1: QPS',
  8.     `count` bigint(20) NOT NULL COMMENT '如果grade为线程数, 表示每秒最高线程数。如果grade为QPS, 表示每秒最高访问量。',
  9.     `strategy` tinyint(1) NOT NULL DEFAULT 0 COMMENT '流控模式。0:直接, 1: 关联, 2:链路',
  10.     `control_behavior` tinyint(1) NOT NULL DEFAULT 0 COMMENT '流控效果。0:默认(直接拒绝), 1: Warm Up(冷启动), 2:匀速排队 3: 冷启动+匀速排队',
  11.     `max_queueing_time_ms` int DEFAULT NULL COMMENT '流控效果为匀速排队时,队列的排队时间(单位:毫秒),需要注意这里类型是int, 并且单位是毫秒',
  12.     `warm_up_period_sec` int DEFAULT NULL COMMENT '冷启动到达最大值的时间(单位:秒)',
  13.     `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '创建时间',
  14.     `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '更新时间',
  15.     `create_user` VARCHAR(50) DEFAULT NULL COMMENT '创建人' ,
  16.     `update_user` VARCHAR(50) DEFAULT NULL COMMENT '更新人' ,
  17.     PRIMARY KEY (`id`),
  18.     UNIQUE KEY resource_key(`resource`)
  19. ) ENGINE=InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='sentinel限流配置表';
  20. -- 标准对接--档案类
  21. INSERT INTO `system_sentinel_config` (`module_name`, `resource`, `desc`, `grade`, `count`, `strategy`, `control_behavior`, `max_queueing_time_ms`, `warm_up_period_sec`) VALUES
  22. ('标准对接--档案类', 'standard:structure:add',     '新增/编辑建筑类节点(片区/楼栋/单元/住家)', 1, 20, 0, 0, null, null),
  23. ('标准对接--档案类', 'standard:structure:delete',  '删除建筑类节点(片区/楼栋/单元/住家)', 1, 20, 0, 0, null, null),
  24. ('标准对接--档案类', 'standard:file:upload',       '上传图片', 1, 20, 0, 0, null, null),
  25. ('标准对接--档案类', 'standard:check:face',        '人脸质量校验', 1, 20, 0, 0, null, null),
  26. ('标准对接--档案类', 'standard:household:add',     '新增/编辑住户(业主,租户)', 1, 20, 0, 0, null, null),
  27. ('标准对接--档案类', 'standard:household:delete',  '删除住户', 1, 20, 0, 0, null, null),
  28. ('标准对接--档案类', 'standard:visitor:add',       '新增/编辑访客', 1, 20, 0, 0, null, null),
  29. ('标准对接--档案类', 'standard:visitor:delete',    '删除访客', 1, 20, 0, 0, null, null);
  30. -- 标准对接--其它
  31. INSERT INTO `system_sentinel_config` (`module_name`, `resource`, `desc`, `grade`, `count`, `strategy`, `control_behavior`, `max_queueing_time_ms`, `warm_up_period_sec`) VALUES
  32. ('标准对接--其它', 'standard:remote:open',         '第三方远程开门', 1, 20, 0, 0, null, null),
  33. ('标准对接--其它', 'standard:smart:lock:control',  '第三方锁门禁权限冻结/解冻', 1, 20, 0, 0, null, null),
  34. ('标准对接--其它', 'standard:smart:lock:set:temporary:pwd',    '第三方锁临时密码下发', 1, 20, 0, 0, null, null);
复制代码
4、对应的SystemSentinelConfigDO对象
  1. import com.alibaba.csp.sentinel.slots.block.RuleConstant;
  2. import com.whysu.scd.base.common.constant.sentinel.SentinelResName;
  3. import lombok.Data;
  4. import lombok.EqualsAndHashCode;
  5. /**
  6. * sentinel限流配置表(SystemSentinelConfig)实体类
  7. */
  8. @Data
  9. public class SystemSentinelConfigDO {
  10.     /**
  11.      * 主键id
  12.      */
  13.     private Long id;
  14.      /**
  15.      * 资源名称
  16.      */
  17.     private String moduleName;
  18.     /**
  19.      * 资源名称(唯一), 对应{@link SentinelResName}
  20.      */
  21.     private String resource;
  22.     /**
  23.      * 资源描述
  24.      */
  25.     private String desc;
  26.     /**
  27.      * 阈值类型
  28.      * 0: 线程数 {@link RuleConstant#FLOW_GRADE_THREAD},
  29.      * 1: QPS {@link RuleConstant#FLOW_GRADE_QPS}
  30.      */
  31.     private Integer grade;
  32.     /**
  33.      * 如果grade为线程数, 表示每秒最高线程数。
  34.      * 如果grade为QPS, 表示每秒最高访问量。
  35.      */
  36.     private Long count;
  37.     /**
  38.      * 流控模式。
  39.      * 0:直接{@link RuleConstant#STRATEGY_DIRECT},
  40.      * 1:关联{@link RuleConstant#STRATEGY_RELATE},
  41.      * 2:链路{@link RuleConstant#STRATEGY_CHAIN},
  42.      */
  43.     private Integer strategy;
  44.     /**
  45.      * 流控效果。
  46.      * 0:默认(直接拒绝){@link RuleConstant#CONTROL_BEHAVIOR_DEFAULT},
  47.      * 1: Warm Up(冷启动){@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP},
  48.      * 2:匀速排队{@link RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER},
  49.      * 3: 冷启动+匀速排队{@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER},
  50.      */
  51.     private Integer controlBehavior;
  52.     /**
  53.      * 流控效果为匀速排队时,队列的排队时间(单位:毫秒), 需要注意这里类型是int, 并且单位是毫秒
  54.      */
  55.     private Integer maxQueueingTimeMs;
  56.     /**
  57.      * 冷启动到达最大值的时间(单位:秒)
  58.      */
  59.     private Integer warmUpPeriodSec;
  60.     /**
  61.      * 创建时间
  62.      */
  63.     private Date createTime;
  64.     /**
  65.      * 更新时间
  66.      */
  67.     private Date updateTime;
  68.     /**
  69.      * 创建人(手机号码)
  70.      */
  71.     private String createUser;
  72.     /**
  73.      * 更新人(手机号码)
  74.      */
  75.     private String updateUser;
  76. }
复制代码
5、系统启动的时候,举行加载。这里的告急方法是。
   FlowRuleManager.loadRules(rules);
  1.    public void initFlowRule() {
  2.         // 查询配置
  3.         List<SystemSentinelConfigDO> list = systemSentinelConfigService.selectList();
  4.         if (CollectionUtils.isEmpty(list)) {
  5.             log.error("sentinel限流配置为空!!!!");
  6.             return;
  7.         }
  8.         List<FlowRule> rules = new ArrayList<>();
  9.         for (SystemSentinelConfigDO configDO : list) {
  10.             rules.add(SentinelUtil.getFlowRule(configDO));
  11.         }
  12.         // 加载
  13.         FlowRuleManager.loadRules(rules);
  14.     }
复制代码
SentinelUtil工具类:
  1. public class SentinelUtil {
  2.     public static void update(List<SystemSentinelConfigDO> list) {
  3.         List<FlowRule> rules = new ArrayList<>();
  4.         for (SystemSentinelConfigDO configDO : list) {
  5.             rules.add(SentinelUtil.getFlowRule(configDO));
  6.         }
  7.         // 加载
  8.         FlowRuleManager.loadRules(rules);
  9.     }
  10.     public static List<FlowRule> getFlowRuleList() {
  11.         return FlowRuleManager.getRules();
  12.     }
  13.     public static FlowRule getFlowRule(SystemSentinelConfigDO configDO) {
  14.         // 限流规则
  15.         FlowRule rateRule = new FlowRule();
  16.         // 设置资源名,即流量控制规则的作用对象
  17.         rateRule.setResource(configDO.getResource());
  18.         // 设置限流阈值
  19.         rateRule.setCount(configDO.getCount());
  20.         // 限流阈值类型
  21.         rateRule.setGrade(configDO.getGrade());
  22.         // 流控模式
  23.         rateRule.setStrategy(configDO.getStrategy());
  24.         // 流控效果
  25.         rateRule.setControlBehavior(configDO.getControlBehavior());
  26.         // 流控效果为匀速排队时,队列的排队时间(单位:毫秒), 需要注意这里类型是int, 并且单位是毫秒
  27.         if (configDO.getMaxQueueingTimeMs() != null && configDO.getMaxQueueingTimeMs() != 0) {
  28.             rateRule.setMaxQueueingTimeMs(configDO.getMaxQueueingTimeMs());
  29.         }
  30.         // 冷启动到达最大值的时间(单位:秒)
  31.         if (configDO.getWarmUpPeriodSec() != null && configDO.getWarmUpPeriodSec() != 0) {
  32.             rateRule.setWarmUpPeriodSec(configDO.getWarmUpPeriodSec());
  33.         }
  34.         return rateRule;
  35.     }
  36. }
复制代码
6、通过update方法动态更新:
  1.     @Transactional
  2.     @Override
  3.     public void update(SystemSentinelConfigDO configDO) {
  4.         ValidateUtils.checkBlank(configDO.getResource());
  5.         SystemSentinelConfigDO dbDO = systemSentinelConfigDao.selectByResource(configDO.getResource());
  6.         if (dbDO != null) {
  7.             configDO.setId(dbDO.getId());
  8.             systemSentinelConfigDao.update(configDO);
  9.         }
  10.         // 全部更新
  11.         SentinelUtil.update(systemSentinelConfigDao.selectList(null));
  12.     }
复制代码
7、定义限流畅用返回, 这里的名称是standardLimit
  1. @Slf4j
  2. public class StandardBlockHandler {
  3.     /**
  4.      * 标准对接, 触发限流时返回
  5.      */
  6.     public static ThirdResponseDTO<Object> standardLimit(BlockException ex) {
  7.         return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
  8.     }
  9. }
复制代码
8、Controller接口通过@SentinelResource指定资源名称,以及触发限流时的返回消息
  1. @RestController
  2. @RequestMapping("/third/archives")
  3. @Slf4j
  4. @RequiredArgsConstructor
  5. public class StandardThirdArchivesController {
  6.     private final StandardArchivesService standardArchivesService;
  7.     /**
  8.      * 新增/编辑建筑类节点(片区/楼栋/单元/住家)
  9.      */
  10.     @PostMapping("/structure/addEdit")
  11.     @SentinelResource(value = "standard:structure:add", blockHandler = "standardLimit", blockHandlerClass = {StandardBlockHandler.class})
  12.     public ThirdResponseDTO<StandardStructureAddRes> addEditStructure(@RequestBody @Validated ThirdRequestDTO<StandardStructureAddReq> req) {
  13.         return ResponseThirdHelper.successResponse(standardArchivesService.addEditStructure(req.getData(), req.getNeighNo()));
  14.     }
  15. }
复制代码

四、热点参数限流

很遗憾,前面说的第三点【基于注解限流】的方式,没法具体到热点参数,因为我的项目标“入参”是有些复杂的对象,但热点参数只支持【基本类型】的入参。。。
1、第三点说的【基于注解限流】直接取消,重新来过
2、maven引入依赖
  1. <!--sentinel核心包-->
  2. <dependency>
  3.     <groupId>com.alibaba.csp</groupId>
  4.     <artifactId>sentinel-core</artifactId>
  5.     <version>${sentinel.version}</version>
  6. </dependency>
  7. <!--sentinel热点参数限流-->
  8. <dependency>
  9.     <groupId>com.alibaba.csp</groupId>
  10.     <artifactId>sentinel-parameter-flow-control</artifactId>
  11.     <version>${sentinel.version}</version>
  12. </dependency>
复制代码
 3、我这里的入参 ThirdRequestDTO 里面有个字段 clientId,是我需要限流的热点参数:
  1. @Data
  2. public class ThirdRequestDTO<T> {
  3.     /**
  4.      * 授权分配的clientId
  5.      */
  6.     private String clientId;
  7. }
复制代码
4、因为热点参数只支持QPS,于是可以设置的选项就很少了:
以下是设置表:standard_sentinel_config (需要注意sql查询的时候,desc, count要加单引号。你也可以给这2个参数重定名)
这里表示在duration_in_sec(秒)内,访问resource(资源)超过count (次数) 就举行限流,
假如是热点参数的话,则表示:
在duration_in_sec(秒)内,访问resource(资源)超过client_id_count(次数) 就举行限流,
  1. DROP TABLE IF EXISTS `standard_sentinel_config`;
  2. CREATE TABLE `standard_sentinel_config` (
  3.     `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  4.     `resource` varchar(100) NOT NULL COMMENT '资源名称{@link SentinelResName}',
  5.     `desc` varchar(100) NOT NULL COMMENT '资源描述',
  6.     `duration_in_sec` int NOT NULL COMMENT '限流的单位时间(秒)',
  7.     `count` int NOT NULL COMMENT '限流参数',
  8.     `client_id_count` int NOT NULL COMMENT '针对clientId限流参数',
  9.     `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '创建时间',
  10.     `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '更新时间',
  11.     create_user VARCHAR(50) DEFAULT NULL COMMENT '创建人' ,
  12.     update_user VARCHAR(50) DEFAULT NULL COMMENT '更新人' ,
  13.     PRIMARY KEY (`id`),
  14.     UNIQUE KEY `resource_key`(`resource`)
  15. ) ENGINE=InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='标准对接限流';
  16. -- 公共字典
  17. INSERT INTO `standard_sentinel_config` (`resource`, `desc`, `duration_in_sec`, `count`, `client_id_count`) VALUES
  18. ('standard:archives',        '标准对接--档案类', 1, 60, 10),
  19. ('standard:query:archives',  '标准对接--查询档案类', 1, 60, 10),
  20. ('standard:other',           '标准对接--其它', 1, 60, 10);
复制代码
5、StandardSentinelConfigDO对象
  1. @Data
  2. public class StandardSentinelConfigDO {
  3.     /**
  4.      * 主键id
  5.      */
  6.     private Long id;
  7.     /**
  8.      * 资源名称{@link SentinelResName}
  9.      */
  10.     private String resource;
  11.     /**
  12.      * 资源描述
  13.      */
  14.     private String desc;
  15.     /**
  16.      * 限流的单位时间(秒)
  17.      */
  18.     private Integer durationInSec;
  19.     /**
  20.      * 限流参数
  21.      */
  22.     private Integer count;
  23.     /**
  24.      * 针对clientId限流参数
  25.      */
  26.     private Integer clientIdCount;
  27.     /**
  28.      * 创建时间
  29.      */
  30.     private Date createTime;
  31.     /**
  32.      * 更新时间
  33.      */
  34.     private Date updateTime;
  35.     /**
  36.      * 创建人(手机号码)
  37.      */
  38.     private String createUser;
  39.     /**
  40.      * 更新人(手机号码)
  41.      */
  42.     private String updateUser;
  43. }
复制代码
6、系统启动的时候,加载规则:(告急是通过ParamFlowRuleManager.loadRules)
  1. import com.alibaba.csp.sentinel.slots.block.RuleConstant;
  2. import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
  3. import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
  4. import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
  5. import com.whysu.scd.base.common.enums.ResultCodeEnum;
  6. import com.whysu.scd.base.common.exception.BusinessException;
  7. import com.whysu.scd.base.common.util.ValidateUtils;
  8. import com.whysu.scd.module.standard.dao.StandardPlatformInfoDao;
  9. import com.whysu.scd.module.standard.dao.StandardSentinelConfigDao;
  10. import com.whysu.scd.module.standard.entity.StandardSentinelConfigDO;
  11. import com.whysu.scd.module.standard.service.StandardSentinelService;
  12. import lombok.RequiredArgsConstructor;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.apache.commons.collections4.CollectionUtils;
  15. import org.springframework.stereotype.Service;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. /**
  19. * 标准对接--限流
  20. */
  21. @Slf4j
  22. @Service
  23. @RequiredArgsConstructor
  24. public class StandardSentinelServiceImpl implements StandardSentinelService {
  25.     private final StandardPlatformInfoDao standardPlatformInfoDao;
  26.     private final StandardSentinelConfigDao standardSentinelConfigDao;
  27.     @Override
  28.     public void init() {
  29.         // 查询sentinel配置
  30.         List<StandardSentinelConfigDO> configList = standardSentinelConfigDao.selectList(null);
  31.         if (CollectionUtils.isEmpty(configList)) {
  32.             log.error("标准对接sentinel配置为空!");
  33.             return;
  34.         }
  35.         // 查询所有的clientId
  36.         List<String> clientIdList = standardPlatformInfoDao.selectClientIdList2();
  37.         List<ParamFlowRule> ruleList = new ArrayList<>();
  38.         for (StandardSentinelConfigDO configDO : configList) {
  39.             // 资源名
  40.             ParamFlowRule rule = new ParamFlowRule(configDO.getResource());
  41.             // 指定当前 rule 对应的热点参数索引
  42.             rule.setParamIdx(0);
  43.             // 限流的维度,该策略针对 QPS 限流
  44.             rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
  45.             // 限流的单位时间(秒)
  46.             rule.setDurationInSec(configDO.getDurationInSec());
  47.             // 未使用指定热点参数时,该资源限流大小为50
  48.             rule.setCount(configDO.getCount());
  49.             // 热点参数限流
  50.             if (CollectionUtils.isNotEmpty(clientIdList)) {
  51.                 List<ParamFlowItem> itemList = new ArrayList<>();
  52.                 for (String clientId : clientIdList) {
  53.                     // item1 设置了clientId的限流,单位时间(DurationInSec)内只能访问10次
  54.                     ParamFlowItem item1 = new ParamFlowItem().setObject(clientId) // 热点参数 value
  55.                             .setClassType(String.class.getName()) // 热点参数数据类型
  56.                             .setCount(configDO.getClientIdCount()); // 针对该value的限流值
  57.                     itemList.add(item1);
  58.                 }
  59.                 rule.setParamFlowItemList(itemList);
  60.             }
  61.             ruleList.add(rule);
  62.         }
  63.         // 加载
  64.         ParamFlowRuleManager.loadRules(ruleList);
  65.     }
  66.     @Override
  67.     public void update(StandardSentinelConfigDO configDO) {
  68.         ValidateUtils.checkBlank(configDO.getResource());
  69.         // 查询
  70.         StandardSentinelConfigDO dbDO = standardSentinelConfigDao.selectByResource(configDO.getResource());
  71.         if (dbDO == null) {
  72.             throw new BusinessException(ResultCodeEnum.PUTIAN_PARAM_ERROR);
  73.         }
  74.         // 更新
  75.         configDO.setId(dbDO.getId());
  76.         standardSentinelConfigDao.update(configDO);
  77.         // 重新初始化
  78.         init();
  79.     }
  80.     @Override
  81.     public List<ParamFlowRule> getRuleList() {
  82.         return ParamFlowRuleManager.getRules();
  83.     }
  84.     @Override
  85.     public List<ParamFlowRule> getRuleOfResource(String resource) {
  86.         return ParamFlowRuleManager.getRulesOfResource(resource);
  87.     }
  88. }
复制代码
7、定义了一个注解:StandardSignature 
  1. @Documented
  2. @Target({ElementType.TYPE, ElementType.METHOD})
  3. @Retention(RetentionPolicy.RUNTIME)
  4. public @interface StandardSignature {
  5.     /**
  6.      * 签名算法版本 2.0
  7.      */
  8.     String version() default ThirdConstant.SignatureVersion.TWO;
  9.     /**
  10.      * 接口权限
  11.      */
  12.     StandardOpenTypeEnum[] openType();
  13.     /**
  14.      * data参数是否不能为空(默认为true表示不能为空)
  15.      */
  16.     boolean dataNotNull() default true;
  17. }
复制代码
8、针对该注解切面:
这里的核心代码是:
  1. Entry entry = null;
  2. try {
  3.     // 调用限流
  4.     entry = SphU.entry(resourceName, EntryType.IN, 1, clientId);
  5.     // 业务代码...
  6.     return proceedingJoinPoint.proceed();
  7. } catch (BlockException e) {
  8.     // 接口限流
  9.     return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
  10. } finally {
  11.     if (entry != null) {
  12.         entry.exit(1, clientId);
  13.     }
  14. }
复制代码
有2个入参:resourceName和clientId
其中clientId是入参ThirdRequestDTO里面的。
resourceName是通过注解指定的StandardSignature里的opernType参数,查询出来的:
  1. /**
  2.      * key: 标准对接接口,value: sentinel限流资源名称{@link SentinelResName}
  3.      */
  4.     public static final HashMap<StandardOpenTypeEnum, String> SENTINEL_RESOURCE = new HashMap<StandardOpenTypeEnum, String>() {
  5.         {
  6.             // 标准对接-档案类
  7.             put(StandardOpenTypeEnum.ARCHIVES, SentinelResName.STANDARD_ARCHIVES);
  8.             put(StandardOpenTypeEnum.ARCHIVES_GET_CALL_NO_FIRST4, SentinelResName.STANDARD_ARCHIVES);
  9.             put(StandardOpenTypeEnum.ARCHIVES_STRUCT_ADD, SentinelResName.STANDARD_ARCHIVES);
  10.             put(StandardOpenTypeEnum.ARCHIVES_STRUCT_DELETE, SentinelResName.STANDARD_ARCHIVES);
  11.             put(StandardOpenTypeEnum.ARCHIVES_UPLOAD_FACE_FILE, SentinelResName.STANDARD_ARCHIVES);
  12.             put(StandardOpenTypeEnum.ARCHIVES_CHECK_FACE, SentinelResName.STANDARD_ARCHIVES);
  13.             put(StandardOpenTypeEnum.ARCHIVES_HOUSEHOLD_ADD, SentinelResName.STANDARD_ARCHIVES);
  14.             put(StandardOpenTypeEnum.ARCHIVES_HOUSEHOLD_DELETE, SentinelResName.STANDARD_ARCHIVES);
  15.             put(StandardOpenTypeEnum.ARCHIVES_VISITOR_ADD, SentinelResName.STANDARD_ARCHIVES);
  16.             put(StandardOpenTypeEnum.ARCHIVES_VISITOR_DELETE, SentinelResName.STANDARD_ARCHIVES);
  17.             // 标准对接-查询档案类
  18.             put(StandardOpenTypeEnum.QUERY_ARCHIVES, SentinelResName.STANDARD_QUERY_ARCHIVES);
  19.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_NEIGH, SentinelResName.STANDARD_QUERY_ARCHIVES);
  20.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_TREE_WHOLE, SentinelResName.STANDARD_QUERY_ARCHIVES);
  21.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_TREE_PAGE, SentinelResName.STANDARD_QUERY_ARCHIVES);
  22.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_AREA, SentinelResName.STANDARD_QUERY_ARCHIVES);
  23.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_BUILDING, SentinelResName.STANDARD_QUERY_ARCHIVES);
  24.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_UNIT, SentinelResName.STANDARD_QUERY_ARCHIVES);
  25.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_HOUSE, SentinelResName.STANDARD_QUERY_ARCHIVES);
  26.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE, SentinelResName.STANDARD_QUERY_ARCHIVES);
  27.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE_STATUS, SentinelResName.STANDARD_QUERY_ARCHIVES);
  28.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
  29.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_ROAD_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
  30.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_CAR_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
  31.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_PERSON_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
  32.             put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
  33.             // 标准对接-其它
  34.             put(StandardOpenTypeEnum.OTHER, SentinelResName.STANDARD_OTHER);
  35.             put(StandardOpenTypeEnum.OTHER_REMOTE_OPEN, SentinelResName.STANDARD_OTHER);
  36.             put(StandardOpenTypeEnum.OTHER_BLOCK_CONTROL, SentinelResName.STANDARD_OTHER);
  37.             put(StandardOpenTypeEnum.OTHER_SEND_TEMPORARY_PWD, SentinelResName.STANDARD_OTHER);
  38.         }
  39.     };
复制代码
其中SentinelResName (对应standard_sentinel_config表的resources字段)
  1. public class SentinelResName {
  2.     /**
  3.      * 标准对接--档案类
  4.      */
  5.     public static final String STANDARD_ARCHIVES = "standard:archives";
  6.     /**
  7.      * 标准对接--查询档案类
  8.      */
  9.     public static final String STANDARD_QUERY_ARCHIVES = "standard:query:archives";
  10.     /**
  11.      * 标准对接--其它
  12.      */
  13.     public static final String STANDARD_OTHER = "standard:other";
  14. }
复制代码
OpenType是用的枚举:
  1. import com.whysu.scd.module.standard.dto.StandardTreeNode;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. import lombok.experimental.Accessors;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. /**
  8. * 允许第三方调用的接口类型集合
  9. */
  10. @Getter
  11. @Accessors(fluent = true)
  12. @AllArgsConstructor
  13. public enum StandardOpenTypeEnum {
  14.     // 全部接口
  15.     ALL(1, 0, "全部接口"),
  16.     // 二级
  17.     ARCHIVES(2, ALL.type, "档案类"),
  18.     QUERY_ARCHIVES(3, ALL.type, "查询档案类"),
  19.     QUERY_RECORD(4, ALL.type, "查询记录"),
  20.     OTHER(5, ALL.type, "其它接口"),
  21.     // 档案类,取值范围:100到199
  22.     ARCHIVES_GET_CALL_NO_FIRST4(100, ARCHIVES.type, "获取呼叫号码前四位"),
  23.     ARCHIVES_STRUCT_ADD(101, ARCHIVES.type, "新增/编辑片区/楼栋/单元/住家"),
  24.     ARCHIVES_STRUCT_DELETE(102, ARCHIVES.type, "删除片区/楼栋/单元/住家"),
  25.     ARCHIVES_UPLOAD_FACE_FILE(103, ARCHIVES.type, "上传人脸"),
  26.     ARCHIVES_CHECK_FACE(104, ARCHIVES.type, "人脸质量校验"),
  27.     ARCHIVES_HOUSEHOLD_ADD(105, ARCHIVES.type, "新增/编辑住户(会进行人脸质量校验)"),
  28.     ARCHIVES_HOUSEHOLD_DELETE(106, ARCHIVES.type, "删除住户"),
  29.     ARCHIVES_VISITOR_ADD(107, ARCHIVES.type, "新增/编辑访客(会进行人脸质量校验)"),
  30.     ARCHIVES_VISITOR_DELETE(108, ARCHIVES.type, "删除访客"),
  31.     // 查询档案类,取值范围:200到299
  32.     QUERY_ARCHIVES_NEIGH(200, QUERY_ARCHIVES.type, "查询小区档案"),
  33.     QUERY_ARCHIVES_TREE_WHOLE(201, QUERY_ARCHIVES.type, "查询树结构(全部)"),
  34.     QUERY_ARCHIVES_TREE_PAGE(202, QUERY_ARCHIVES.type, "查询树结构(分页)(小区片区楼栋单元住家地点)"),
  35.     QUERY_ARCHIVES_AREA(203, QUERY_ARCHIVES.type, "查询片区档案(分页)"),
  36.     QUERY_ARCHIVES_BUILDING(204, QUERY_ARCHIVES.type, "查询楼栋档案(分页)"),
  37.     QUERY_ARCHIVES_UNIT(205, QUERY_ARCHIVES.type, "查询单元档案(分页)"),
  38.     QUERY_ARCHIVES_HOUSE(206, QUERY_ARCHIVES.type, "查询房屋档案(分页)"),
  39.     QUERY_ARCHIVES_DEVICE(207, QUERY_ARCHIVES.type, "查询设备档案(分页)"),
  40.     QUERY_ARCHIVES_DEVICE_STATUS(208, QUERY_ARCHIVES.type, "查询设备在离线状态(分页)"),
  41.     QUERY_ARCHIVES_PARKING_INFO(209, QUERY_ARCHIVES.type, "查询车场档案"),
  42.     QUERY_ARCHIVES_PARKING_ROAD_INFO(210, QUERY_ARCHIVES.type, "查询车道档案(分页)"),
  43.     QUERY_ARCHIVES_PARKING_CAR_INFO(211, QUERY_ARCHIVES.type, "查询车辆档案(分页)"),
  44.     QUERY_ARCHIVES_PERSON_INFO(212, QUERY_ARCHIVES.type, "查询人员档案(住户/访客/工作人员)(分页)"),
  45.     QUERY_ARCHIVES_DEVICE_INFO(213, QUERY_ARCHIVES.type, "查询设备详情"),
  46.     // 查询记录类,取值范围:300到399
  47.     QUERY_RECORD_ACCESS_PAGE(300, QUERY_RECORD.type, "查询门禁记录(分页,不能跨月查询)"),
  48.     QUERY_RECORD_TALK_PAGE(301, QUERY_RECORD.type, "查询对讲记录(分页,不能跨月查询)"),
  49.     QUERY_RECORD_CAR_PAGE(302, QUERY_RECORD.type, "查询车辆出入记录(分页,不能跨月查询)"),
  50.     // 其它接口,取值范围:400到499
  51.     OTHER_REMOTE_OPEN(400, OTHER.type, "第三方远程开门"),
  52.     OTHER_BLOCK_CONTROL(401, OTHER.type, "锁门禁权限冻结/解冻"),
  53.     OTHER_SEND_TEMPORARY_PWD(402, OTHER.type, "锁临时密码下发"),
  54.     ;
  55.     /**
  56.      * 允许第三方调用的接口类型
  57.      */
  58.     private final int type;
  59.     /**
  60.      * 父节点接口类型
  61.      */
  62.     private final int parentType;
  63.     /**
  64.      * 描述
  65.      */
  66.     private final String desc;
  67. }
复制代码
完整的切面代码如下:
  1. import com.alibaba.csp.sentinel.Entry;
  2. import com.alibaba.csp.sentinel.EntryType;
  3. import com.alibaba.csp.sentinel.SphU;
  4. import com.alibaba.csp.sentinel.slots.block.BlockException;
  5. import com.fasterxml.jackson.databind.JsonNode;
  6. import com.fasterxml.jackson.databind.ObjectMapper;
  7. import com.fasterxml.jackson.databind.node.ObjectNode;
  8. import com.whysu.scd.base.common.constant.i18n.third.standard.MessageThirdStandard;
  9. import lombok.extern.slf4j.Slf4j;
  10. import org.apache.commons.collections4.CollectionUtils;
  11. import org.apache.commons.lang3.StringUtils;
  12. import org.aspectj.lang.JoinPoint;
  13. import org.aspectj.lang.ProceedingJoinPoint;
  14. import org.aspectj.lang.annotation.*;
  15. import org.aspectj.lang.reflect.MethodSignature;
  16. import org.springframework.context.annotation.Configuration;
  17. import org.springframework.stereotype.Component;
  18. import org.springframework.web.context.request.RequestAttributes;
  19. import org.springframework.web.context.request.RequestContextHolder;
  20. import org.springframework.web.context.request.ServletRequestAttributes;
  21. import javax.annotation.Resource;
  22. import javax.servlet.http.HttpServletRequest;
  23. import java.lang.reflect.Method;
  24. import java.util.HashSet;
  25. import java.util.List;
  26. import java.util.Set;
  27. /**
  28. * 标准对接-数字签名校验切面
  29. */
  30. @Aspect
  31. @Component
  32. @Slf4j
  33. @Configuration
  34. public class StandardSignatureValidateAspect {
  35.     @Pointcut(value = "@annotation(com.whysu.scd.module.standard.annotation.StandardSignature)")
  36.     public void signaturePointcut() {
  37.     }
  38.     @Around("signaturePointcut()")
  39.     public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  40.         MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
  41.         StandardSignature annotation = signature.getMethod().getAnnotation(StandardSignature.class);
  42.         Object[] args = proceedingJoinPoint.getArgs();
  43.         for (Object arg : args) {
  44.             if (arg instanceof ThirdRequestDTO) {
  45.                 ThirdRequestDTO requestDTO = (ThirdRequestDTO) arg;
  46.                 String clientId = requestDTO.getClientId();
  47.                 // 根据openType获取资源名称
  48.                 Set<String> resourceSet = new HashSet<>();
  49.                 for (StandardOpenTypeEnum openTypeEnum : annotation.openType()) {
  50.                     String resourceName = StandardMap.SENTINEL_RESOURCE.get(openTypeEnum);
  51.                     if (StringUtils.isNotBlank(resourceName)) {
  52.                         resourceSet.add(resourceName);
  53.                     }
  54.                 }
  55.                 // 限流判断
  56.                 for (String resourceName : resourceSet) {
  57.                     Entry entry = null;
  58.                     try {
  59.                         // 调用限流
  60.                         entry = SphU.entry(resourceName, EntryType.IN, 1, clientId);
  61.                         // 业务代码...
  62.                         return proceedingJoinPoint.proceed();
  63.                     } catch (BlockException e) {
  64.                         // 接口限流
  65.                         return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
  66.                     } finally {
  67.                         if (entry != null) {
  68.                             entry.exit(1, clientId);
  69.                         }
  70.                     }
  71.                 }
  72.             }
  73.         }
  74.         return null;
  75.     }
  76.     @AfterReturning(returning = "ret", pointcut = "signaturePointcut()")
  77.     public void doAfterReturning(Object ret) {
  78.         // 处理完请求,返回内容
  79.         log.info("标准对接请求scd, 响应参数为:{}", JacksonUtils.toJson(ret));
  80.     }
  81. }
复制代码
9、在Controller接口指定注解:
  1.     /**
  2.      * 新增/编辑建筑类节点(片区/楼栋/单元/住家)
  3.      */
  4.     @StandardSignature(openType = StandardOpenTypeEnum.ARCHIVES_STRUCT_ADD)
  5.     @PostMapping("/structure/addEdit")
  6.     public ThirdResponseDTO<StandardStructureAddRes> addEditStructure(@RequestBody @Validated ThirdRequestDTO<StandardStructureAddReq> req) {
  7.         return ResponseThirdHelper.successResponse(standardArchivesService.addEditStructure(req.getData(), req.getNeighNo()));
  8.     }
复制代码

五、利用JMeter验证

起首声明这个工具我不大会用哈哈哈
1、先下载http://jmeter.apache.org/download_jmeter.cgi
2、解压,进入bin目录下执行jmeter.bat即可启动成功。
3、默认语言是英文,进入bin目录修改 jmeter.properties,添加如下设置即可改成中文
   language=zh_CN
  4、右键添加--线程(用户)-线程组

设置1秒并发100次

5、线程组右键:添加--取样器--HTTP请求

指定请求协议,地址,端口,方式,路径。可以直接在【消息体数据】里面复制json对象。

6、HTTP请求右键:添加--设置元件--HTTP信息头管理器

添加请求头:Content-Type   application/json;charset=utf-8

7、HTTP请求右键:添加--断言--相应断言

我这里也不知道咋写,但是我知道我项目标相应码3011是对应限流。
我这里就设置成,相应文本,包含3011,就表示成功

8、线程组右键:添加--监听器--察看结果树

9、线程组右键:启动

查看结果树,被限流了哈哈哈哈^_^、、、。。。





免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

徐锦洪

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表