brpc基于延迟最大并发度限流

brpc有const concurrenty limiter 和 auto concurrency limiter,用于限制服务的并发度,const concurrency limiter需要实际对服务压测配置,运营起来比较繁琐。auto concurrency limiter比较灵活,基于little’s low法则,但是在使用过程中发现会经常报ELIMIT。
在服务正常运营过程中,流量的增减,请求体的大小这些会有变化,涉及到磁盘请求,磁盘的响应会有波动,造成auto concurrency limiter算法得到的最大并发、最小延迟的波动比较大,所以会经常报ELIMIT。
基于此,提出一个想法,是否可以基于用户对请求的最大延迟要求max_latency,做一个latency concurrency limiter,用concurrency * avg_latency得到请求的预期处理时间,超过用户要求的max_latency就报ELIMIT。用户对请求延迟的要求一般都会比服务的min_latency要高很多,所以这个算法就不会造成太多的报错,也能比较容易运营。
@wwbmmm 辛苦看一下,这样的算法是否合理?

基于请求延迟的并发控制 · Issue #2013 · apache/brpc · GitHub

add timeout concurrency limiter by yanglimingcn · Pull Request #2027 · apache/brpc · GitHub

add timeout concurrency limiter by yanglimingcn · Pull Request #2027 · apache/brpc · GitHub

文档:add timeout concurrency limiter doc by yanglimingcn · Pull Request #2091 · apache/brpc · GitHub

brpc/docs/cn/timeout_concurrency_limiter.md at master · apache/brpc · GitHub

server.cpp

details/method_status.cpp

adaptive_max_concurrency.cpp

global.cpp

constant_concurrency_limiter.h

details/method_status.h

thrift_protocol.cpp

限制最大并发

“并发”可能有两种含义,一种是连接数,一种是同时在处理的请求数。这里提到的是后者。

在传统的同步server中,最大并发不会超过工作线程数,设定工作线程数量一般也限制了并发。但brpc的请求运行于bthread中,M个bthread会映射至N个worker中(一般M大于N),所以同步server的并发度可能超过worker数量。另一方面,虽然异步server的并发不受线程数控制,但有时也需要根据其他因素控制并发量。

brpc支持设置server级和method级的最大并发,当server或method同时处理的请求数超过并发度限制时,它会立刻给client回复brpc::ELIMIT错误,而不会调用服务回调。看到ELIMIT错误的client应重试另一个server。这个选项可以防止server出现过度排队,或用于限制server占用的资源。

默认不开启。

为什么超过最大并发要立刻给client返回错误而不是排队?

当前server达到最大并发并不意味着集群中的其他server也达到最大并发了,立刻让client获知错误,并去尝试另一台server在全局角度是更好的策略。

为什么不限制QPS?

QPS是一个秒级的指标,无法很好地控制瞬间的流量爆发。而最大并发和当前可用的重要资源紧密相关:“工作线程”,“槽位”等,能更好地抑制排队。

另外当server的延时较为稳定时,限制并发的效果和限制QPS是等价的。但前者实现起来容易多了:只需加减一个代表并发度的计数器。这也是大部分流控都限制并发而不是QPS的原因,比如TCP中的“窗口"即是一种并发度。

计算最大并发数

最大并发度 = 极限QPS * 低负载延时 (little’s law)

极限QPS指的是server能达到的最大qps,低负载延时指的是server在没有严重积压请求的前提下时的平均延时。一般的服务上线都会有性能压测,把测得的QPS和延时相乘一般就是该服务的最大并发度。

限制server级别并发度

设置ServerOptions.max_concurrency,默认值0代表不限制。访问内置服务不受此选项限制。

Server.ResetMaxConcurrency()可在server启动后动态修改server级别的max_concurrency。

限制method级别并发度

server.MaxConcurrencyOf("…") = …可设置method级别的max_concurrency。也可以通过设置ServerOptions.method_max_concurrency一次性为所有的method设置最大并发。 当ServerOptions.method_max_concurrency和server.MaxConcurrencyOf("…")=…同时被设置时,使用server.MaxConcurrencyOf()所设置的值。

ServerOptions.method_max_concurrency = 20;                   // Set the default maximum concurrency for all methods
server.MaxConcurrencyOf("example.EchoService.Echo") = 10;    // Give priority to the value set by server.MaxConcurrencyOf()
server.MaxConcurrencyOf("example.EchoService", "Echo") = 10;
server.MaxConcurrencyOf(&service, "Echo") = 10;
server.MaxConcurrencyOf("example.EchoService.Echo") = "10";  // You can also assign a string value

此设置一般发生在AddService后,server启动前。当设置失败时(比如对应的method不存在),server会启动失败同时提示用户修正MaxConcurrencyOf设置错误。

当method级别和server级别的max_concurrency都被设置时,先检查server级别的,再检查method级别的。

注意:没有service级别的max_concurrency。

使用自适应限流算法

实际生产环境中,最大并发未必一成不变,在每次上线前逐个压测和设置服务的最大并发也很繁琐。这个时候可以使用自适应限流算法。

自适应限流是method级别的。要使用自适应限流算法,把method的最大并发度设置为"auto"即可:

// Set auto concurrency limiter for all methods
brpc::ServerOptions options;
options.method_max_concurrency = "auto";

// Set auto concurrency limiter for specific method
server.MaxConcurrencyOf("example.EchoService.Echo") = "auto";

关于自适应限流的更多细节可以看这里

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值