面试题答案
一键面试令牌桶算法原理
- 核心概念:系统以固定速率生成令牌放入桶中,请求到达时尝试从桶中获取令牌。如果桶中有足够令牌,请求可以被处理并消耗相应令牌;若桶中无令牌,请求则可能被限流(比如直接拒绝或等待令牌)。
- 特点:能允许一定程度的突发流量,只要桶中有足够令牌。例如,桶容量为100,生成令牌速率为每秒10个,在某瞬间桶中有100个令牌,此时可以允许100个请求瞬间通过。
漏桶算法原理
- 核心概念:请求(水)先进入到漏桶里,漏桶以固定速率(漏水速率)流出请求进行处理。如果流入请求的速度过快,桶满后多余的请求会被丢弃。
- 特点:可以平滑突发流量,保证流出的速率稳定。无论请求到达多么集中,都以固定速率处理,如漏水速率设定为每秒处理10个请求,即使瞬间有100个请求到达,也只能每秒处理10个。
在Spring Cloud中基于令牌桶算法实现服务限流
- 使用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 {
// 限流处理,如返回提示信息等
}
}
}
- 结合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中基于漏桶算法实现服务限流
- 使用自定义漏桶实现:可以自行编写漏桶算法的实现。例如:
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 {
// 限流处理
}
}
}
- 使用第三方组件:如
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 {
// 限流处理
}
}
}