diff --git a/redis限流/pom.xml b/redis限流/pom.xml new file mode 100644 index 0000000..f74f39b --- /dev/null +++ b/redis限流/pom.xml @@ -0,0 +1,138 @@ + + + + + + 8 + 8 + 2.1.8.RELEASE + Greenwich.SR3 + 2.1.0.RELEASE + 1.8 + 1.7.25 + 2.12.0 + 1.2.17 + 1.6.1 + 2.7.6 + 2.8.4 + 4.0.1 + 3.4.6 + 0.1 + 1.0.0 + 1.5.0 + + + 4.0.0 + com.yomahub.tlog.example + tlog-example-logback-feign-consumer + 1.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + com.google.guava + guava + 30.1-jre + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + + com.yomahub + tlog-feign-spring-boot-starter + ${tlog.version} + + + com.yomahub + tlog-web-spring-boot-starter + ${tlog.version} + + + org.projectlombok + lombok + + + junit + junit + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring-cloud-alibaba.version} + pom + import + + + + + log4j + log4j + ${log4j.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + + + diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.java new file mode 100644 index 0000000..b44c806 --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.java @@ -0,0 +1,19 @@ +package com.yomahub.tlog.example.feign; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableFeignClients +//@EnableDiscoveryClient +@EnableAsync +public class TLogFeignConsumerRunner { + + public static void main(String[] args) { + SpringApplication.run(TLogFeignConsumerRunner.class, args); + + } +} diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimit.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimit.java new file mode 100644 index 0000000..aa83e6a --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimit.java @@ -0,0 +1,30 @@ +package com.yomahub.tlog.example.feign.aop; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +@Documented +public @interface RedisLimit { + /** + * 资源的key,唯一 + * 作用:不同的接口,不同的流量控制 + */ + String key() default ""; + + /** + * 最多的访问限制次数 + */ + long permitsPerSecond() default 2; + + /** + * 过期时间也可以理解为单位时间,单位秒,默认60 + */ + long expire() default 60; + + + /** + * 得不到令牌的提示语 + */ + String msg() default "系统繁忙,请稍后再试."; +} diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimitAop.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimitAop.java new file mode 100644 index 0000000..a739dba --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/aop/RedisLimitAop.java @@ -0,0 +1,117 @@ +package com.yomahub.tlog.example.feign.aop; + +import com.yomahub.tlog.example.feign.exception.RedisLimitException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.scripting.support.ResourceScriptSource; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * Limit AOP + */ +@Slf4j +@Aspect +@Component +public class RedisLimitAop { + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + + @Pointcut("@annotation(com.yomahub.tlog.example.feign.aop.RedisLimit)") + private void check() { + + } + + private DefaultRedisScript redisScript; + + @PostConstruct + public void init() { + redisScript = new DefaultRedisScript<>(); + redisScript.setResultType(Long.class); + redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua"))); + } + + + @Before("check()") + public void before(JoinPoint joinPoint) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + + //拿到RedisLimit注解,如果存在则说明需要限流 + RedisLimit redisLimit = method.getAnnotation(RedisLimit.class); + + if (redisLimit != null) { + //获取redis的key + String key = redisLimit.key(); + String className = method.getDeclaringClass().getName(); + String name = method.getName(); + + String limitKey = key + className + method.getName(); + + log.info(limitKey); + + if (StringUtils.isEmpty(key)) { + throw new RedisLimitException("key cannot be null"); + } + + long limit = redisLimit.permitsPerSecond(); + + long expire = redisLimit.expire(); + + List keys = new ArrayList<>(); + keys.add(key); + + Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limit), String.valueOf(expire)); + + log.info("Access try count is {} for key={}", count, key); + + if (count != null && count == 0) { + log.debug("获取key失败,key为{}", key); + throw new RedisLimitException(redisLimit.msg()); + } + } + + } + +// /** +// * 构建redis lua脚本 +// * +// * @return +// */ +// private String buildLuaScript() { +// StringBuilder luaString = new StringBuilder(); +// luaString.append("local key = KEYS[1]"); +// //获取ARGV内参数Limit +// luaString.append("\nlocal limit = tonumber(ARGV[1])"); +// //获取key的次数 +// luaString.append("\nlocal curentLimit = tonumber(redis.call('get', key) or '0')"); +// luaString.append("\nif curentLimit + 1 > limit then"); +// luaString.append("\nreturn 0"); +// luaString.append("\nelse"); +// //自增长 1 +// luaString.append("\n redis.call('INCRBY', key, 1)"); +// //设置过期时间 +// luaString.append("\nredis.call('EXPIRE', key, ARGV[2])"); +// luaString.append("\nend"); +// return luaString.toString(); +// } +// + + +} \ No newline at end of file diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.java new file mode 100644 index 0000000..701b441 --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.java @@ -0,0 +1,41 @@ +package com.yomahub.tlog.example.feign.configuration; + + +import java.util.HashMap; +import java.util.Map; + +/** + * 现在拦截加密的日志有三类: + * 1,身份证 + * 2,姓名 + * 3,身份证号 + * 加密的规则后续可以优化在配置文件中 + **/ +public class Log4j2Rule { + + /** + * 正则匹配 关键词 类别 + */ + public static Map regularMap = new HashMap<>(); + /** + * TODO 可配置 + * 此项可以后期放在配置项中 + */ + public static final String USER_NAME_STR = "Name,name,联系人,姓名"; + public static final String USER_IDCARD_STR = "empCard,idCard,身份证,证件号"; + public static final String USER_PHONE_STR = "mobile,Phone,phone,电话,手机"; + + /** + * 正则匹配,自己根据业务要求自定义 + */ + private static String IDCARD_REGEXP = "(\\d{17}[0-9Xx]|\\d{14}[0-9Xx])"; + private static String USERNAME_REGEXP = "[\\u4e00-\\u9fa5]{2,4}"; + private static String PHONE_REGEXP = "(? redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式) + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class); + template.setValueSerializer(serializer); + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.afterPropertiesSet(); + + return template; + } + +} + diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/controller/LimitRedisController.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/controller/LimitRedisController.java new file mode 100644 index 0000000..530750d --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/controller/LimitRedisController.java @@ -0,0 +1,29 @@ +package com.yomahub.tlog.example.feign.controller; + + +import com.yomahub.tlog.example.feign.aop.RedisLimit; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * SpringBoot如何用redis限流? + * 可以这样玩! + */ +@Slf4j +@RestController +@RequestMapping("/limit/redis") +public class LimitRedisController { + + /** + * 基于Redis AOP限流 + */ + @GetMapping("/test") + @RedisLimit(key = "redis-limit:test", permitsPerSecond = 2, expire = 1, msg = "当前排队人数较多,请稍后再试!") + public String test() { + log.info("限流成功。。。"); + return "ok"; + } + +} \ No newline at end of file diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..865c935 --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.java @@ -0,0 +1,29 @@ +package com.yomahub.tlog.example.feign.exception; +import com.yomahub.tlog.example.feign.vo.ResultInfo; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice// 声明这个类为全局异常处理器 +public class GlobalExceptionHandler { + + + @ExceptionHandler(RedisLimitException.class) // 声明当前方法要处理的异常类型 + public ResultInfo handlerCustomException(RedisLimitException e) { + //1. 打印日志 +// e.printStackTrace(); + + //2. 给前端提示 + return ResultInfo.error(e.getMessage()); + } + + + //非预期异常 对于他们,我们直接捕获,捕获完了,记录日志, 给前端一个假提示 + @ExceptionHandler(Exception.class) + public ResultInfo handlerException(Exception e) { + //1. 打印日志 + e.printStackTrace(); + + //2. 给前端提示 + return ResultInfo.error("当前系统异常"); + } +} diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/RedisLimitException.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/RedisLimitException.java new file mode 100644 index 0000000..8189b0c --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/exception/RedisLimitException.java @@ -0,0 +1,12 @@ +package com.yomahub.tlog.example.feign.exception; + + +/** + * Redis限流自定义异常 + * @date 2023/3/10 21:43 + */ +public class RedisLimitException extends RuntimeException{ + public RedisLimitException(String msg) { + super( msg ); + } +} \ No newline at end of file diff --git a/redis限流/src/main/java/com/yomahub/tlog/example/feign/vo/ResultInfo.java b/redis限流/src/main/java/com/yomahub/tlog/example/feign/vo/ResultInfo.java new file mode 100644 index 0000000..45bc816 --- /dev/null +++ b/redis限流/src/main/java/com/yomahub/tlog/example/feign/vo/ResultInfo.java @@ -0,0 +1,28 @@ +package com.yomahub.tlog.example.feign.vo; + + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ResultInfo { + + private String message; + private String code; + private T data; + + + public ResultInfo(String message, String code, T data) { + this.message = message; + this.code = code; + this.data = data; + } + + public static ResultInfo error(String message) { + return new ResultInfo(message,"502",null); + } + + + +} diff --git a/redis限流/src/main/resources/application.properties b/redis限流/src/main/resources/application.properties new file mode 100644 index 0000000..acdf5bd --- /dev/null +++ b/redis限流/src/main/resources/application.properties @@ -0,0 +1,19 @@ +spring.application.name=tlog-logback-feign-consumer +server.port=3111 +#eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/ + +tlog.pattern=[$currIp][$spanId][$traceId] +#spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 + +http.connectTimeOutMillis=8000 +http.readTimeOutMillis=8000 + +spring.task.execution.pool.core-size=5 +spring.task.execution.pool.max-size=50 +spring.task.execution.pool.queue-capacity=200 +spring.task.execution.thread-name-prefix=woniugege- + + +spring.redis.host=192.168.56.10 +spring.redis.password=123456 +spring.redis.port=6379 diff --git a/redis限流/src/main/resources/rateLimiter.lua b/redis限流/src/main/resources/rateLimiter.lua new file mode 100644 index 0000000..362e0cc --- /dev/null +++ b/redis限流/src/main/resources/rateLimiter.lua @@ -0,0 +1,16 @@ +--获取KEY +local key = KEYS[1] + +local limit = tonumber(ARGV[1]) + +local curentLimit = tonumber(redis.call('get', key) or "0") + +if curentLimit + 1 > limit +then return 0 +else + -- 自增长 1 + redis.call('INCRBY', key, 1) + -- 设置过期时间 + redis.call('EXPIRE', key, ARGV[2]) + return curentLimit + 1 +end \ No newline at end of file diff --git a/redis限流/target/classes/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat b/redis限流/target/classes/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat new file mode 100644 index 0000000..738e011 Binary files /dev/null and b/redis限流/target/classes/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat differ diff --git a/redis限流/target/classes/application.properties b/redis限流/target/classes/application.properties new file mode 100644 index 0000000..acdf5bd --- /dev/null +++ b/redis限流/target/classes/application.properties @@ -0,0 +1,19 @@ +spring.application.name=tlog-logback-feign-consumer +server.port=3111 +#eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/ + +tlog.pattern=[$currIp][$spanId][$traceId] +#spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 + +http.connectTimeOutMillis=8000 +http.readTimeOutMillis=8000 + +spring.task.execution.pool.core-size=5 +spring.task.execution.pool.max-size=50 +spring.task.execution.pool.queue-capacity=200 +spring.task.execution.thread-name-prefix=woniugege- + + +spring.redis.host=192.168.56.10 +spring.redis.password=123456 +spring.redis.port=6379 diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.class new file mode 100644 index 0000000..e8cec92 Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/TLogFeignConsumerRunner.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimit.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimit.class new file mode 100644 index 0000000..fffc5d9 Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimit.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimitAop.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimitAop.class new file mode 100644 index 0000000..a7ef5fc Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/aop/RedisLimitAop.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.class new file mode 100644 index 0000000..bee301d Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/Log4j2Rule.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/RedisConfig.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/RedisConfig.class new file mode 100644 index 0000000..539739d Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/configuration/RedisConfig.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/controller/LimitRedisController.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/controller/LimitRedisController.class new file mode 100644 index 0000000..3e03560 Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/controller/LimitRedisController.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.class new file mode 100644 index 0000000..af98984 Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/GlobalExceptionHandler.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/RedisLimitException.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/RedisLimitException.class new file mode 100644 index 0000000..d888a1b Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/exception/RedisLimitException.class differ diff --git a/redis限流/target/classes/com/yomahub/tlog/example/feign/vo/ResultInfo.class b/redis限流/target/classes/com/yomahub/tlog/example/feign/vo/ResultInfo.class new file mode 100644 index 0000000..a770600 Binary files /dev/null and b/redis限流/target/classes/com/yomahub/tlog/example/feign/vo/ResultInfo.class differ diff --git a/redis限流/target/classes/rateLimiter.lua b/redis限流/target/classes/rateLimiter.lua new file mode 100644 index 0000000..362e0cc --- /dev/null +++ b/redis限流/target/classes/rateLimiter.lua @@ -0,0 +1,16 @@ +--获取KEY +local key = KEYS[1] + +local limit = tonumber(ARGV[1]) + +local curentLimit = tonumber(redis.call('get', key) or "0") + +if curentLimit + 1 > limit +then return 0 +else + -- 自增长 1 + redis.call('INCRBY', key, 1) + -- 设置过期时间 + redis.call('EXPIRE', key, ARGV[2]) + return curentLimit + 1 +end \ No newline at end of file diff --git a/redis限流/tlog-example-logback-feign-consumer.iml b/redis限流/tlog-example-logback-feign-consumer.iml new file mode 100644 index 0000000..4e9a846 --- /dev/null +++ b/redis限流/tlog-example-logback-feign-consumer.iml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file