服务限流怎么做
限流算法
每个单位时间能通过的请求数固定,超过阈值直接拒绝。
通过维护一个单位时间内的计数器,每次请求计数器加1,当单位时间内计数器累加到大于设定的阈值,则之后的请求都被绝,直到单位时间已经过去,再将计数器重置为零。但可能会在窗口切换时出现流量突刺。
维持一个队列,所有请求先进队列,然后从队列取出请求的速率是固定。【保护请求】
漏桶算法可以很好地限制容量池的大小,从而防止流量暴增。漏桶可以看作是一个带有常量服务时间的单服务器队列,如果漏桶(包缓存)溢出,那么数据包会被丢弃。 在网络中,漏桶算法可以控制端口的流量输出速率,平滑网络上的突发流量,实现流量整形,从而为网络提供一个稳定的流量。
漏桶算法需要通过两个变量进行控制:一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)(从队列取出请求)
按一定额定的速率产生令牌,存入令牌桶,桶有最大容量(应该为微服务最大承载);服务过来时需要请求到一个令牌才可以进入服务执行;服务里就可以保持基本不会超过承载值。【保护服务】
令牌桶算法是对漏桶算法的一种改进,桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。
一、基于springcloud-gateway的Filter限流
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代了Zuul网关。Gateway提供了路由、过滤、限流等功能,其中限流功能主要是通过GatewayFilter实现的。
限流过程与实现原理
Spring Cloud Gateway的限流主要是通过RequestRateLimiter GatewayFilter实现的。这个过滤器会在处理请求之前检查请求是否超过了预设的限流规则。如果超过了限流规则,过滤器会返回HTTP 429 Too Many Requests响应。
RequestRateLimiter过滤器的工作原理是使用一个ReactiveRedisRateLimiter或RedisRateLimiter对象来检查请求的速率。这个对象会在Redis中维护一个令牌桶,每次请求都会尝试从令牌桶中获取一个令牌。如果令牌桶中没有令牌,那么请求就会被限流。
示例
以下是一个基于Spring Cloud Gateway的限流示例:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, RedisRateLimiter redisRateLimiter) {
return builder.routes()
.route("test_route", r -> r.path("/test")
.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter)))
.uri("http://localhost:8080"))
.build();
}
在这个示例中,我们定义了一个路由规则,所有匹配/test路径的请求都会被路由到http://localhost:8080。在路由之前,我们添加了一个RequestRateLimiter过滤器,使用RedisRateLimiter作为限流器。这样,所有匹配/test路径的请求都会被限流。
注意,这个示例需要Redis服务器的支持,因为RedisRateLimiter会在Redis中维护令牌桶。你需要在Spring Cloud Gateway的配置文件中配置Redis服务器的地址和端口。
二、基于Sentinel的限流
Sentinel是阿里巴巴开源的一款轻量级的流量控制、熔断降级Java库,主要用于防止服务雪崩和系统保护。
限流过程与实现原理
Sentinel的限流主要是通过定义资源和规则来实现的。资源是对业务逻辑的抽象,规则定义了资源的访问限制。当一个请求到来时,Sentinel会检查请求的资源是否超过了预设的规则。如果超过了规则,Sentinel会根据策略进行限流,例如直接拒绝、排队等待或慢启动。
Sentinel的限流规则主要有以下几种:
以下是一个基于Sentinel的限流示例:
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.exception.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import java.util.Collections;
public class SentinelDemo {
public static void main(String[] args) {
// 定义限流规则
FlowRule rule = new FlowRule();
rule.setResource("HelloWorld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(10);
FlowRuleManager.loadRules(Collections.singletonList(rule));
// 模拟请求
while (true) {
try (Entry entry = SphU.entry("HelloWorld")) {
// 被保护的业务逻辑
System.out.println("Hello World");
} catch (BlockException e) {
// 被限流的处理逻辑
System.out.println("Blocked");
}
}
}
}
在这个示例中,我们定义了一个名为"HelloWorld"的资源,并为它设置了一个QPS限流规则,限制每秒的访问次数为10。然后我们模拟了一个无限循环的请求,每次请求都会尝试进入"HelloWorld"资源。如果资源没有被限流,那么就执行业务逻辑(打印"Hello World");如果资源被限流,那么就执行被限流的处理逻辑(打印"Blocked")。