Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
brpc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
brpc
Commits
43dfa79f
Commit
43dfa79f
authored
Sep 15, 2017
by
gejun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove wrongly merged file
parent
24092f31
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
0 additions
and
21 deletions
+0
-21
avalanche_effect.md
docs/cn/avalanche_effect.md
+0
-21
No files found.
docs/cn/avalanche_effect.md
deleted
100644 → 0
View file @
24092f31
“雪崩”指的是访问服务集群时绝大部分请求都超时,且在流量减少时仍无法恢复的现象。下面解释这个现象的来源。
当流量超出服务的最大qps时,服务将无法正常服务;当流量恢复正常时(小于服务的处理能力),积压的请求会被处理,虽然其中很大一部分可能会因为处理的不及时而超时,但服务本身一般还是会恢复正常的。这就相当于一个水池有一个入水口和一个出水口,如果入水量大于出水量,水池子终将盛满,多出的水会溢出来。但如果入水量降到出水量之下,一段时间后水池总会排空。雪崩并不是单一服务能产生的。
如果一个请求经过两个服务,情况就有所不同了。比如请求访问A服务,A服务又访问了B服务。当B被打满时,A处的client会大量超时,如果A处的client在等待B返回时也阻塞了A的服务线程(常见),且使用了固定个数的线程池(常见),那么A处的最大qps就从
**线程数 / 平均延时**
,降到了
**线程数 / 超时**
。由于超时往往是平均延时的3~4倍,A处的最大qps会相应地下降3~4倍,从而产生比B处更激烈的拥塞。如果A还有类似的上游,拥塞会继续传递上去。但这个过程还是可恢复的。B处的流量终究由最前端的流量触发,只要最前端的流量回归正常,B处的流量总会慢慢降下来直到能正常回复大多数请求,从而让A恢复正常。
但有两个例外:
1.
A可能对B发起了过于频繁的基于超时的重试。这不仅会让A的最大qps降到
**线程数 / 超时**
,还会让B处的qps翻
**重试次数**
倍。这就可能陷入恶性循环了:只要
**线程数 / 超时 \* 重试次数**
大于B的最大qps
**,**
B就无法恢复 -> A处的client会继续超时 -> A继续重试 -> B继续无法恢复。
2.
A或B没有限制某个缓冲或队列的长度,或限制过于宽松。拥塞请求会大量地积压在那里,要恢复就得全部处理完,时间可能长得无法接受。由于有限长的缓冲或队列需要在填满时解决等待、唤醒等问题,有时为了简单,代码可能会假定缓冲或队列不会满,这就埋下了种子。即使队列是有限长的,恢复时间也可能很长,因为清空队列的过程是个追赶问题,排空的时间取决于
**积压的请求数 / (最大qps - 当前qps)**
,如果当前qps和最大qps差的不多,积压的请求又比较多,那排空时间就遥遥无期了。
了解这些因素后可以更好的理解brpc中相关的设计。
1.
拥塞时A服务最大qps的跳变是因为线程个数是
**硬限**
,单个请求的处理时间很大程度上决定了最大qps。而brpc server端默认在bthread中处理请求,个数是软限,单个请求超时只是阻塞所在的bthread,并不会影响为新请求建立新的bthread。brpc也提供了完整的异步接口,让用户可以进一步提高io-bound服务的并发度,降低服务被打满的可能性。
2.
brpc中
[
重试
](
client.md#重试
)
默认只在连接出错时发起,避免了流量放大,这是比较有效率的重试方式。如果需要基于超时重试,可以设置
[
backup request
](
client.md#重试
)
,这类重试最多只有一次,放大程度降到了最低。brpc中的RPC超时是deadline,超过后RPC一定会结束,这让用户对服务的行为有更好的预判。在之前的一些实现中,RPC超时是单次超时
*
重试次数,在实践中容易误判。
3.
brpc server端的
[
max_concurrency选项
](
server.md#限制最大并发
)
控制了server的最大并发:当同时处理的请求数超过max_concurrency时,server会回复client错误,而不是继续积压。这一方面在服务开始的源头控制住了积压的请求数,尽量避免延生到用户缓冲或队列中,另一方面也让client尽快地去重试其他server,对集群来说是个更好的策略。
对于brpc的用户来说,要防止雪崩,主要注意两点:
1.
评估server的最大并发,设置合理的max_concurrency值。这个默认是不设的,也就是不限制。无论程序是同步还是异步,用户都可以通过
**最大qps \* 非拥塞时的延时**
(秒)来评估最大并发,原理见
[
little's law
](
https://en.wikipedia.org/wiki/Little
)
,这两个量都可以在brpc中的内置服务中看到。max_concurrency与最大并发相等或大一些就行了。
2.
注意考察重试发生时的行为,特别是在定制RetryPolicy时。如果你只是用默认的brpc重试,一般是安全的。但用户程序也常会自己做重试,比如通过一个Channel访问失败后,去访问另外一个Channel,这种情况下要想清楚重试发生时最差情况下请求量会放大几倍,服务是否可承受。
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment