当前位置:   article > 正文

Sentinel 的QPS限流和Redis流量风控

Sentinel 的QPS限流和Redis流量风控

目录

Sentinel 的QPS限流

导入依赖:

这个限制的时每秒的QPS为1:

如果触发风控,设置降级策略。

在代码中引入 Sentinel 注解控制流控规则。

用Redis实现流量风控:

lua脚本如下:

配置过滤器器执行lua脚本,判断访问次数是否超过:我们可以通过这个过滤器得知,再timeWindow时间内,我们的访问次数是否超过设定的currentAccessCount

然后配置过滤器使其生效:

下面是针对上面的一些参数的配置读取

yaml里面配置风控的参数


Sentinel 的QPS限流
导入依赖:
  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.alibaba.csp</groupId>
  7. <artifactId>sentinel-annotation-aspectj</artifactId>
  8. </dependency>
这个限制的时每秒的QPS为1:
  1. /**
  2. * 初始化限流配置
  3. *
  4. */
  5. @Component
  6. public class SentinelRuleConfig implements InitializingBean {
  7. @Override
  8. public void afterPropertiesSet() throws Exception {
  9. List<FlowRule> rules = new ArrayList<>();
  10. FlowRule createOrderRule = new FlowRule();
  11. createOrderRule.setResource("create_short-link");
  12. createOrderRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
  13. createOrderRule.setCount(1);
  14. rules.add(createOrderRule);
  15. FlowRuleManager.loadRules(rules);
  16. }
  17. }
如果触发风控,设置降级策略。
  1. /**
  2. * 自定义流控策略
  3. *
  4. */
  5. public class CustomBlockHandler {
  6. public static Result<ShortLinkCreateRespDTO> createShortLinkBlockHandlerMethod(ShortLinkCreateReqDTO requestParam, BlockException exception) {
  7. return new Result<ShortLinkCreateRespDTO>().setCode("B100000").setMessage("当前访问网站人数过多,请稍后再试...");
  8. }
  9. }
在代码中引入 Sentinel 注解控制流控规则。
  1. /**
  2. * 创建XXX
  3. */
  4. @PostMapping("/api/short-link/v1/create")
  5. @SentinelResource(
  6. value = "create_short-link",
  7. blockHandler = "createShortLinkBlockHandlerMethod",
  8. blockHandlerClass = CustomBlockHandler.class
  9. )
  10. public Result<ShortLinkCreateRespDTO> createShortLink(@RequestBody ShortLinkCreateReqDTO requestParam) {
  11. return Results.success(shortLinkService.createShortLink(requestParam));
  12. }

限制了每秒钟只能有一个创建XXX的请求被成功处理。多余的请求在该时间段内会被限流处理(如返回错误信息、等待、丢弃等),直到下一秒开始重新计数。这样可以防止短时间内大量请求对服务端造成压力,保证系统的稳定性和可用性。


用Redis实现流量风控

用redis的自增,key不存在,设置值为1,每次访问加1。

有效期是timeWindow,访问次数是currentAccessCount

lua脚本如下:
  1. -- 设置用户访问频率限制的参数
  2. local username = KEYS[1]
  3. local timeWindow = tonumber(ARGV[1]) -- 时间窗口,单位:秒
  4. -- 构造 Redis 中存储用户访问次数的键名
  5. local accessKey = "short-link:user-flow-risk-control:" .. username
  6. -- 原子递增访问次数,并获取递增后的值
  7. local currentAccessCount = redis.call("INCR", accessKey)
  8. -- 设置键的过期时间
  9. redis.call("EXPIRE", accessKey, timeWindow)
  10. -- 返回当前访问次数
  11. return currentAccessCount
