于限流,如果是自研或者二次开发,是一个很好的参考。
Resilience4j
之前我们介绍过它的熔断功能,Resilience4j也提供了限流的实现,可以参考这里。相比guava,Resilience4j是框架级别的,可以很方便的使用。但Resilience4j也是单机版的实现,无法支持集群功能。
Resilience4j限流实现的是令牌桶,如下配置,每1s会生成10个令牌。
resilience4j.ratelimiter:
instances:
backendA:
limitForPeriod: 10
limitRefreshPeriod: 1s
timeoutDuration: 0
registerHealthIndicator: true
eventConsumerBufferSize: 100
sentinel
流量控制是sentinel最重要的一个功能,sentinel属于后起之秀,文档齐全,支持的场景更加丰富。sentinel支持集群限流,也可以像guava一样预热,还可以基于调用链路进行限流。
sentinel还提供了控制台功能,支持多种数据源的持久化,使用spring cloud的话可以通过spring cloud alibaba引入sentinel。
开源版的sentinel有一些限制,并且使用起来并不是那么方便,例如Resilience4j可以配置一个default针对所有的请求生效,但sentinel需要单个单个url去配置,显得非常麻烦,包括熔断feign接口的配置也是,这个给spring cloud alibaba提了feature,也许在下一个版本就会提供支持。
nginx
上面讲到的都是应用级别的限流,nginx通常作为网络请求的入口,从运维的角度来说,在这里做限流再合适不过,nginx本身也提供了限流的支持。
nginx比较适合对外的限流,但是我们内部不同系统间的调用一遍不经过nginx,会直接访问到对方的网关,所以两者并不矛盾。
nginx限流通过limit_req和limit_conn两个模块支持,分别对应请求限制和链接限制(一个链接可以有多个请求)。
http {
limit_req_zone zone=name:10m rate=100r/s;
server {
location /app/ {
limit_req zone=name burst=500 nodelay;
}
}
如上,定义了一个name zone,访问速率最高是100个每秒,/app路径应用了这个规则。busrt表示爆发的意思,是一个缓冲队列,用于存储突增的请求,这些请求会被缓存不会拒绝,如果超过了burst,nodelay表示不等待直接拒绝。
前面我们说到有些恶意攻击可能每秒发送上万个请求,导致服务崩溃,如果多个应用系统共用一个nginx,那么可以统一在nginx配置处理,不需要每个系统自己去实现。
limit_conn_zone $binary_remote_addr zone=name:10m;
server {
limit_conn name 50;
}
如上,定义了一个name zone,$binary_remote_addr表示远端地址,也就是ip,10m表示存储空间,10m大概可以存储16w的ip地址,我们在server节点应用这个规则,50表示最多50个,超过就会拒绝。
欢迎关注我的github:https://github.com/jmilktea/jtea