令牌桶限流

使用Guava库的RateLimit完成限流的,而其底层使用的是令牌桶算法实现的限流。

 常用的限流算法有两种:漏桶算法令牌桶算法

      漏桶算法思路,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

漏桶图1

令牌桶限流_第1张图片

 

对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如图2所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

令牌桶图2

令牌桶限流_第2张图片

二、基本环境搭建

  • 一个eureka
  • 一个网关zuul

三、创建eureka

(1)创建项目,命名00-eurekaserver-8000

令牌桶限流_第3张图片

(2)依赖



    4.0.0
 
    com.abc
    00-eurekaserver-8000
    0.0.1-SNAPSHOT
    jar
 
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
 
    
        1.8
        Greenwich.SR2
    
 
    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        
 
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    
 
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    
 
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    
 

(3)application.yml配置

server:
  port: 8000
 
eureka:
  instance:
    hostname: localhost  # 指定Eureka主机
  client:
    register-with-eureka: false   # 指定当前主机是否向Eureka服务器进行注册
    fetch-registry: false    # 指定当前主机是否要从Eurka服务器下载服务注册列表
    service-url:   # 服务暴露地址
     defaultZone: http://localhost:8000/eureka
#     defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
 
#  server:
#    enable-self-preservation: false    # 关闭自我保护

(4)启动类

package com.abc.eureka;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 
@SpringBootApplication
@EnableEurekaServer   // 开启Eureka服务
public class EurekaServerApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

四、创建zuul

(1)创建项目,命名00-zuul-tokenbucket-9000

令牌桶限流_第4张图片

(2)依赖



    4.0.0

    com.abc
    00-zuul-tokenbucket-9000
    0.0.1-SNAPSHOT
    jar

    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    

    
        1.8
        Greenwich.SR1
    

    
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-actuator
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-zuul
        
    


    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    


(3)application.yml配置

server:
  port: 9000

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka

spring:
  application:
    name: abcmsc-zuul-depart

zuul:
  routes:
    # 指定微服务的路由规则
    abcmsc-consumer-depart-8080: /abc8080/**
    abcmsc-consumer-depart-8090: /abc8090/**
    abcmsc-consumer-depart: /abc012/**





(4)ZuulFilter类

package com.abc.zuul.filter;

import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class RouteFilter extends ZuulFilter {

    // 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -5;
    }

    @Override
    public Object run() throws ZuulException {
        log.info("通过过滤");
        return null;
    }

    @Override
    public boolean shouldFilter() {
        // 获取请求上下文
        RequestContext context = RequestContext.getCurrentContext();

        // tryAcquire() 只要能够马上获致到1个令牌,则返回true,不阻塞
        // tryAcquire(5, 3, TimeUnit.SECONDS) 在3秒钟内可以获取到5个令牌,则返回true,不阻塞
        // acquire(5) 获取到5个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
        // acquire() 获取到1个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
        if(!RATE_LIMITER.tryAcquire()) {
            log.warn("访问量超载");
            // 指定当前请求未通过过滤
            context.setSendZuulResponse(false);
            // 向客户端返回响应码429,请求数量过多
            context.setResponseStatusCode(429);
            return false;
        }
        return true;
    }
}

(5)启动类

package com.abc.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableZuulProxy    // 开启zuul代理模式
@SpringBootApplication
public class ZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }

}

五、测试

(1)启动eureka

令牌桶限流_第5张图片

(2)启动zuul

令牌桶限流_第6张图片

(3)一秒内浏览器帅新2次

http://localhost:9000/abc8090/consumer/depart/get/1

浏览器显示

令牌桶限流_第7张图片

后台显示

令牌桶限流_第8张图片

你可能感兴趣的:(Spring,Cloud)