Skip to content

无侵入的应用级网关限流框架,无需配置文件,细粒度控制,高灵活性,高可用性,使用redis+lua脚本实现。

Notifications You must be signed in to change notification settings

jiashuaizhang/syj-ratelimit

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 

Repository files navigation

syj-ratelimit


项目介绍

此项目为一个无侵入的应用级网关限流框架,如果您正在寻找一个网关限流的框架,使用syj-ratelimit是最明智的选择

为什么选择syj-ratelimit

  1. 无需任何复杂配置文件,一个注解玩转syj-ratelimit
  2. 细粒度控制,您可以控制同一个类中的A方法每分钟限流100而B方法每分钟限流200
  3. 高灵活性,可根据自定义信息(如用户id、用户ip、用户权限等)进行限流、可灵活选择限流算法
  4. 高可用性,使用redis+lua脚本的原子性为分布式系统保驾护航
  5. 高可扩展性,可灵活添加限流算法

Quick Start

1. 引入syj-ratelimit

<dependency>
    <groupId>cn.org.zhixiang</groupId>
    <artifactId>syj-ratelimit</artifactId>
    <version>${lastVersion}</version>
 </dependency>
注: 当前fork没有发布到maven中心仓库,请编译源码手动安装

2. 注册syj-ratelimit

因为并不是所有的项目都会使用SpringBoot,所以在注册这一步我们分为两种情况

1.SpringBoot或SpringCloud项目

您需要在启动类上增加一个注解

@EnableSyjRateLimit

2.Spring

您需要提供一个可以被Spring管理的配置类。比如说:

@Import(EnableSyjRateLimitConfiguration.class)
@Configuration
public class SyjRateLimitConfig {
}

3. 配置您的redis连接

您需要配置您的redis连接为syj-ratelimit,同2的情况我们把项目分为两种情况(注意下方的配置需要根据实际情况调整)

1.SpringBoot或SpringCloud项目

spring:
  redis:
  
    #cluster: 集群模式启用
     # nodes: 10.0.20.135:7010,10.0.20.135:7011,10.0.20.135:7012
    host: 
    port: 
    password:
    pool:
      max-active: 8
      max-wait: 1
      max-idle: 8
      min-idle: 0
    timeout: 2000

2. Spring应用

您只需要注册一个RedisConnectionFactory子类的bean。比如说

<beans>
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
        <property name="poolConfig" ref="poolConfig" />
        <property name="port" value="${redis.port}" />
        <property name="hostName" value="${redis.host}" />
        <property name="timeout" value="${redis.timeout}" ></property>
        <property name="database" value="1"></property>
    </bean>
</beans>

4. 使用syj-ratelimit

其实看到这一步的时候您已经可以使用syj-ratelimit来进行限流了哦。

syj-ratelimit为您提供了注解来进行限流,只需在类或方法上@RateLimit
public @interface RateLimit {
    /**
     *ALL
     */
    public CheckTypeEnum checkType() default CheckTypeEnum.ALL;
    
    /**
     * 限流算法
     * @return
     */
    RateLimitAlgorithm algorithm() default RateLimitAlgorithm.COUNTER;
    /**
     * 限流次数。默认值10
     */
    public long limit() default 10;
    /**
     * 限流时间间隔,以秒为单位。默认值60
     */
    public long refreshInterval() default 60;

}

来几个使用的例子吧

  1. 限流总资源数。(例如,需要每个方法每30秒只允许调用10次)
@RateLimit(limit = 10,refreshInterval=30)
@RestController
@RequestMapping("/testClass")
public class TestClassRateLimitController {

    @PostMapping("/havaParam")
    public void havaParam(@RequestBody Map<String,String> map){
        System.out.println("业务逻辑。。。。");
    }

    @GetMapping("/noParam")
    public void noParam(){
        System.out.println("业务逻辑。。。。");
    }

}
  1. 根据IP限流总资源数
