加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

分布式限流,你想知道的都在这里

发布时间:2019-04-25 05:51:23 所属栏目:教程 来源:儒雅程序员
导读:副标题#e# 前言 在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用。 比如最近就有个这样的需求,我作为客户端要向kafka生产数据,而kafka的消费者则再源

这样客户端在使用时:

  1. RedisLimit redisLimit = new RedisLimit.Builder<>(jedisCluster) 
  2.  .limit(limit) 
  3.  .build(); 

更加的简单直接,并且避免了将创建过程分成了多个子步骤。

这在有多个构造参数,但又不是必选字段时很有作用。

因此顺便将分布式锁的构建器方式也一并更新了:

https://github.com/crossoverJie/distributed-redis-tool#features

API

从上文可以看出,使用过程就是调用 limit 方法。

  1. //限流 
  2.  boolean limit = redisLimit.limit(); 
  3.  if (!limit){ 
  4.  //具体限流逻辑 
  5.  } 

为了减少侵入性,也为了简化客户端提供了两种注解方式。

@ControllerLimit

该注解可以作用于 @RequestMapping 修饰的接口中,并会在限流后提供限流响应。

实现如下:

  1. @Component 
  2. public class WebIntercept extends WebMvcConfigurerAdapter { 
  3.  private static Logger logger = LoggerFactory.getLogger(WebIntercept.class); 
  4.  @Autowired 
  5.  private RedisLimit redisLimit; 
  6.  @Override 
  7.  public void addInterceptors(InterceptorRegistry registry) { 
  8.  registry.addInterceptor(new CustomInterceptor()) 
  9.  .addPathPatterns("/**"); 
  10.  } 
  11.  private class CustomInterceptor extends HandlerInterceptorAdapter { 
  12.  @Override 
  13.  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
  14.  Object handler) throws Exception { 
  15.  if (redisLimit == null) { 
  16.  throw new NullPointerException("redisLimit is null"); 
  17.  } 
  18.  if (handler instanceof HandlerMethod) { 
  19.  HandlerMethod method = (HandlerMethod) handler; 
  20.  ControllerLimit annotation = method.getMethodAnnotation(ControllerLimit.class); 
  21.  if (annotation == null) { 
  22.  //skip 
  23.  return true; 
  24.  } 
  25.  boolean limit = redisLimit.limit(); 
  26.  if (!limit) { 
  27.  logger.warn("request has bean limit"); 
  28.  response.sendError(500, "request limit"); 
  29.  return false; 
  30.  } 
  31.  } 
  32.  return true; 
  33.  } 
  34.  } 

其实就是实现了 SpringMVC 中的拦截器,并在拦截过程中判断是否有使用注解,从而调用限流逻辑。

前提是应用需要扫描到该类,让 Spring 进行管理。

  1. @ComponentScan(value = "com.crossoverjie.distributed.intercept") 

@CommonLimit

当然也可以在普通方法中使用。实现原理则是 Spring AOP (SpringMVC 的拦截器本质也是 AOP)。

  1. @Aspect 
  2. @Component 
  3. @EnableAspectJAutoProxy(proxyTargetClass = true) 
  4. public class CommonAspect { 
  5.  private static Logger logger = LoggerFactory.getLogger(CommonAspect.class); 
  6.  @Autowired 
  7.  private RedisLimit redisLimit ; 
  8.  @Pointcut("@annotation(com.crossoverjie.distributed.annotation.CommonLimit)") 
  9.  private void check(){} 
  10.  @Before("check()") 
  11.  public void before(JoinPoint joinPoint) throws Exception { 
  12.  if (redisLimit == null) { 
  13.  throw new NullPointerException("redisLimit is null"); 
  14.  } 
  15.  boolean limit = redisLimit.limit(); 
  16.  if (!limit) { 
  17.  logger.warn("request has bean limit"); 
  18.  throw new RuntimeException("request has bean limit") ; 
  19.  } 
  20.  } 

很简单,也是在拦截过程中调用限流。

当然使用时也得扫描到该包:

  1. @ComponentScan(value = "com.crossoverjie.distributed.intercept") 

总结

限流在一个高并发大流量的系统中是保护应用的一个利器,成熟的方案也很多,希望对刚了解这一块的朋友提供一些思路。

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读