配置过滤器器执行lua脚本,判断访问次数是否超过:
我们可以通过这个过滤器得知,再timeWindow时间内,我们的访问次数是否超过设定的currentAccessCount
  1. /**
  2. * 用户操作流量分控过滤器
  3. */
  4. @Slf4j
  5. @RequiredArgsConstructor
  6. public class UserFlowRiskControlFilter implements Filter {
  7. private final StringRedisTemplate stringRedisTemplate;
  8. private final UserFlowRiskControlConfiguration userFlowRiskControlConfiguration;
  9. private static final String USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH = "lua/user_flow_risk_control.lua";
  10. @SneakyThrows
  11. @Override
  12. public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
  13. // lua脚本执行 魔板
  14. DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
  15. //lua脚本执 路径
  16. redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(USER_FLOW_RISK_CONTROL_LUA_SCRIPT_PATH)));
  17. //返回值结果类型
  18. redisScript.setResultType(Long.class);
  19. String username = Optional.ofNullable(UserContext.getUsername()).orElse("other");
  20. Long result;
  21. try {
  22. result = stringRedisTemplate.execute(redisScript, Lists.newArrayList(username), userFlowRiskControlConfiguration.getTimeWindow());
  23. } catch (Throwable ex) {
  24. log.error("执行用户请求流量限制LUA脚本出错", ex);
  25. returnJson((HttpServletResponse) response, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));
  26. return;
  27. }
  28. if (result == null || result > userFlowRiskControlConfiguration.getMaxAccessCount()) {
  29. returnJson((HttpServletResponse) response, JSON.toJSONString(Results.failure(new ClientException(FLOW_LIMIT_ERROR))));
  30. return;
  31. }
  32. filterChain.doFilter(request, response);
  33. }
  34. private void returnJson(HttpServletResponse response, String json) throws Exception {
  35. response.setCharacterEncoding("UTF-8");
  36. response.setContentType("text/html; charset=utf-8");
  37. try (PrintWriter writer = response.getWriter()) {
  38. writer.print(json);
  39. }
  40. }
  41. }
然后配置过滤器使其生效:
  1. package com.wyk.config;
  2. import com.wyk.common.biz.user.UserFlowRiskControlFilter;
  3. import com.wyk.common.biz.user.UserTransmitFilter;
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  5. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.data.redis.core.StringRedisTemplate;
  9. /**
  10. * 用户配置自动装配
  11. */
  12. @Configuration
  13. public class UserConfiguration {
  14. /**
  15. * 用户操作流量风控过滤器
  16. */
  17. @Bean
  18. @ConditionalOnProperty(name = "short-link.flow-limit.enable", havingValue = "true")
  19. public FilterRegistrationBean<UserFlowRiskControlFilter> globalUserFlowRiskControlFilter(
  20. StringRedisTemplate stringRedisTemplate,
  21. UserFlowRiskControlConfiguration userFlowRiskControlConfiguration) {
  22. FilterRegistrationBean<UserFlowRiskControlFilter> registration = new FilterRegistrationBean<>();
  23. registration.setFilter(new UserFlowRiskControlFilter(stringRedisTemplate, userFlowRiskControlConfiguration));
  24. registration.addUrlPatterns("/*");
  25. registration.setOrder(10);
  26. return registration;
  27. }
  28. }
下面是针对上面的一些参数的配置读取
  1. @Data
  2. @Component
  3. @ConfigurationProperties(prefix = "short-link.flow-limit")
  4. public class UserFlowRiskControlConfiguration {
  5. /**
  6. * 是否开启用户流量风控验证
  7. */
  8. private Boolean enable;
  9. /**
  10. * 流量风控时间窗口,单位:秒
  11. */
  12. private String timeWindow;
  13. /**
  14. * 流量风控时间窗口内可访问次数
  15. */
  16. private Long maxAccessCount;
  17. }
yaml里面配置风控的参数
  1. short-link:
  2. flow-limit:
  3. enable: true
  4. time-window: 1
  5. max-access-count: 20

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/431080
推荐阅读
相关标签
  

闽ICP备14008679号