精华内容
下载资源
问答
  • QoS技术中令牌桶算法实现方式比较,关于QoS令牌桶应用的算法。
  • 基于令牌桶算法实现的SpringBoot无锁限流插件,支持方法级别、系统级别的限流,提供快速失败与CAS阻塞两种方案,开箱即用!
  • 最完整清晰的redis+lua脚本 + 令牌桶算法 实现限流控制 在网上看了好多博客,感觉不是很清楚,于是决定自己手撸一个。 一、自定义一个注解,用来给限流的方法标注 @Target({ElementType.TYPE, ElementType....

    最完整清晰的redislua脚本 + 令牌桶算法 实现限流控制

    在网上看了好多博客,感觉不是很清楚,于是决定自己手撸一个。

    一、自定义一个注解,用来给限流的方法标注

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RateLimit {
        //限流唯一标示
        String key() default "";
    
        //限流单位时间(单位为s)
        int time() default 1;
    
        //单位时间内限制的访问次数
        int count();
    
        //是否限制ip
        boolean ipLimit() default false;
    }
    

    二、编写lua脚本

    重要的地方注释得非常详细了,这里就不多解释;

    主要功能是:

    根据key(参数) 查询 对应的 value(令牌数)
    	如果为null 说明该key 是第一次进入 
    	{
    		初始化 令牌桶(参数)数量;记录初始化时间 ->返回 剩余令牌数
    	} 
    	
    	如果不为null
    	{
    		判断 value 是否大于1 
    		{
    			大于1  ->value - 1  -> 返回 剩余令牌数
    			小于1  -> 判断  补充令牌时间间隔是否足够
    			{
    				足够 -> 补充令牌;更新补充令牌时间-> 返回 剩余令牌数
    				不足够	-> 返回 -1 (说明超过限流访问次数)
    			}
    		}
    	}
    	
    
    redis.replicate_commands();
    -- 参数中传递的key
    local key = KEYS[1]
    -- 令牌桶填充 最小时间间隔
    local update_len = tonumber(ARGV[1])
    -- 记录 当前key上次更新令牌桶的时间的 key
    local key_time = 'ratetokenprefix'..key
    -- 获取当前时间(这里的curr_time_arr 中第一个是 秒数,第二个是 秒数后毫秒数),由于我是按秒计算的,这里只要curr_time_arr[1](注意:redis数组下标是从1开始的)
    --如果需要获得毫秒数 则为 tonumber(arr[1]*1000 + arr[2])
    local curr_time_arr = redis.call('TIME')
    -- 当前时间秒数
    local nowTime = tonumber(curr_time_arr[1])
    -- 从redis中获取当前key 对应的上次更新令牌桶的key 对应的value
    local curr_key_time = tonumber(redis.call('get',KEYS[1]) or 0)
    -- 获取当前key对应令牌桶中的令牌数
    local token_count = tonumber(redis.call('get',KEYS[1]) or -1)
    -- 当前令牌桶的容量
    local token_size = tonumber(ARGV[2])
    -- 令牌桶数量小于0 说明令牌桶没有初始化
    if token_count < 0 then
    	redis.call('set',key_time,nowTime)
    	redis.call('set',key,token_size -1)
    	return token_size -1
    else
    	if token_count > 0 then --当前令牌桶中令牌数够用
    		redis.call('set',key,token_count - 1)
    		return token_count -1   --返回剩余令牌数
    	else    --当前令牌桶中令牌数已清空
    		if curr_key_time + update_len < nowTime then    --判断一下,当前时间秒数 与上次更新时间秒数  的间隔,是否大于规定时间间隔数 (update_len)
    			redis.call('set',key,token_size -1)
    			return token_size - 1
    		else
    			return -1
    		end
    	end
    end
    

    三、读取lua脚本

    @Component
    public class CommonConfig {
        /**
         * 读取限流脚本
         */
        @Bean
        public DefaultRedisScript<Number> redisluaScript() {
            DefaultRedisScript<Number> redisScript = new DefaultRedisScript<>();
            //这里脚本的路径为path for source root 路径
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("myLua.lua"))); 
            redisScript.setResultType(Number.class);
            return redisScript;
        }
        /**
         * RedisTemplate
         */
        @Bean
        public RedisTemplate<String, Serializable> limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    }
    

    四、创建拦截器拦截带有该注解的方法

    @Component
    public class RateLimitInterceptor implements HandlerInterceptor {
        private final Logger LOG = LoggerFactory.getLogger(this.getClass());
        
        @Autowired
        private RedisTemplate<String, Serializable> limitRedisTemplate;
    
        @Autowired
        private DefaultRedisScript<Number> redisLuaScript;
        
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            assert handler instanceof HandlerMethod;
            HandlerMethod method = (HandlerMethod) handler;
            RateLimit rateLimit = method.getMethodAnnotation(RateLimit.class);
            //当前方法上有我们自定义的注解
            if (rateLimit != null) {
                //获得单位时间内限制的访问次数
                int count = rateLimit.count();
                String key = rateLimit.key();
                //获得限流单位时间(单位为s)
                int time = rateLimit.time();
                boolean ipLimit = rateLimit.ipLimit();
                //拼接 redis中的key
                StringBuilder sb = new StringBuilder();
                sb.append(Constants.RATE_LIMIT_KEY).append(key).append(":");
                //如果需要限制ip的话
                if(ipLimit){
                    sb.append(getIpAddress(request)).append(":");
                }
                List<String> keys = Collections.singletonList(sb.toString());
               //执行lua脚本
                Number execute = limitRedisTemplate.execute(redisLuaScript, keys, time, count);
                assert execute != null;
                if (-1 == execute.intValue()) {
                    ResultModel resultModel = ResultModel.error_900("接口调用超过限流次数");
                    response.setStatus(901);
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/json");
                    response.getWriter().write(JSONObject.toJSONString(resultModel));
                    response.getWriter().flush();
                    response.getWriter().close();
                    LOG.info("当前接口调用超过时间段内限流,key:{}", sb.toString());
                    return false;
                } else {
                    LOG.info("当前访问时间段内剩余{}次访问次数", execute.toString());
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
        
        public static String getIpAddr(HttpServletRequest request) {
            String ipAddress = null;
            try {
                ipAddress = request.getHeader("x-forwarded-for");
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getHeader("Proxy-Client-IP");
                }
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getRemoteAddr();
                }
                // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                // "***.***.***.***".length()
                if (ipAddress != null && ipAddress.length() > 15) { 
                    // = 15
                    if (ipAddress.indexOf(",") > 0) {
                        ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                    }
                }
            } catch (Exception e) {
                ipAddress = "";
            }
            return ipAddress;
        }
    
    }
    

    一个自定义的常量

    用作redis前缀

    public class Constants {
        public static final String RATE_LIMIT_KEY = "rateLimit:";
    }
    

    五、在WebConfig中注册这个这个拦截器

    @Configuration
    @EnableWebMvc
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Autowired
        private RateLimitInterceptor rateLimitInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(rateLimitInterceptor);
            super.addInterceptors(registry);
        }
    }
    

    六、注解使用

    @RestController
    @RequestMapping(value = "/test")
    public class TestController {
    
        //限流规则为 1秒内只允许同一个ip发送5次请求
        @RateLimit(key = "testGet",time = 1,count = 5,ipLimit = true)
        @RequestMapping(value = "/get")
        public ResultModel testGet(){
            return ResultModel.ok_200();
        }
    
    }
    展开全文
  • 系统在运行过程中,如遇上某些活动,访问的人数会在一瞬间内爆增,导致服务器瞬间压力飙升,使系统超...本文介绍php基于redis,使用令牌桶算法实现访问流量的控制,提供完整算法说明及演示实例,方便大家学习使用。
  • 本demo适用于分布式环境的基于RateLimiter令牌桶算法的限速控制与基于计数器算法的限量控制,可应用于中小型项目中有相关需求的场景(注:本实现未做压力测试,如果用户并发量较大需验证效果)。
  • 本文针对第一中情况,利用令牌桶算法实现: 这个方法:https://github.com/kwsy/Flask-TrafficShape,其实实现的是限制单个请求的频率。但是思路可以借鉴,我们需要做的是对请求的内容大小进行...

    限流、限速:

    1、针对flask的单个路由进行限流,主要场景是上传文件和下载文件的场景

    2、针对整个应用进行限流,方法:利用nginx网关做限流

    本文针对第一中情况,利用令牌桶算法实现:

     

     

    这个方法:https://github.com/kwsy/Flask-TrafficShape,其实实现的是限制单个请求的频率。但是思路可以借鉴,我们需要做的是对请求的内容大小进行速率限制。那么该如何利用flask下的werkzeug是限制请求呢?源代码看了半天,没有搞太明白,后续再看

     

    参考:

    1、https://juejin.im/post/5ab10045518825557005db65

    2、https://caden16.github.io/python/python%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6/

    3、https://github.com/kwsy/Flask-TrafficShape

    4、http://werkzeug.pocoo.org/docs/0.14/wrappers/#wrappers

    5、http://werkzeug.pocoo.org/docs/0.14/request_data/#limiting-request-data

    转载于:https://www.cnblogs.com/shengulong/p/9020764.html

    展开全文
  • QoS技术中令牌桶算法实现

    千次阅读 2009-08-12 23:41:00
    QoS技术中令牌桶算法实现方式比较前序:令牌桶算法比较麻烦,但是请注意,在IE考试里整形和管制的概念以及在实际生活中所使用的限速都是基于这一算法.所以很有必要搞搞清楚!!!!!今天我发得我的心得,这里暂时先不涉及在...

    QoS技术中令牌桶算法实现方式比较

    前序:令牌桶算法比较麻烦,但是请注意,在IE考试 里整形和管制的概念以及在实际生活中所使用的限速都是基于这一算法.所以很有必要搞搞清楚!!!!!今天我发得我的心得,这里暂时先不涉及在cisco 设备上的配置,我会用专门的专题来讲!!!


    令牌桶算法是目前IP QoS 中最常采用的一种流量 限制方法,广泛应用于约定访问速率技术 、 通用流量整形技术以及物理接口总速率限制等技术中。IETF RFC 建议规范了单速率三色标记和双速率三色标记两种令牌桶算法,在桶的构成、令牌添加和报文处理流程方面前者较后者简单,成为目前业界比较常用的流量标记方 式。在实际应用中,应针对不同的流量特征选择恰当的标记方式。
      令牌桶的常见类型:单速率三色标记(双桶);双速率三色标记(双桶)!!!  

          
    RFC中定义了两种令牌桶算法——单速率三色标记算法和双速率三色标记算法,其评估结果都是为报文打上红、黄、绿三色标记。QoS会根据报文的颜色,设置 报文的丢弃优先级,其中单速率三色标记比较关心报文尺寸的突发,而双速率三色标记则关注速率上的突发,两种算法都可工作于色盲模式和非色盲模式。以下结合这两种工作模式介绍一下RFC中所描述的这两种算法。

    1 单速率三色标记算法
      IETF的RFC文件[2]定义了单速率三色标记算法,评估依据以下3个参数:承诺访问速率(CIR),即向令牌桶中填充令牌的速率;承诺突发尺寸 (CBS),即令牌桶的容量,每次突发所允许的最大流量尺寸(注:设置的突发尺寸必须大于最大报文长度);超额突发尺寸(EBS)。
      一般采用双桶结构:C桶和E桶。Tc表示C桶中的令牌数,Te表示E桶中令牌数,两桶的总容量分别为CBS和EBS。初始状态时两桶是满的,即Tc和 Te初始值分别等于CBS和EBS。令牌的产生速率是CIR,通常是先往C桶中添加令牌,等C桶满了,再往E桶中添加令牌,当两桶都被填满时,新产生的令 牌将会被丢弃。
      色盲模式下,假设到达的报文长度为B。若报文长度B小于C桶中的令牌数Tc,则报文被标记为绿色,且C桶中的令牌数减少B;若Tc<BTe,标记为红色,两桶总令牌数都不减少。

    2 双速率三色标记算法
      IETF的RFC文件[3]定义了双速率三色算法,主要是根据4种流量参数来评估:CIR、CBS、峰值信息速率(PIR),峰值突发尺寸(PBS)。前两种参数与单速率三色算法中的含义相同,PIR这个参数只在交换机 上才有,路由器 没有这个参数。该值必须不小于CIR的设置值,如果大于CIR,则速率限制在CIR于PRI之间的一个值。
      与单速率三色标记算法不同,双速率三色标记算法的两个令牌桶C桶和P桶填充令牌的速率不同,C桶填充速率为CIR,P桶为PIR;两桶的容量分别为 CBS和PBS。用Tc和Tp表示两桶中的令牌数目,初始状态时两桶是满的,即Tc和Tp初始值分别等于CBS和PBS。
      色盲模式下,如果到达的报文速率大于PIR,超过Tp+Tc部分无法得到令牌,报文被标记为红色,未超过Tp+Tc而从P桶中获取令牌的报文标记为黄 色,从C桶中获取令牌的报文被标记为绿色;当报文速率小于PIR,大于CIR时,报文不会得不到令牌,但超过Tp部分报文将从P桶中获取令牌,被标记为黄 色报文,从C桶中获取令牌的报文被标记为绿色;当报文速率小于CIR时,报文所需令牌数不会超过Tc,只从C桶中获取令牌,所以只会被标记为绿色报文。

    展开全文
  • 最完整清晰的redis+ lua脚本 + 令牌桶算法 实现限流控制 在网上看了好多博客,感觉不是很清楚,于是决定自己手撸一个。 一、自定义一个注解,用来给限流的方法标注 @Target({ElementType.TYPE, ElementType.METHOD})...

    最完整清晰的redis+ lua脚本 + 令牌桶算法 实现限流控制

    在网上看了好多博客,感觉不是很清楚,于是决定自己手撸一个。

    一、自定义一个注解,用来给限流的方法标注

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RateLimit {
        //限流唯一标示
        String key() default "";
    
        //限流单位时间(单位为s)
        int time() default 1;
    
        //单位时间内限制的访问次数
        int count();
    
        //是否限制ip
        boolean ipLimit() default false;
    }
    

    二、编写lua脚本

    重要的地方注释得非常详细了,这里就不多解释;

    主要功能是:

    根据key(参数) 查询 对应的 value(令牌数)
    	如果为null 说明该key 是第一次进入 
    	{
    		初始化 令牌桶(参数)数量;记录初始化时间 ->返回 剩余令牌数
    	} 
    	
    	如果不为null
    	{
    		判断 value 是否大于1 
    		{
    			大于1  ->value - 1  -> 返回 剩余令牌数
    			小于1  -> 判断  补充令牌时间间隔是否足够
    			{
    				足够 -> 补充令牌;更新补充令牌时间-> 返回 剩余令牌数
    				不足够	-> 返回 -1 (说明超过限流访问次数)
    			}
    		}
    	}
    	
    
    redis.replicate_commands();
    -- 参数中传递的key
    local key = KEYS[1]
    -- 令牌桶填充 最小时间间隔
    local update_len = tonumber(ARGV[1])
    -- 记录 当前key上次更新令牌桶的时间的 key
    local key_time = 'ratetokenprefix'..key
    -- 获取当前时间(这里的curr_time_arr 中第一个是 秒数,第二个是 秒数后毫秒数),由于我是按秒计算的,这里只要curr_time_arr[1](注意:redis数组下标是从1开始的)
    --如果需要获得毫秒数 则为 tonumber(arr[1]*1000 + arr[2])
    local curr_time_arr = redis.call('TIME')
    -- 当前时间秒数
    local nowTime = tonumber(curr_time_arr[1])
    -- 从redis中获取当前key 对应的上次更新令牌桶的key 对应的value
    local curr_key_time = tonumber(redis.call('get',KEYS[1]) or 0)
    -- 获取当前key对应令牌桶中的令牌数
    local token_count = tonumber(redis.call('get',KEYS[1]) or -1)
    -- 当前令牌桶的容量
    local token_size = tonumber(ARGV[2])
    -- 令牌桶数量小于0 说明令牌桶没有初始化
    if token_count < 0 then
    	redis.call('set',key_time,nowTime)
    	redis.call('set',key,token_size -1)
    	return token_size -1
    else
    	if token_count > 0 then --当前令牌桶中令牌数够用
    		redis.call('set',key,token_count - 1)
    		return token_count -1   --返回剩余令牌数
    	else    --当前令牌桶中令牌数已清空
    		if curr_key_time + update_len < nowTime then    --判断一下,当前时间秒数 与上次更新时间秒数  的间隔,是否大于规定时间间隔数 (update_len)
    			redis.call('set',key,token_size -1)
    			return token_size - 1
    		else
    			return -1
    		end
    	end
    end
    

    三、读取lua脚本

    @Component
    public class CommonConfig {
        /**
         * 读取限流脚本
         */
        @Bean
        public DefaultRedisScript<Number> redisluaScript() {
            DefaultRedisScript<Number> redisScript = new DefaultRedisScript<>();
            //这里脚本的路径为path for source root 路径
            redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("myLua.lua"))); 
            redisScript.setResultType(Number.class);
            return redisScript;
        }
        /**
         * RedisTemplate
         */
        @Bean
        public RedisTemplate<String, Serializable> limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Serializable> template = new RedisTemplate<String, Serializable>();
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    }
    

    四、创建拦截器拦截带有该注解的方法

    @Component
    public class RateLimitInterceptor implements HandlerInterceptor {
        private final Logger LOG = LoggerFactory.getLogger(this.getClass());
        
        @Autowired
        private RedisTemplate<String, Serializable> limitRedisTemplate;
    
        @Autowired
        private DefaultRedisScript<Number> redisLuaScript;
        
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            assert handler instanceof HandlerMethod;
            HandlerMethod method = (HandlerMethod) handler;
            RateLimit rateLimit = method.getMethodAnnotation(RateLimit.class);
            //当前方法上有我们自定义的注解
            if (rateLimit != null) {
                //获得单位时间内限制的访问次数
                int count = rateLimit.count();
                String key = rateLimit.key();
                //获得限流单位时间(单位为s)
                int time = rateLimit.time();
                boolean ipLimit = rateLimit.ipLimit();
                //拼接 redis中的key
                StringBuilder sb = new StringBuilder();
                sb.append(Constants.RATE_LIMIT_KEY).append(key).append(":");
                //如果需要限制ip的话
                if(ipLimit){
                    sb.append(getIpAddress(request)).append(":");
                }
                List<String> keys = Collections.singletonList(sb.toString());
               //执行lua脚本
                Number execute = limitRedisTemplate.execute(redisLuaScript, keys, time, count);
                assert execute != null;
                if (-1 == execute.intValue()) {
                    ResultModel resultModel = ResultModel.error_900("接口调用超过限流次数");
                    response.setStatus(901);
                    response.setCharacterEncoding("utf-8");
                    response.setContentType("application/json");
                    response.getWriter().write(JSONObject.toJSONString(resultModel));
                    response.getWriter().flush();
                    response.getWriter().close();
                    LOG.info("当前接口调用超过时间段内限流,key:{}", sb.toString());
                    return false;
                } else {
                    LOG.info("当前访问时间段内剩余{}次访问次数", execute.toString());
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
        
        public static String getIpAddr(HttpServletRequest request) {
            String ipAddress = null;
            try {
                ipAddress = request.getHeader("x-forwarded-for");
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getHeader("Proxy-Client-IP");
                }
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                    ipAddress = request.getRemoteAddr();
                }
                // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                // "***.***.***.***".length()
                if (ipAddress != null && ipAddress.length() > 15) { 
                    // = 15
                    if (ipAddress.indexOf(",") > 0) {
                        ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                    }
                }
            } catch (Exception e) {
                ipAddress = "";
            }
            return ipAddress;
        }
    
    }
    
    一个自定义的常量

    用作redis前缀

    public class Constants {
        public static final String RATE_LIMIT_KEY = "rateLimit:";
    }
    

    五、在WebConfig中注册这个这个拦截器

    @Configuration
    @EnableWebMvc
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Autowired
        private RateLimitInterceptor rateLimitInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(rateLimitInterceptor);
            super.addInterceptors(registry);
        }
    }
    

    六、注解使用

    @RestController
    @RequestMapping(value = "/test")
    public class TestController {
    
        //限流规则为 1秒内只允许同一个ip发送5次请求
        @RateLimit(key = "testGet",time = 1,count = 5,ipLimit = true)
        @RequestMapping(value = "/get")
        public ResultModel testGet(){
            return ResultModel.ok_200();
        }
    
    }
    

    如果觉得有问题,欢迎各位大佬指正
    觉得可以的话点个赞再走吧!!!!!!

    展开全文
  • 令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水)...
  •  基于令牌桶算法实现的分布式无锁限流框架,支持熔断降级,支持动态配置规则,支持可视化监控,开箱即用。  Noun#  限流#  当我们设计了一个函数,准备上线,这时候这个函数会消耗一些资源,处理上限是1秒...
  • 前端每次请求从令牌桶取走令牌,后端匀速向桶内投递令牌,如果前端取到令牌,则说明这次请求有效,否则让前端再次请求或者等待。避免了大量请求下服务器压力过大导致的崩溃问题。 令牌桶类: <?php class ...
  • go-rate是速率限制器库,基于 Token Bucket(令牌桶)算法实现。 go-rate被用在LangTrend的生产中 用于遵守GitHub API速率限制。 速率限制可以完成一些特殊的功能需求,包括但不限于服务器端垃圾邮件保护、防止api调用...
  • 令牌桶算法实现限流

    2021-05-16 15:45:42
    令牌桶算法中,存在一个桶,用来存放固定数量的令牌。该算法以一定的速率往桶中放入令牌。每次请求需要先获取到桶中的令牌才能继续执行,否则等待可用的令牌,或者直接拒绝。   放令牌的动作是持续不断进行的,...
  • 基于令牌桶算法实现的分布式无锁限流框架,支持动态配置规则,支持可视化监控,开箱即用。 Document 使用文档:| 功能概要 限流 降级 授权 注解 监控 黑名单 白名单 控制台 分布式 高可用 设计模式 单例模式 观察者...
  • 技术上使用Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法来完成限流,非常易于使用 优点: 支持大的并发,有效利用网络带宽 create(double permitsPerSecond) 根据指定的稳定吞吐率创建...
  • 令牌桶算法:min((当前时间-上次更新桶时间) * 速率 + 桶里剩余的令牌数量,桶大小),即min(((currentMills - last_mill_second) / 1000)*rate+current_permits,max_burst) 举例:在秒杀活动中
  • 基本思路:定义一个chan,chan大小为需要限制的qps大小,go一个协程启动tick,每1000/qps时间在tick中写入数值,启动另一个协程,读取chan中的值,如果读取到chan中有值,则向下层接口发送请求。...
  • 令牌桶算法实现收集

    千次阅读 2017-11-29 23:24:07
    c:实现 http://www-scf.usc.edu/~trigunay/token-bucket.html go实现: https://github.com/juju/ratelimit

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 664
精华内容 265
关键字:

令牌桶算法实现