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
28bcc04d
Commit
28bcc04d
authored
Sep 13, 2017
by
gejun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
more translations in client.md
parent
0b979456
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
16 additions
and
18 deletions
+16
-18
bthread.md
docs/cn/bthread.md
+11
-13
client.md
docs/cn/client.md
+0
-0
client.md
docs/en/client.md
+0
-0
http_client.cpp
example/http_c++/http_client.cpp
+5
-5
No files found.
docs/cn/bthread.md
View file @
28bcc04d
...
...
@@ -2,21 +2,22 @@ bthread([代码](http://icode.baidu.com/repo/baidu/opensource/baidu-rpc/files/ma
# Goals
-
用户可以延续同步的编程模式,能
很快地
建立bthread,可以用多种原语同步。
-
bthread所有接口可
以
在pthread中被调用并有合理的行为,使用bthread的代码可以在pthread中正常执行。
-
用户可以延续同步的编程模式,能
在数百纳秒内
建立bthread,可以用多种原语同步。
-
bthread所有接口可在pthread中被调用并有合理的行为,使用bthread的代码可以在pthread中正常执行。
-
能充分利用多核。
-
更好的cache locality,更低的延时。
-
better cache locality, supporting NUMA is a plus.
# NonGoals
-
提供pthread的兼容接口,只需链接即可使用。拒绝理由:bthread没有优先级,不适用于所有的场景,链接的方式容易使用户在不知情的情况下误用bthread,造成bug。
-
修改内核让pthread支持同核快速切换。拒绝理由:拥有大量pthread后,每个线程对资源的需求被稀释了,基于thread-local cache的代码效果都会很差,比如tcmalloc。而独立的bthread不会有这个问题,因为它最终还是被映射到了少量的pthread。
-
提供pthread的兼容接口,只需链接即可使用。
**拒绝理由**
: bthread没有优先级,不适用于所有的场景,链接的方式容易使用户在不知情的情况下误用bthread,造成bug。
-
覆盖各类可能阻塞的glibc函数和系统调用,让原本阻塞系统线程的函数改为阻塞bthread。
**拒绝理由**
: 1. bthread阻塞可能切换系统线程,依赖系统TLS的函数的行为未定义。2. 和阻塞pthread的函数混用时可能死锁。3. 这类hook函数本身的效率一般更差,因为往往还需要额外的系统调用,如epoll。但这类覆盖对N:1合作式线程库(fiber)有一定意义:虽然函数本身慢了,但若不覆盖会更慢(系统线程阻塞会导致所有fiber阻塞)。
-
修改内核让pthread支持同核快速切换。
**拒绝理由**
: 拥有大量pthread后,每个线程对资源的需求被稀释了,基于thread-local cache的代码效果会很差,比如tcmalloc。而独立的bthread不会有这个问题,因为它最终还是被映射到了少量的pthread。bthread相比pthread的性能提升很大一部分来自更集中的线程资源。另一个考量是可移植性,bthread更倾向于纯用户态代码。
# FAQ
##### Q:bthread是协程(coroutine)吗?
不是。我们常说的协程
是N:1线程库,即所有的协程都运行于一个系统线程中,计算能力和各种eventloop等价。由于不跨线程,协程之间的切换不需要系统调用,可以非常快(100ns-200ns),受cache同步的影响也小。但相应的代价是协程无法高效地利用多核,代码必须非阻塞,否则所有的协程都被卡住,对开发者要求苛刻。协程的这个特点使其适合写运行时间确定的IO服务器,典型如http server,在一些精心调试的场景中,可以达到非常高的吞吐。但百度内大部分在线服务的运行时间并不确定,一个缓慢的函数很容易卡住所有的协程。在这点上eventloop是类似的,一个回调卡住整个loop就卡住了,比如ub
**a**
server(注意那个a,不是ubserver)是公司内对异步框架的尝试,由多个并行的eventloop组成,真实表现糟糕:回调里打日志慢一些,访问下redis
,计算重一点,等待中的其他请求就会大量超时。所以这个框架从未流行起来。
不是。我们常说的协程
特指N:1线程库,即所有的协程运行于一个系统线程中,计算能力和各类eventloop库等价。由于不跨线程,协程之间的切换不需要系统调用,可以非常快(100ns-200ns),受cache一致性的影响也小。但代价是协程无法高效地利用多核,代码必须非阻塞,否则所有的协程都被卡住,对开发者要求苛刻。协程的这个特点使其适合写运行时间确定的IO服务器,典型如http server,在一些精心调试的场景中,可以达到非常高的吞吐。但百度内大部分在线服务的运行时间并不确定,且很多检索由几十人合作完成,一个缓慢的函数会卡住所有的协程。在这点上eventloop是类似的,一个回调卡住整个loop就卡住了,比如ub
**a**
server(注意那个a,不是ubserver)是百度对异步框架的尝试,由多个并行的eventloop组成,真实表现糟糕:回调里打日志慢一些,访问redis卡顿
,计算重一点,等待中的其他请求就会大量超时。所以这个框架从未流行起来。
bthread是一个M:N线程库,一个bthread被卡住不会影响其他bthread。关键技术两点:work stealing调度和butex,前者让bthread更快地被调度到更多的核心上,后者让bthread和pthread可以相互等待和唤醒。这两点协程都不需要。更多线程的知识查看
[
这里
](
threading_overview.md
)
。
...
...
@@ -26,7 +27,7 @@ bthread是一个M:N线程库,一个bthread被卡住不会影响其他bthread
##### Q:bthread和pthread worker如何对应?
pthread worker在任何时间只会运行一个bthread,当前bthread挂起时,pthread worker先尝试从本地
(runqueue)
弹出一个待运行的bthread,若没有,则随机偷另一个worker的待运行bthread,仍然没有才睡眠并会在有新的待运行bthread时被唤醒。
pthread worker在任何时间只会运行一个bthread,当前bthread挂起时,pthread worker先尝试从本地
runqueue
弹出一个待运行的bthread,若没有,则随机偷另一个worker的待运行bthread,仍然没有才睡眠并会在有新的待运行bthread时被唤醒。
##### Q:bthread中能调用阻塞的pthread或系统函数吗?
...
...
@@ -42,19 +43,16 @@ pthread worker在任何时间只会运行一个bthread,当前bthread挂起时
##### Q:若有大量的bthread调用了阻塞的pthread或系统函数,会影响RPC运行么?
会。比如有8个pthread worker,当有8个bthread都调用了系统usleep()后,处理网络收发的RPC代码就暂时无法运行了。只要阻塞时间不太长, 这一般
没什么影响
, 毕竟worker都用完了, 除了排队也没有什么好方法.
会。比如有8个pthread worker,当有8个bthread都调用了系统usleep()后,处理网络收发的RPC代码就暂时无法运行了。只要阻塞时间不太长, 这一般
**没什么影响**
, 毕竟worker都用完了, 除了排队也没有什么好方法.
在brpc中用户可以选择调大worker数来缓解问题, 在server端可设置
[
ServerOptions.num_threads
](
server.md#id-创建和设置Server-worker线程数
)
或
[
-bthread_concurrency
](
http://brpc.baidu.com:8765/flags/bthread_concurrency
)
, 在client端可设置
[
-bthread_concurrency
](
http://brpc.baidu.com:8765/flags/bthread_concurrency
)
.
那有没有完全规避的方法呢?
-
一个容易想到的方法是动态增加worker数. 但实际未必如意, 当大量的worker同时被阻塞时,
它们很可能在等待同一个资源(比如同一把锁), 增加worker可能只是增加了更多的等待者.
-
大部分RPC框架采取的方法是区分io线程和worker线程, io线程专门处理收发, worker线程调用用户逻辑,
即使worker线程全部阻塞也不会影响io线程. 但这个方法使得每个请求都要从io线程跳转至worker线程,
增加了一次上下文切换, 在机器繁忙时, 切换都有一定概率无法被及时调度, 会导致更多的延时长尾.
另一个问题是增加一层处理环节(io线程)并不能缓解拥塞, 如果worker线程全部卡住, 程序仍然会卡住,
-
那区分io线程和worker线程? io线程专门处理收发, worker线程调用用户逻辑, 即使worker线程全部阻塞也不会影响io线程. 但增加一层处理环节(io线程)并不能缓解拥塞, 如果worker线程全部卡住, 程序仍然会卡住,
只是卡的地方从socket缓冲转移到了io线程和worker线程之间的消息队列. 换句话说, 在worker卡住时,
还在运行的io线程做的可能是无用功. 事实上, 这正是上面提到的
"没什么影响"真正的含义
.
还在运行的io线程做的可能是无用功. 事实上, 这正是上面提到的
**没什么影响**
真正的含义. 另一个问题是每个请求都要从io线程跳转至worker线程, 增加了一次上下文切换, 在机器繁忙时, 切换都有一定概率无法被及时调度, 会导致更多的延时长尾
.
-
一个实际的解决方法是
[
限制最大并发
](
server.md#限制最大并发
)
, 只要同时被处理的请求数低于worker数, 自然可以规避掉"所有worker被阻塞"的情况.
-
另一个解决方法当被阻塞的worker超过阈值时(比如8个中的6个), 就不在原地调用用户代码了, 而是扔到一个独立的线程池中运行. 这样即使用户代码全部阻塞, 也总能保留几个worker处理rpc的收发. 不过目前bthread模式并没有这个机制, 但类似的机制在
[
打开pthread模式
](
server.md#pthread模式
)
时已经被实现了. 那像上面提到的, 这个机制是不是在用户代码都阻塞时也在做"无用功"呢? 可能是的. 但这个机制更多是为了规避在一些极端情况下的死锁, 比如所有的用户代码都lock在一个pthread mutex上, 并且这个mutex需要在某个RPC回调中unlock, 如果所有的worker都被阻塞, 那么就没有线程来处理RPC回调了, 整个程序就死锁了. 虽然绝大部分的RPC实现都有这个潜在问题, 但实际出现频率似乎很低, 只要养成不在锁内做RPC的好习惯, 这是完全可以规避的.
...
...
docs/cn/client.md
View file @
28bcc04d
This diff is collapsed.
Click to expand it.
docs/en/client.md
View file @
28bcc04d
This diff is collapsed.
Click to expand it.
example/http_c++/http_client.cpp
View file @
28bcc04d
...
...
@@ -13,11 +13,11 @@
// limitations under the License.
// - Access pb services via HTTP
// ./http_client http://
db-rpc-dev00.db01.baidu
.com:8765/EchoService/Echo -d '{"message":"hello"}'
// ./http_client http://
www.foo
.com:8765/EchoService/Echo -d '{"message":"hello"}'
// - Access builtin services
// ./http_client http://
db-rpc-dev00.db01.baidu
.com:8765/vars/rpc_server*
// - Access www.
baidu
.com
// ./http_client www.
baidu
.com
// ./http_client http://
www.foo
.com:8765/vars/rpc_server*
// - Access www.
foo
.com
// ./http_client www.
foo
.com
#include <gflags/gflags.h>
#include <butil/logging.h>
...
...
@@ -38,7 +38,7 @@ int main(int argc, char* argv[]) {
google
::
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
if
(
argc
!=
2
)
{
LOG
(
ERROR
)
<<
"Usage: ./http_client
\"
www.
baidu
.com
\"
"
;
LOG
(
ERROR
)
<<
"Usage: ./http_client
\"
www.
foo
.com
\"
"
;
return
-
1
;
}
char
*
url
=
argv
[
1
];
...
...
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