zuul实现限流

zuul限流
限流算法
漏桶: leakey bucket,原理:桶的下方的小孔会以一个相对恒定的速率漏水,而不管入桶的水流量,这样就达到了控制出水口的流量
令牌桶: token bucket,原理:以相对恒定的速率向桶中加入令牌,请求来时于桶中取令牌,取到了就放行,没能取到令牌的请求则丢弃
限流粒度
粗粒度
网关限流
单个服务
细粒度
user: 认证用户或者匿名,针对某个用户粒度进行限流
origin: 客户机的IP,针对请求客户机的IP进行限流
url: 特定url,针对请求的url粒度进行限流
serviceId: 特定服务,针对某个服务的id粒度进行限流
实现
从单个服务的角度实现限流,原理:利用redis键过期的自动删除的特性。以url为key,如果key不存在,创建key,并设置键过期时间,相同请求过来就对这个key进行计数,使用redis.incr原子方法,当请求超过limit时,则不让请求api。

1.定义注解:br/>@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
br/>@Documented
public @interface RateLimit {

//每秒请求
int value() default 10;

}

2.定义切面br/>@Aspect
@Component
br/>@Slf4j
public class RateLimitAspect {

@Autowired
private RedisTemplate redisTemplate;

@Pointcut(value = "@annotation(com.pinlor.gml.cloudrateservice.annotation.RateLimit)")
public void pointcut(){

}

@Around(value = "pointcut()")
@ResponseBody
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    log.debug("限速检测");
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method method = methodSignature.getMethod();
    RateLimit rate = method.getAnnotation(RateLimit.class);
    int limit = rate.value();
    HttpServletRequest request = RequestUtil.getRequest();
    String key = request.getRequestURI();
    //最好以下部分用redis分布锁加锁一下
    Object object = redisTemplate.opsForValue().get(key);
    if (object == null){
        redisTemplate.opsForValue().increment(key);
        redisTemplate.expire(key, 1, TimeUnit.SECONDS);
    }else {
        System.out.println("当前记数: "+ redisTemplate.opsForValue().get(key));
        if (redisTemplate.opsForValue().increment(key) > limit) {
            System.out.println("服务器繁忙,请稍后再试!!");
            return "服务器繁忙,请稍后再试!!";
        }
    }

    return joinPoint.proceed();

}

}

3.redis配置:br/>@Configuration
public class RedisConfig {

@Autowired
private RedisConnectionFactory redisConnectionFactory;

// 默认用的是用JdkSerializationRedisSerializer进行序列化的
@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    // 注入数据源
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 使用Jackson2JsonRedisSerialize 替换默认序列化
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
                         new Jackson2JsonRedisSerializer(Object.class);
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
    // key-value结构序列化数据结构
    redisTemplate.setKeySerializer(stringRedisSerializer);
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    // hash数据结构序列化方式,必须这样否则存hash 就是基于jdk序列化的
    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    // 启用默认序列化方式
    redisTemplate.setEnableDefaultSerializer(true);
    redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);

    /// redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

}

4.api服务:br/>@RestController
@RequestMapping(value = "/rc")
public class RateController {

@Value(value = "${server.port}")
private int port;

@RateLimit(value = 10)
@GetMapping("/getRate")
public String getRate(){
    System.out.println("rate from: "+ port);
    return "rate from: "+ port;
}

}

5.工具类:
public class RequestUtil {

扫描二维码关注公众号,回复: 10755255 查看本文章
public static HttpServletRequest getRequest(){
    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
    if (requestAttributes == null){
        return null;
    }
    return ((ServletRequestAttributes)requestAttributes).getRequest();
}

}
6.maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>

猜你喜欢

转载自blog.51cto.com/youling87/2486771