MST

星途 面试题库

面试题:微服务架构下Spring Cloud实现服务限流的常见算法有哪些及原理

在Spring Cloud微服务架构中,实现服务限流是保障系统稳定性的重要手段。请阐述常见的服务限流算法,比如令牌桶算法、漏桶算法的原理,并且说明在Spring Cloud中如何基于这些算法来实现服务限流。
21.5万 热度难度
后端开发微服务架构

知识考点

AI 面试

面试题答案

一键面试

令牌桶算法原理

  1. 核心概念:系统以固定速率生成令牌放入桶中,请求到达时尝试从桶中获取令牌。如果桶中有足够令牌,请求可以被处理并消耗相应令牌;若桶中无令牌,请求则可能被限流(比如直接拒绝或等待令牌)。
  2. 特点:能允许一定程度的突发流量,只要桶中有足够令牌。例如,桶容量为100,生成令牌速率为每秒10个,在某瞬间桶中有100个令牌,此时可以允许100个请求瞬间通过。

漏桶算法原理

  1. 核心概念:请求(水)先进入到漏桶里,漏桶以固定速率(漏水速率)流出请求进行处理。如果流入请求的速度过快,桶满后多余的请求会被丢弃。
  2. 特点:可以平滑突发流量,保证流出的速率稳定。无论请求到达多么集中,都以固定速率处理,如漏水速率设定为每秒处理10个请求,即使瞬间有100个请求到达,也只能每秒处理10个。

在Spring Cloud中基于令牌桶算法实现服务限流

  1. 使用Guava库:Guava库提供了RateLimiter类实现令牌桶算法。
    • 引入依赖:在pom.xml中添加Guava依赖:
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.1-jre</version>
</dependency>
- **代码实现**:在需要限流的服务方法中使用`RateLimiter`。例如:
import com.google.common.util.concurrent.RateLimiter;

public class MyService {
    private final RateLimiter rateLimiter = RateLimiter.create(10.0); // 每秒生成10个令牌

    public void limitedMethod() {
        if (rateLimiter.tryAcquire()) {
            // 处理业务逻辑
        } else {
            // 限流处理,如返回提示信息等
        }
    }
}
  1. 结合Spring AOP:可以通过Spring AOP将限流逻辑统一管理。
    • 创建切面类
import com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RateLimitAspect {
    private final RateLimiter rateLimiter = RateLimiter.create(10.0);

    @Around("@annotation(rateLimit)")
    public Object checkRateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        if (rateLimiter.tryAcquire()) {
            return joinPoint.proceed();
        } else {
            // 限流处理
            throw new RuntimeException("请求限流");
        }
    }
}
- **定义注解**:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimit {
}
- **在方法上使用注解**:
import org.springframework.stereotype.Service;

@Service
public class MyServiceImpl {
    @RateLimit
    public void myMethod() {
        // 业务逻辑
    }
}

在Spring Cloud中基于漏桶算法实现服务限流

  1. 使用自定义漏桶实现:可以自行编写漏桶算法的实现。例如:
public class LeakyBucket {
    private final long capacity;
    private final long rate;
    private long lastLeakTime;
    private long water;

    public LeakyBucket(long capacity, long rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.lastLeakTime = System.currentTimeMillis();
        this.water = 0;
    }

    public boolean tryConsume(int tokens) {
        long now = System.currentTimeMillis();
        long leaked = (now - lastLeakTime) * rate / 1000;
        water = Math.max(0, water - leaked);
        lastLeakTime = now;

        if (water + tokens <= capacity) {
            water += tokens;
            return true;
        }
        return false;
    }
}

在需要限流的地方使用:

public class MyService {
    private final LeakyBucket leakyBucket = new LeakyBucket(100, 10); // 容量100,每秒处理10个请求

    public void limitedMethod() {
        if (leakyBucket.tryConsume(1)) {
            // 处理业务逻辑
        } else {
            // 限流处理
        }
    }
}
  1. 使用第三方组件:如Resilience4j,它支持多种限流算法包括漏桶算法。
    • 引入依赖
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
    <version>1.7.1</version>
</dependency>
- **配置漏桶限流**:
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;

public class MyService {
    private final RateLimiter rateLimiter;

    public MyService() {
        RateLimiterConfig config = RateLimiterConfig.custom()
               .limitForPeriod(10) // 周期内限制请求数
               .limitRefreshPeriod(1000) // 周期时长,毫秒
               .timeoutDuration(Duration.ofMillis(100)) // 等待令牌超时时间
               .build();

        RateLimiterRegistry registry = RateLimiterRegistry.of(config);
        rateLimiter = registry.rateLimiter("myRateLimiter");
    }

    public void limitedMethod() {
        RateLimiter.Context context = rateLimiter.acquirePermission();
        if (context != null) {
            try {
                // 处理业务逻辑
            } finally {
                context.release();
            }
        } else {
            // 限流处理
        }
    }
}