Sentinel与各种开源框架适配

Sentinel是一款优秀的流量控制框架,在实际生产中,我们的项目通过会用到Spring boot,Dubbo等框架,如果在这些框架中实现流量控制,需要怎样配置才是最优解呢,本篇文章重点分析Sentinel如何与各种开源框架适配的。

Web Servlet

Sentinel 提供针对 Servlet 的原生整合,可以对 Web 请求进行流量控制。使用时需引入以下模块(以 Maven 为例):

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>x.y.z</version>
</dependency>

在Spring中增加配置,定义Bean:

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sentinelFilter");
        registration.setOrder(1);

        return registration;
    }
}

实际就是通过Filter机制进行拦截,具体实现流控的类为 CommonFilter

1)对URL进行清洗

用户需要自行实现 UrlCleaner 接口清洗一下资源(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下),然后将其注册至 WebCallbackManager 中。否则会导致资源数量过多,超出资源数量阈值(目前是 6000)时多出的资源的规则将 不会生效。

// Clean and unify the URL.
// For REST APIs, you have to clean the URL (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or
// the amount of context and resources will exceed the threshold.
UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner();
if (urlCleaner != null) {
    target = urlCleaner.clean(target);
}

Web.png

在适配Web Servlet中支持按照来源限流,资源为处理的URL,也可以拼接方法名,定义的资源类型为Web。

Dubbo

在Dubbo中可以划分为 Service Provider 和 Service Consumer,两种维度的侧重点有点区别。

Service Provider

为了保护 Provider 不被激增的流量拖垮影响稳定性,可以给 Provider 配置 QPS 模式的限流,这样当每秒的请求量超过设定的阈值时会自动拒绝多的请求。限流粒度可以是 服务接口 和 服务方法 两种粒度。

具体实现是基于 Dubbo Filter和SPI机制。

provider.png

定义的资源类型为 RPC。

Service Consumer

Service Consumer 作为客户端去调用远程服务。每一个服务都可能会依赖几个下游服务,若某个服务 A 依赖的下游服务 B 出现了不稳定的情况,服务 A 请求 服务 B 的响应时间变长,从而服务 A 调用服务 B 的线程就会产生堆积,最终可能耗尽服务 A 的线程数。我们通过用并发线程数来控制对下游服务 B 的访问,来保证下游服务不可靠的时候,不会拖垮服务自身。基于这种场景,推荐给 Consumer 配置线程数模式的限流,来保证自身不被不稳定服务所影响。

代码基本与 Provider一致,Entry方向为 EntryType.OUT。

gRPC

在使用 Sentinel gRPC Adapter 时,只需要将对应的 Interceptor 注册至对应的客户端或服务端中。其中客户端的示例如下:

public class ServiceClient {

    private final ManagedChannel channel;

    ServiceClient(String host, int port) {
        this.channel = ManagedChannelBuilder.forAddress(host, port)
            .intercept(new SentinelGrpcClientInterceptor()) // 在此处注册拦截器
            .build();
        // 在此处初始化客户端 stub 类
    }
}

服务端的示例如下:

import io.grpc.Server;

Server server = ServerBuilder.forPort(port)
     .addService(new MyServiceImpl()) // 添加自己的服务实现
     .intercept(new SentinelGrpcServerInterceptor()) // 在此处注册拦截器
     .build();

grpc.png

猜你喜欢

转载自juejin.im/post/7235435351049076792