在咱們項目開發過程當中,有些接口是暴露在用戶的經常使用中,包括一些高危接口,如 (支付,開發票,訂單),這些接口 都是高危接口,且被用戶常用,在高併發的狀況下,io阻塞,不可避免的出現重複提交,或者點擊頻繁的操做,因此咱們就要加入限流,避免用戶屢次點擊,減小咱們接口的壓力,把整數據不會重複,接口壓力減少java
在咱們作項目負載均衡的時候, 分佈式,微服務架構的時候,不可避免的多個節點,這個時候咱們就要考慮會被隨機分配到各個節點,若是 咱們使用 令牌桶 或者 漏斗桶 算法到話,存到 本地,各個節點不會共享,因此
咱們要考慮模塊,節點間的共享web
自定義註解redis
com.yxl.annotation; org.springframework.core.annotation.AliasFor; java.lang.annotation.*; java.util.concurrent.TimeUnit; (ElementType.METHOD) (RetentionPolicy.RUNTIME) RateLimiter { NOT_LIMITED = ; () ; () ; ; ; }
AOP實現切面 + 令牌桶算法實現算法
com.yxl.aspect; com.yxl.annotation.RateLimiter; lombok.extern.slf4j.Slf4j; org.aspectj.lang.ProceedingJoinPoint; org.aspectj.lang.annotation.Around; org.aspectj.lang.annotation.Aspect; org.aspectj.lang.annotation.Pointcut; org.aspectj.lang.reflect.MethodSignature; org.springframework.core.annotation.AnnotationUtils; org.springframework.stereotype.Component; java.lang.reflect.Method; java.util.concurrent.ConcurrentHashMap; java.util.concurrent.ConcurrentMap; 4j { ConcurrentMap<String, com.google.common.util.concurrent.RateLimiter> RATE_LIMITER_CACHE = ConcurrentHashMap<>(); () { } () { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class); (rateLimiter != && rateLimiter.qps() > RateLimiter.NOT_LIMITED) { qps = rateLimiter.qps(); (RATE_LIMITER_CACHE.get(method.getName()) == ) { RATE_LIMITER_CACHE.put(method.getName(), com.google.common.util.concurrent.RateLimiter.create(qps)); } log.debug(, method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate()); (RATE_LIMITER_CACHE.get(method.getName()) != && !RATE_LIMITER_CACHE.get(method.getName()).tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) { RuntimeException(); } } point.proceed(); } }
使用方式spring
查看結果(這裏使用了自定義異常)apache
com.yxzapp.annotation; org.springframework.core.annotation.AliasFor; java.lang.annotation.*; java.util.concurrent.TimeUnit; (ElementType.METHOD) (RetentionPolicy.RUNTIME) RateLimiter { NOT_LIMITED = ; ; () ; () ; ; ; }
使用 AOP + redis 實現架構
com.yxzapp.aspect; com.yxzapp.annotation.RateLimiter; com.yxzapp.commons.constant.MessageConstant; com.yxzapp.exception.BizException; com.yxzapp.modules.sys.entity.SysUser; com.yxzapp.utils.RedisUtils; lombok.extern.slf4j.Slf4j; org.apache.shiro.SecurityUtils; org.aspectj.lang.ProceedingJoinPoint; org.aspectj.lang.annotation.Around; org.aspectj.lang.annotation.Aspect; org.aspectj.lang.annotation.Pointcut; org.aspectj.lang.reflect.MethodSignature; org.springframework.beans.factory.annotation.Autowired; org.springframework.core.annotation.AnnotationUtils; org.springframework.stereotype.Component; org.springframework.web.context.request.RequestContextHolder; org.springframework.web.context.request.ServletRequestAttributes; javax.servlet.http.HttpServletRequest; java.lang.reflect.Method; java.util.concurrent.ConcurrentHashMap; java.util.concurrent.ConcurrentMap; 4j { RedisUtils redisUtils; () { } () { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); Class aClass = signature.getClass(); RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class); (rateLimiter != && rateLimiter.qps() > RateLimiter.NOT_LIMITED) { qps = rateLimiter.qps(); String key = rateLimiter.className() + ++ method.getName(); (!redisUtils.hasKey(key)){ redisUtils.setMillisecond(key,rateLimiter.qps(),rateLimiter.timeout()); } (redisUtils.get(key) != ) { BizException(MessageConstant.MSG_STATUS,); } log.debug(, key, redisUtils.get(key)); } point.proceed(); } }
使用方式併發
查看結果 (這裏使用了自定義異常)app