@RateLimit(limit = 10,refreshInterval=30,checkType = CheckTypeEnum.IP)//每个IP每30秒可以访问10次
  1. 根据自定义信息限流总资源数(自定义时推荐在controller中查出能标识用户唯一性的值放入request中,然后把限流注解添加到service中进行限流)
@RestController
@RequestMapping("/testAnnotation")
public class TestRateLimitController {

    @Autowired
    private TestService testCstom;

    @PostMapping("/custom")
    public void custom(HttpServletRequest httpServletRequest){
        //根据一系列操作查出来了用户id
        httpServletRequest.setAttribute(Const.CUSTOM,"用户id");//限流时在httpServletRequest中根据Const.CUSTOM的值进行限流
        testCstom.testCstom();
    }
}

@RateLimit(limit = 10,refreshInterval=30,checkType = CheckTypeEnum.CUSTOM)
public class TestService {
    public  void testCstom(){
        System.out.println("此方法每个key为Const.CUSTOM的用户每30秒可以进入10次");
    }
}
  1. 限流某个方法的并发数
@RestController
@RequestMapping("/testAnnotation")
public class TestRateLimitController {

    @PostMapping("/defult")
    public void defult(){
        System.out.println("没有拦截");
    }

    @PostMapping("/ip")
    public void ip(){
        System.out.println("没有拦截");
    }

    @RateLimit(checkType = CheckTypeEnum.USER)
    @PostMapping("/user")
    public void user(){
        System.out.println("根据用户信息拦截");//用户信息取自request.getUserPrincipal()
    }

}

更多信息

相信看完了上方的Quick Start您已经迫不及待的想要将syj-ratelimit应用于生产了。我在这里为您提供了两种限流算法。您可以根据自己系统的需求选择自己需要的算法

限流算法

如果您对限流算法不太了解的话可以先参考一下这篇文章http://zhixiang.org.cn

  1. 计数器法
    程序默认使用计数器算法进行限流,如果您要使用计数器法的话无需要额外的配置。
  2. 令牌桶算法
    如果您想要使用令牌桶算法的话,那么有两个需要注意的地方。
    1. 在注解中指定algorithm为TOKEN_BUCKET
        @RateLimit(limit = 8, algorithm = RateLimitAlgorithm.TOKEN_BUCKET)
    1. 您需要将目光放到@RateLimit上的另外两个属性上
        /**
         * 向令牌桶中添加数据的时间间隔,以秒为单位。默认值10秒
         */
        public long tokenBucketTimeInterval() default 10;
        /**
         * 每次为令牌桶中添加的令牌数量。默认值5个
         */
        public long tokenBucketStepNum() default 5;

再次开发

如果您想使用别的算法,您可以在这fork项目进行开发

为了遵守代码的开闭原则,您在添加新的限流算法时请参考包ratelimit、config和algorithm

作者信息

  1. 个人网站
  2. GitHub

项目实现设计的技术

  1. 如何使用Redis执行Lua脚本
  2. 我是如何把自定义注解应用到生产的
  3. 大型网站限流算法的实现和改造
  4. IDEA中使用lombok插件
  5. SpringBoot条件注解@Conditional
  6. 策略模式
  7. 如何将自己的jar包发布到mavan中央仓库

版本信息

1.0.0

syj-ratelimit上线

1.1.0
  1. 修复计算令牌数取整问题
  2. 修复redis集群部署slot不一致问题
1.1.1
  1. 修复令牌桶算法脚本的bug
z-1.1.2
  1. 修复集群模式下的bug,修正hashTag的使用
z-1.1.3
  1. 统一了类和方法上的注解,以方法注解为优先
  2. 限流算法细化到注解级

About

无侵入的应用级网关限流框架,无需配置文件,细粒度控制,高灵活性,高可用性,使用redis+lua脚本实现。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 93.3%
  • Lua 6.7%