|
1 | 1 | # spring-redis-current-limit |
2 | | -此项目为一个无侵入的应用级网关限流框架,如果您正在寻找一个网关限流的框架,使用spring-redis-current-limit是最明智的选择 |
| 2 | +*** |
| 3 | + |
| 4 | +## 项目介绍 |
| 5 | +> 此项目为一个无侵入的应用级网关限流框架,如果您正在寻找一个网关限流的框架,使用spring-redis-current-limit是最明智的选择 |
| 6 | +
|
| 7 | +### 为什么选择spring-redis-current-limit |
| 8 | +1. 无需任何复杂配置文件,一个注解玩转spring-redis-current-limit<br> |
| 9 | +2. 细粒度控制,您可以控制同一个类中的A方法每分钟限流100而B方法每分钟限流200<br> |
| 10 | +3. 高灵活性,可根据自定义信息(如用户id、用户ip、用户权限等)进行限流、可灵活选择限流算法<br> |
| 11 | +4. 高可用性,使用redis+lua脚本的原子性为分布式系统保驾护航<br> |
| 12 | +5. 高可扩展性,可灵活添加限流算法<br> |
| 13 | +## Quick Start |
| 14 | +### 1. 引入spring-redis-current-limit |
| 15 | +```xml |
| 16 | +<dependency> |
| 17 | + <groupId>com.chqiuu</groupId> |
| 18 | + <artifactId>spring-redis-current-limit</artifactId> |
| 19 | + <version>1.0.0</version> |
| 20 | + </dependency> |
| 21 | +``` |
| 22 | +### 2. 注册spring-redis-current-limit |
| 23 | +>因为并不是所有的项目都会使用SpringBoot,所以在注册这一步我们分为两种情况 |
| 24 | +#### 1.SpringBoot或SpringCloud项目 |
| 25 | +您需要在启动类上增加一个注解 |
| 26 | +```java |
| 27 | +@EnableCurrentLimit |
| 28 | +@SpringBootApplication |
| 29 | +public class StudyApplication { |
| 30 | + public static void main(String[] args) { |
| 31 | + SpringApplication.run(StudyApplication.class, args); |
| 32 | + } |
| 33 | +} |
| 34 | +``` |
| 35 | +#### 2.Spring项目 |
| 36 | +您需要提供一个可以被Spring管理的配置类。比如说: |
| 37 | +```java |
| 38 | +@Import(EnableCurrentLimitConfiguration.class) |
| 39 | +@Configuration |
| 40 | +public class CurrentLimitConfig { |
| 41 | +} |
| 42 | +``` |
| 43 | +### 3. 配置您的redis连接 |
| 44 | +>您需要配置您的redis连接为spring-redis-current-limit,同2的情况我们把项目分为两种情况(注意下方的配置需要根据实际情况调整) |
| 45 | +#### 1.SpringBoot或SpringCloud项目 |
| 46 | +```yaml |
| 47 | +spring: |
| 48 | + redis: |
| 49 | + host: |
| 50 | + port: |
| 51 | + password: |
| 52 | + pool: |
| 53 | + max-active: 8 |
| 54 | + max-wait: 1 |
| 55 | + max-idle: 8 |
| 56 | + min-idle: 0 |
| 57 | + timeout: 2000 |
| 58 | +``` |
| 59 | +#### 2. Spring应用 |
| 60 | +您只需要注册一个RedisConnectionFactory子类的bean。比如说 |
| 61 | +```xml |
| 62 | +<beans> |
| 63 | + <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" > |
| 64 | + <property name="maxIdle" value="${redis.maxIdle}" /> |
| 65 | + <property name="maxWaitMillis" value="${redis.maxWait}" /> |
| 66 | + <property name="testOnBorrow" value="${redis.testOnBorrow}" /> |
| 67 | + </bean> |
| 68 | + <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > |
| 69 | + <property name="poolConfig" ref="poolConfig" /> |
| 70 | + <property name="port" value="${redis.port}" /> |
| 71 | + <property name="hostName" value="${redis.host}" /> |
| 72 | + <property name="timeout" value="${redis.timeout}" ></property> |
| 73 | + <property name="database" value="1"></property> |
| 74 | + </bean> |
| 75 | +</beans> |
| 76 | +``` |
| 77 | +### 4. 使用spring-redis-current-limit |
| 78 | +>其实看到这一步的时候您已经可以使用spring-redis-current-limit来进行限流了哦。<br> |
| 79 | +
|
| 80 | +##### spring-redis-current-limit为您提供了一个注解@CurrentLimit来进行限流。您可以将它用在类上或方法上。 |
| 81 | + |
| 82 | +接下来介绍一下注解中的几个属性 |
| 83 | + |
| 84 | +```java |
| 85 | +@Target({ElementType.METHOD, ElementType.TYPE}) |
| 86 | +@Retention(RetentionPolicy.RUNTIME) |
| 87 | +@Inherited |
| 88 | +@Documented |
| 89 | +public @interface CurrentLimit { |
| 90 | + /** |
| 91 | + * 设置限流条件唯一标识,默认为系统自动生成。建议不配置此项,若想要配置请保证此项的唯一性 |
| 92 | + * |
| 93 | + * @return 限流条件唯一标识 |
| 94 | + */ |
| 95 | + String key() default ""; |
| 96 | + |
| 97 | + /** |
| 98 | + * 设置提示消息 |
| 99 | + * |
| 100 | + * @return 被限流时的提示消息 |
| 101 | + */ |
| 102 | + String message() default "您的手速太快了,请稍后再试"; |
| 103 | + |
| 104 | + /** |
| 105 | + * 设置给定的时间范围 单位(秒) |
| 106 | + * |
| 107 | + * @return 给定的时间范围 单位(秒)。默认值60 |
| 108 | + */ |
| 109 | + long interval() default 60; |
| 110 | + |
| 111 | + /** |
| 112 | + * 设置单位时间内可访问次数(限流次数) |
| 113 | + * 当为令牌桶算法时,为向令牌桶中添加数据的时间间隔, 以秒为单位。默认值10秒 |
| 114 | + * |
| 115 | + * @return 单位时间内可访问次数(限流次数)。默认值10 |
| 116 | + */ |
| 117 | + long limit() default 10; |
| 118 | + |
| 119 | + /** |
| 120 | + * 设置每次为令牌桶中添加的令牌数量 |
| 121 | + * |
| 122 | + * @return 每次为令牌桶中添加的令牌数量。默认值5个 |
| 123 | + */ |
| 124 | + long step() default 5; |
| 125 | + |
| 126 | + /** |
| 127 | + * 设置限流类型。默认值:LOCAL |
| 128 | + */ |
| 129 | + LimitTypeEnum limitType() default LimitTypeEnum.LOCAL; |
| 130 | +} |
| 131 | +``` |
| 132 | +来几个使用的例子吧<br> |
| 133 | +1. 限流一个Controller中的所有接口。(例如,需要每个方法每30秒只允许调用10次)<br> |
| 134 | +```java |
| 135 | +@CurrentLimit(interval = 30, limit = 10, message = "class,您的手速太快了,请稍后再试") |
| 136 | +@RestController |
| 137 | +@RequestMapping("/object") |
| 138 | +public class ObjectCurrentLimitController { |
| 139 | + |
| 140 | + @PostMapping("/havaParam") |
| 141 | + public void havaParam(@RequestBody Map<String, String> map) { |
| 142 | + System.out.println("业务代码havaParam……"); |
| 143 | + } |
| 144 | + |
| 145 | + @GetMapping("/noParam") |
| 146 | + public void noParam() { |
| 147 | + System.out.println("业务代码noParam……"); |
| 148 | + } |
| 149 | +} |
| 150 | +``` |
| 151 | +2. 根据IP限流访问次数 |
| 152 | +```java |
| 153 | +//每个IP每20秒可以访问5次 |
| 154 | +@CurrentLimit(interval = 20, limit = 5, limitType = LimitTypeEnum.IP, message = "IP,您的手速太快了,请稍后再试") |
| 155 | +``` |
| 156 | + |
| 157 | +4. 限流某个方法的并发数 |
| 158 | +```java |
| 159 | +@CurrentLimit(interval = 20, limit = 6, message = "class,您的手速太快了,请稍后再试")// 对当前这个类进行整体限流 |
| 160 | +@RestController |
| 161 | +public class LimiterController { |
| 162 | + private static final AtomicInteger ATOMIC_INTEGER_1 = new AtomicInteger(); |
| 163 | + private static final AtomicInteger ATOMIC_INTEGER_2 = new AtomicInteger(); |
| 164 | + private static final AtomicInteger ATOMIC_INTEGER_3 = new AtomicInteger(); |
| 165 | + |
| 166 | + @CurrentLimit(interval = 20, limit = 5, message = "ALL,您的手速太快了,请稍后再试")// 对这个方法进行整体限流 |
| 167 | + @GetMapping("/limitTest1") |
| 168 | + public int testLimiter1() { |
| 169 | + return ATOMIC_INTEGER_1.incrementAndGet(); |
| 170 | + } |
| 171 | + |
| 172 | + @CurrentLimit(interval = 20, limit = 3, limitType = LimitTypeEnum.CUSTOM)// 对这个方法进行自定义限流 |
| 173 | + @GetMapping("/limitTest2") |
| 174 | + public int testLimiter2(HttpServletRequest request) { |
| 175 | + //根据一系列操作查出来了用户id |
| 176 | + //限流时在httpServletRequest中根据Const.CUSTOM的值进行限流 |
| 177 | + request.setAttribute(Constant.CUSTOM, "用户id"); |
| 178 | + return ATOMIC_INTEGER_2.incrementAndGet(); |
| 179 | + } |
| 180 | + |
| 181 | + @CurrentLimit(interval = 20, limit = 5, limitType = LimitTypeEnum.IP, message = "IP,您的手速太快了,请稍后再试") // 对这个方法进行IP限流 |
| 182 | + @GetMapping("/limitTest3") |
| 183 | + public int testLimiter3() { |
| 184 | + return ATOMIC_INTEGER_3.incrementAndGet(); |
| 185 | + } |
| 186 | +} |
| 187 | +``` |
| 188 | + |
| 189 | + |
| 190 | +## 更多信息 |
| 191 | + |
| 192 | +>相信看完了上方的Quick Start您已经迫不及待的想要将spring-redis-current-limit应用于生产了。我在这里为您提供了两种限流算法。您可以根据自己系统的需求选择自己需要的算法 |
| 193 | +
|
| 194 | +#### 限流算法 |
| 195 | +> 如果您对限流算法不太了解的话可以先参考一下这篇文章[高并发系统的限流方案研究,其实限流实现也不复杂](https://blog.csdn.net/QIU176161650/article/details/111291392) |
| 196 | +
|
| 197 | +1. 令牌桶算法<br> |
| 198 | +程序默认使用令牌桶算法进行限流,如果您要使用令牌桶算法的话无需要额外的配置。 |
| 199 | +2. 计数器算法<br> |
| 200 | +如果您想要使用计数器算法的话,只需要增加一个配置即可。在配置文件中指定算法为计数器算法。(推荐您使用yml文件) |
| 201 | + 1. yml |
| 202 | + ```yaml |
| 203 | + current-limit: |
| 204 | + algorithm: counter |
| 205 | + ``` |
| 206 | + 2. properties |
| 207 | + ```properties |
| 208 | + current-limit.algorithm= counter |
| 209 | + ``` |
| 210 | + |
| 211 | +#### 再次开发 |
| 212 | +> 如果您想使用别的算法,您可以[在这](https://github.com/chqiuu/spring-redis-current-limit)fork项目进行开发 |
| 213 | +
|
| 214 | +#### 作者信息 |
| 215 | +1. [个人博客](https://blog.csdn.net/QIU176161650) |
| 216 | +2. [GitHub](https://github.com/chqiuu) |
| 217 | + |
| 218 | +#### 版本信息 |
| 219 | + |
| 220 | +##### 1.0.0 |
| 221 | +>spring-redis-current-limit 正式上线 |
0 commit comments