Commit 30466e19 authored by jiangrujie's avatar jiangrujie

Merge branch 'master' of https://github.com/brpc/brpc

parents bea97617 0bd2e97c
#ignore all files without extension
*
!*.*
!*/
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.log
*.pb.cc
*.pb.h
*.prof
/output
/test/output
#ignore hidden files
.*
*.swp
*.lib
docs/_site/
docs/.sass-cache/
docs/.jekyll-metadata
docs/_pdf
docs/.DS_Store
# Executables
*.exe
*.out
*.app
......@@ -32,7 +32,7 @@ Common doubts on RPC:
# What is ![brpc](docs/images/logo.png)?
A RPC framework used throughout [Baidu](http://ir.baidu.com/phoenix.zhtml?c=188488&p=irol-irhome), with **600,000+** instances and **500+** kinds of services, was called **baidu-rpc** inside Baidu. Only C++ implementation is opensourced right now.
A RPC framework used throughout [Baidu](http://ir.baidu.com/phoenix.zhtml?c=188488&p=irol-irhome), with **600,000+** instances(not counting clients) and **500+** kinds of services, called "**baidu-rpc**" inside Baidu. Only C++ implementation is opensourced right now.
You can use it for:
* Build a server that can talk in multiple protocols (**on same port**), or access all sorts of services
......@@ -42,7 +42,8 @@ You can use it for:
* hadoop_rpc(not opensourced yet)
* [rdma](https://en.wikipedia.org/wiki/Remote_direct_memory_access) support via [openucx](https://github.com/openucx/ucx) (will be opensourced soon)
* all sorts of protocols used in Baidu: baidu_std, [streaming_rpc](docs/cn/streaming_rpc.md), hulu_pbrpc, [sofa_pbrpc](https://github.com/baidu/sofa-pbrpc), nova_pbrpc, public_pbrpc, ubrpc, and nshead-based ones.
* Many protobuf-based protocols are accessible via HTTP+json, probably from another language.
* Access protobuf-based protocols with HTTP+json, probably from another language.
* Build distributed services using [RAFT consensus algorithm](https://raft.github.io) (will be opensourced at [braft](https://github.com/brpc/braft) soon)
* Rich processing patterns
* Services can handle requests [synchronously](docs/cn/server.md) or [asynchronously](docs/cn/server.md#异步service).
* Access service [synchronously](docs/cn/client.md#同步访问) or [asynchronously](docs/cn/client.md#异步访问), or even [semi-synchronously](docs/cn/client.md#半同步).
......@@ -139,6 +140,7 @@ Check out [benchmark](docs/cn/benchmark.md) for a comparison between brpc and ot
* [IOBuf](docs/cn/iobuf.md)
* [Streaming Log](docs/cn/streaming_log.md)
* [FlatMap](docs/cn/flatmap.md)
* [brpc外功修炼宝典](docs/cn/brpc_intro.pptx)(新人培训材料)
* RPC in depth
* [New Protocol](docs/cn/new_protocol.md)
* [atomic instructions](docs/cn/atomic_instructions.md)
......
......@@ -12,8 +12,8 @@
了解这些因素后可以更好的理解brpc中相关的设计。
1. 拥塞时A服务最大qps的跳变是因为线程个数是**硬限**,单个请求的处理时间很大程度上决定了最大qps。而brpc server端默认在bthread中处理请求,个数是软限,单个请求超时只是阻塞所在的bthread,并不会影响为新请求建立新的bthread。brpc也提供了完整的异步接口,让用户可以进一步提高io-bound服务的并发度,降低服务被打满的可能性。
2. brpc中[重试](client.md#重试)默认只在连接出错时发起,避免了流量放大,这是比较有效率的重试方式。如果需要基于超时重试,可以设置[backup request](client.md#backuprequest),这类重试最多只有一次,放大程度降到了最低。brpc中的RPC超时是deadline,超过后RPC一定会结束,这让用户对服务的行为有更好的预判。在之前的一些实现中,RPC超时是单次超时*重试次数,在实践中容易误判。
3. brpc server端的[max_concurrency选项](server.md#id-创建和设置Server-限制最大并发)控制了server的最大并发:当同时处理的请求数超过max_concurrency时,server会回复client错误,而不是继续积压。这一方面在服务开始的源头控制住了积压的请求数,尽量避免延生到用户缓冲或队列中,另一方面也让client尽快地去重试其他server,对集群来说是个更好的策略。
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的用户来说,要防止雪崩,主要注意两点:
......
“雪崩”指的是访问服务集群时绝大部分请求都超时,且在流量减少时仍无法恢复的现象。下面解释这个现象的来源。
当流量超出服务的最大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,这种情况下要想清楚重试发生时最差情况下请求量会放大几倍,服务是否可承受。
......@@ -23,28 +23,28 @@ com组(INF前身)在08年开发的RPC框架,在百度产品线广泛使用
- nova_pbrpc:网盟在12年基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,协议是nshead + user's protobuf。
- public_pbrpc:INF在13年初基于UB开发的RPC框架,用protobuf代替mcpack作为序列化方法,但协议与nova_pbrpc不同,大致是nshead + meta protobuf。meta protobuf中有个string字段包含user's protobuf。由于用户数据要序列化两次,这个RPC的性能很差,没有被推广开来。
我们以在网盟广泛使用的nova_pbrpc为UB的代表。测试时其代码为[r10500](https://svn.baidu.com/app/ecom/cm/trunk/pb-rpc)。早期的UB支持CPOOL和XPOOL,分别使用[select](http://linux.die.net/man/2/select)[leader-follower模型](http://kircher-schwanninger.de/michael/publications/lf.pdf),后来提供了EPOOL,使用[epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)处理多路连接。鉴于产品线大都是用EPOOL模型,我们的UB配置也使用EPOOL。UB只支持[连接池](client.md#连接方式),结果用“**ubrpc_mc**"指代(mc代表"multiple
我们以在网盟广泛使用的nova_pbrpc为UB的代表。测试时其代码为r10500。早期的UB支持CPOOL和XPOOL,分别使用[select](http://linux.die.net/man/2/select)[leader-follower模型](http://kircher-schwanninger.de/michael/publications/lf.pdf),后来提供了EPOOL,使用[epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)处理多路连接。鉴于产品线大都是用EPOOL模型,我们的UB配置也使用EPOOL。UB只支持[连接池](client.md#连接方式),结果用“**ubrpc_mc**"指代(mc代表"multiple
connection")。虽然这个名称不太准确(见上文对ubrpc的介绍),但在本文的语境下,请默认ubrpc = UB。
## hulu-pbrpc
INF在13年基于saber(kylin变种)和protobuf实现的RPC框架,hulu在实现上有较多问题:未封装的引用计数,混乱的生命周期,充斥的race conditions和ABA problems,运行质量不可靠,比如短链接从来没有能正常运行过。之后迅速被brpc代替,测试时其代码为<https://svn.baidu.com/public/tags/hulu/pbrpc/pbrpc_2-0-15-27959_PD_BL>。hulu-pbrpc只支持单连接,结果用“**hulu-pbrpc**"指代。
INF在13年基于saber(kylin变种)和protobuf实现的RPC框架,hulu在实现上有较多问题:未封装的引用计数,混乱的生命周期,充斥的race conditions和ABA problems,运行质量不可靠,比如短链接从来没有能正常运行过。之后迅速被brpc代替,测试时其代码为`pbrpc_2-0-15-27959_PD_BL`。hulu-pbrpc只支持单连接,结果用“**hulu-pbrpc**"指代。
## brpc
INF在2014年底开发至今的rpc产品,支持百度内所有协议(不限于protobuf),并第一次统一了百度内主要分布式系统的RPC框架。测试时其代码为[r31906](https://svn.baidu.com/public/tags/baidu-rpc/baidu-rpc_1-0-199-31906_PD_BL)(开发请使用@ci-base保持更新)。brpc既支持单连接也支持连接池,前者的结果用"**baidu-rpc**"指代,后者用“**baidu-rpc_mc**"指代。
INF在2014年底开发至今的rpc产品,支持百度内所有协议(不限于protobuf),并第一次统一了百度内主要分布式系统的RPC框架。测试时代码为r31906(开发请使用@ci-base保持更新)。brpc既支持单连接也支持连接池,前者的结果用"**baidu-rpc**"指代,后者用“**baidu-rpc_mc**"指代。
## sofa-pbrpc
大搜在13年基于boost::asio和protobuf实现的RPC框架,有多个版本,咨询相关同学后,确认ps/opensource下的和github上的较新,且会定期同步。故测试使用使用ps/opensource下的版本。测试时其代码为<https://svn.baidu.com/ps/opensource/branches/sofa-pbrpc/sofa-pbrpc_1-0-2_BRANCH/>。sofa-pbrpc只支持单连接,结果用“**sofa-pbrpc**”指代。
大搜在13年基于boost::asio和protobuf实现的RPC框架,有多个版本,咨询相关同学后,确认ps/opensource下的和github上的较新,且会定期同步。故测试使用使用ps/opensource下的版本。测试时其代码为`sofa-pbrpc_1-0-2_BRANCH`。sofa-pbrpc只支持单连接,结果用“**sofa-pbrpc**”指代。
## apache thrift
thrift是由facebook最早在07年开发的序列化方法和rpc框架,包含独特的序列化格式和IDL,支持很多编程语言。开源后改名[apache thrift](https://thrift.apache.org/),fb自己有一个[fbthrift分支](https://github.com/facebook/fbthrift),我们使用的是apache thrift。测试时其代码为[0.9](https://svn.baidu.com/third-64/tags/thrift/thrift_0-9-1-400_PD_BL)。thrift的缺点是:代码看似分层清晰,client和server选择很多,但没有一个足够通用,每个server实现都只能解决很小一块场景,每个client都线程不安全,实际使用很麻烦。由于thrift没有线程安全的client,所以每个线程中都得建立一个client,使用独立的连接。在测试中thrift其实是占了其他实现的便宜:它的client不需要处理多线程问题。thrift的结果用"**thrift_mc**"指代。
thrift是由facebook最早在07年开发的序列化方法和rpc框架,包含独特的序列化格式和IDL,支持很多编程语言。开源后改名[apache thrift](https://thrift.apache.org/),fb自己有一个[fbthrift分支](https://github.com/facebook/fbthrift),我们使用的是apache thrift。测试时其代码为`thrift_0-9-1-400_PD_BL`。thrift的缺点是:代码看似分层清晰,client和server选择很多,但没有一个足够通用,每个server实现都只能解决很小一块场景,每个client都线程不安全,实际使用很麻烦。由于thrift没有线程安全的client,所以每个线程中都得建立一个client,使用独立的连接。在测试中thrift其实是占了其他实现的便宜:它的client不需要处理多线程问题。thrift的结果用"**thrift_mc**"指代。
## grpc
由google开发的rpc框架,使用http/2和protobuf 3.0,测试时其代码为<https://github.com/grpc/grpc/tree/release-0_11>。grpc并不是stubby,定位更像是为了推广http/2和protobuf 3.0,但鉴于很多人对它的表现很感兴趣,我们也(很麻烦地)把它加了进来。grpc的结果用"**grpc**"指代。
由google开发的rpc框架,使用http/2和protobuf 3.0,测试时其代码为<https://github.com/grpc/grpc/tree/release-0_11>。grpc并不是stubby,定位更像是为了推广http/2和protobuf 3.0,但鉴于很多人对它的表现很感兴趣,我们也(很麻烦地)把它加了进来。grpc的结果用"**grpc**"指代。
# 测试方法
......@@ -99,16 +99,15 @@ server一样的[内置服务](builtin_service.md)。
![img](../images/qps_vs_reqsize.png)
以_mc结尾的曲线代表client和server保持多个连接(线程数个),在本测试中会有更好的表现。
**分析**
* 以_mc结尾的曲线代表client和server保持多个连接(线程数个),在本测试中会有更好的表现。
* brpc:当请求包小于16KB时,单连接下的吞吐超过了多连接的ubrpc_mc和thrift_mc,随着请求包变大,内核对单个连接的写入速度成为瓶颈。而多连接下的brpc则一骑绝尘,达到了测试中最高的2.3GB/s。注意:虽然使用连接池的brpc在发送大包时吞吐更高,但也会耗费更多的CPU(UB和thrift也是这样)。下图中的单连接brpc已经可以提供800多兆的吞吐,足以打满万兆网卡,而使用的CPU可能只有多链接下的1/2
* (写出过程是[wait-free的](io.md#发消息)),真实系统中请优先使用单链接。
* brpc:当请求包小于16KB时,单连接下的吞吐超过了多连接的ubrpc_mc和thrift_mc,随着请求包变大,内核对单个连接的写入速度成为瓶颈。而多连接下的brpc则达到了测试中最高的2.3GB/s。注意:虽然使用连接池的brpc在发送大包时吞吐更高,但也会耗费更多的CPU(UB和thrift也是这样)。下图中的单连接brpc已经可以提供800多兆的吞吐,足以打满万兆网卡,而使用的CPU可能只有多链接下的1/2(写出过程是[wait-free的](io.md#发消息)),真实系统中请优先使用单链接。
* thrift: 初期明显低于brpc,随着包变大超过了单连接的brpc。
* UB:
* 和thrift类似的曲线,但平均要低4-5万QPS,在32K包时超过了单连接的brpc。整个过程中QPS几乎没变过。
* UB:和thrift类似的曲线,但平均要低4-5万QPS,在32K包时超过了单连接的brpc。整个过程中QPS几乎没变过。
* grpc: 初期几乎与UB平行,但低1万左右,超过8K开始下降。
* hulu-pbrpc和sofa-pbrpc:
* 512字节前高于UB和grpc,但之后就急转直下,相继垫底。这个趋势是写不够并发的迹象。
* hulu-pbrpc和sofa-pbrpc: 512字节前高于UB和grpc,但之后就急转直下,相继垫底。这个趋势是写不够并发的迹象。
## 同机单client→单server在不同线程数下的QPS(越高越好)
......
bthread([代码](https://github.com/brpc/brpc/tree/master/src/bthread))是brpc使用的M:N线程库,目的是在提高程序的并发度的同时,降低编码难度,并在核数日益增多的CPU上提供更好的scalability和cache locality。”M:N“是指M个bthread会映射至N个pthread,一般M远大于N。由于linux当下的pthread实现([NPTL](http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library))是1:1的,M个bthread也相当于映射至N个[LWP](http://en.wikipedia.org/wiki/Light-weight_process)。bthread的前身是[DP](http://wiki.babel.baidu.com/twiki/bin/view/Com/Ecom/DistributedProcess)中的fiber,一个N:1的合作式线程库,等价于event-loop库,但写的是同步代码。
[bthread](https://github.com/brpc/brpc/tree/master/src/bthread)是brpc使用的M:N线程库,目的是在提高程序的并发度的同时,降低编码难度,并在核数日益增多的CPU上提供更好的scalability和cache locality。”M:N“是指M个bthread会映射至N个pthread,一般M远大于N。由于linux当下的pthread实现([NPTL](http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library))是1:1的,M个bthread也相当于映射至N个[LWP](http://en.wikipedia.org/wiki/Light-weight_process)。bthread的前身是[DP](http://wiki.babel.baidu.com/twiki/bin/view/Com/Ecom/DistributedProcess)中的fiber,一个N:1的合作式线程库,等价于event-loop库,但写的是同步代码。
# Goals
......@@ -44,7 +44,7 @@ pthread worker在任何时间只会运行一个bthread,当前bthread挂起时
##### Q:若有大量的bthread调用了阻塞的pthread或系统函数,会影响RPC运行么?
会。比如有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).
在brpc中用户可以选择调大worker数来缓解问题, 在server端可设置[ServerOptions.num_threads](server.md#worker线程数)[-bthread_concurrency](http://brpc.baidu.com:8765/flags/bthread_concurrency), 在client端可设置[-bthread_concurrency](http://brpc.baidu.com:8765/flags/bthread_concurrency).
那有没有完全规避的方法呢?
......
# 什么是内置服务?
内置服务以多种形式展现服务器内部状态,提高你开发和调试服务的效率。brpc通过HTTP协议提供内置服务,可通过浏览器或curl访问,服务器会根据User-Agent返回纯文本或html,你也可以添加?console=1要求返回纯文本。我们在自己的开发机上启动了[一个长期运行的例子](http://brpc.baidu.com:8765/),你可以点击后随便看看。服务端口只有在8000-8999内才能被笔记本访问到,对于范围之外的端口可以使用[rpc_view](rpc_view.md)或在命令行中使用curl <SERVER-URL>
内置服务以多种形式展现服务器内部状态,提高你开发和调试服务的效率。brpc通过HTTP协议提供内置服务,可通过浏览器或curl访问,服务器会根据User-Agent返回纯文本或html,你也可以添加?console=1要求返回纯文本。我们在自己的开发机上启动了[一个长期运行的例子](http://brpc.baidu.com:8765/),你可以点击后随便看看。对于服务端口被限的情况(比如百度内在8000-8999内才能被笔记本访问到),可以使用[rpc_view](rpc_view.md)转发或在命令行中使用curl \<SERVER-URL\>
从浏览器访问:
......
# 1.什么是bvar?
[public/bvar](https://github.com/brpc/brpc/blob/master/src/)是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值,它利用了thread local存储避免了cache bouncing,相比UbMonitor几乎不会给程序增加性能开销,也快于竞争频繁的原子操作。brpc集成了bvar,[/vars](http://brpc.baidu.com:8765/vars)可查看所有曝光的bvar,[/vars/VARNAME](http://brpc.baidu.com:8765/vars/rpc_socket_count)可查阅某个bvar,在rpc中的具体使用方法请查看[这里](vars.md)。brpc大量使用了bvar提供统计数值,当你需要在多线程环境中计数并展现时,应该第一时间想到bvar。但bvar不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读得合并所有写过的线程中的数据,而不可避免地变慢了。当你读写都很频繁并得基于数值做一些逻辑判断时,你不应该用bvar。
[bvar](https://github.com/brpc/brpc/blob/master/src/bvar)是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值,它利用了thread local存储避免了cache bouncing,相比UbMonitor几乎不会给程序增加性能开销,也快于竞争频繁的原子操作。brpc集成了bvar,[/vars](http://brpc.baidu.com:8765/vars)可查看所有曝光的bvar,[/vars/VARNAME](http://brpc.baidu.com:8765/vars/rpc_socket_count)可查阅某个bvar,在rpc中的具体使用方法请查看[这里](vars.md)。brpc大量使用了bvar提供统计数值,当你需要在多线程环境中计数并展现时,应该第一时间想到bvar。但bvar不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读得合并所有写过的线程中的数据,而不可避免地变慢了。当你读写都很频繁并得基于数值做一些逻辑判断时,你不应该用bvar。
# 2.什么是cache bouncing?
......
......@@ -36,7 +36,7 @@ fm-sync算法: 替换前总耗时6:16:37, 替换后总耗时5:21:00, 提升14.6%
| 替换后 | 304.878 | 2571.34 | 0 |
| 缩短 | 53.7% | 63.9% | |
##结论
## 结论
单个rpc-call以及单次请求所有rpc-call的提升非常显著,提升都在50%以上,总任务的耗时除了ftrl-sync-no-shuffle提升不明显外,其余三个算法都有15%左右的提升,现在算法的瓶颈在于对计算逻辑,所以相对单个的rpc的提升没有那么多。
......
......@@ -21,6 +21,7 @@ brpc改造后的connecter收益明显,可以用较少的机器提供更优质
# 不同配置机器qps和延时的比较
qps固定为6500,观察延时。
| 机器名称 | 略 | 略 |
| ----- | ---------------------------------------- | ---------------------------------------- |
| cpu | 24 Intel(R) Xeon(R) CPU E5645 @ 2.40GHz | 24 Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz |
......@@ -30,7 +31,6 @@ qps固定为6500,观察延时。
有此可见:
* ubrpc在不同配置下性能表现差异大,在配置较低的机器下表现较差。
* brpc表现的比ubrpc好,在较低配置的机器上也能有好的表现,因机器不同带来的差异不大。
# 相同配置机器idle分布的比较
......
......@@ -510,7 +510,7 @@ Channel的默认协议是标准协议,可通过设置ChannelOptions.protocol
- PROTOCOL_NOVA_PBRPC 或 ”nova_pbrpc“,网盟的协议,默认为连接池。
- PROTOCOL_HTTP 或 ”http", http协议,默认为连接池(Keep-Alive)。具体方法见[访问HTTP服务](http_client.md)
- PROTOCOL_SOFA_PBRPC 或 "sofa_pbrpc",sofa-pbrpc的协议,默认为单连接。
- PROTOCOL_PUBLIC_PBRPC 或 "public_pbrpc",public/pbrpc的协议,默认为连接池。
- PROTOCOL_PUBLIC_PBRPC 或 "public_pbrpc",public_pbrpc的协议,默认为连接池。
- PROTOCOL_UBRPC_COMPACK 或 "ubrpc_compack",public/ubrpc的协议,使用compack打包,默认为连接池。具体方法见[ubrpc (by protobuf)](ub_client.md)。相关的还有PROTOCOL_UBRPC_MCPACK2或ubrpc_mcpack2,使用mcpack2打包。
- PROTOCOL_NSHEAD_CLIENT 或 "nshead_client",这是发送brpc-ub中所有UBXXXRequest需要的协议,默认为连接池。具体方法见[访问ub](ub_client.md)
- PROTOCOL_NSHEAD 或 "nshead",这是brpc中发送NsheadMessage需要的协议,默认为连接池。注意发送NsheadMessage的效果等同于发送brpc-ub中的UBRawBufferRequest,但更加方便一点。具体方法见[nshead+blob](ub_client.md#nshead-blob)
......@@ -714,13 +714,13 @@ struct ChannelOptions {
### Q: Invalid address=`bns://group.user-persona.dumi.nj03'是什么意思
```
FATAL 04-07 20:00:03 7778 public/brpc/src/brpc/channel.cpp:123] Invalid address=`bns://group.user-persona.dumi.nj03'. You should use Init(naming_service_name, load_balancer_name, options) to access multiple servers.
FATAL 04-07 20:00:03 7778 src/brpc/channel.cpp:123] Invalid address=`bns://group.user-persona.dumi.nj03'. You should use Init(naming_service_name, load_balancer_name, options) to access multiple servers.
```
访问bns要使用三个参数的Init,它第二个参数是load_balancer_name,而你这里用的是两个参数的Init,框架当你是访问单点,就会报这个错。
### Q: 两个产品线都使用protobuf,为什么不能互相访问
协议 !=protobuf。protobuf负责打包,协议负责定字段。打包格式相同不意味着字段可以互通。协议中可能会包含多个protobuf包,以及额外的长度、校验码、magic number等等。协议的互通是通过在RPC框架内转化为统一的编程接口完成的,而不是在protobuf层面。从广义上来说,protobuf也可以作为打包框架使用,生成其他序列化格式的包,像[idl<=>protobuf](idl_protobuf.md)就是通过protobuf生成了解析idl的代码。
协议 !=protobuf。protobuf负责打包,协议负责定字段。打包格式相同不意味着字段可以互通。协议中可能会包含多个protobuf包,以及额外的长度、校验码、magic number等等。协议的互通是通过在RPC框架内转化为统一的编程接口完成的,而不是在protobuf层面。从广义上来说,protobuf也可以作为打包框架使用,生成其他序列化格式的包,像[idl<=>protobuf](mcpack2pb.md)就是通过protobuf生成了解析idl的代码。
### Q: 为什么C++ client/server 能够互相通信, 和其他语言的client/server 通信会报序列化失败的错误
......@@ -734,7 +734,7 @@ FATAL 04-07 20:00:03 7778 public/brpc/src/brpc/channel.cpp:123] Invalid address=
1. 创建一个[bthread_id](https://github.com/brpc/brpc/blob/master/src/bthread/id.h)作为本次RPC的correlation_id。
2. 根据Channel的创建方式,从进程级的[SocketMap](https://github.com/brpc/brpc/blob/master/src/brpc/socket_map.h)中或从[LoadBalancer](https://github.com/brpc/brpc/blob/master/src/brpc/load_balancer.h)中选择一台下游server作为本次RPC发送的目的地。
3. 根据连接方式(单连接、连接池、短连接),选择一个[Socket](https://svn.baidu.com/public/trunk/baidu-rpc/src/baidu/rpc/socket.h)
3. 根据连接方式(单连接、连接池、短连接),选择一个[Socket](https://github.com/brpc/brpc/blob/master/src/brpc/socket.h)
4. 如果开启验证且当前Socket没有被验证过时,第一个请求进入验证分支,其余请求会阻塞直到第一个包含认证信息的请求写入Socket。这是因为server端只对第一个请求进行验证。
5. 根据Channel的协议,选择对应的序列化函数把request序列化至[IOBuf](https://github.com/brpc/brpc/blob/master/src/butil/iobuf.h)
6. 如果配置了超时,设置定时器。从这个点开始要避免使用Controller对象,因为在设定定时器后->有可能触发超时机制->调用到用户的异步回调->用户在回调中析构Controller。
......
......@@ -15,7 +15,7 @@ server端Controller的SetFailed()常由用户在服务回调中调用。当处
brpc使用的所有ErrorCode都定义在[errno.proto](https://github.com/brpc/brpc/blob/master/src/brpc/errno.proto)中,*SYS_*开头的来自linux系统,与/usr/include/errno.h中定义的精确一致,定义在proto中是为了跨语言。其余的是brpc自有的。
[berror(error_code)](https://github.com/brpc/brpc/blob/master/src/butil/errno.h)可获得error_code的描述,berror()可获得[system errno](http://www.cplusplus.com/reference/cerrno/errno/)的描述。**ErrorText() != berror(****ErrorCode())**,ErrorText()会包含更具体的错误信息。brpc默认包含berror,你可以直接使用。
[berror(error_code)](https://github.com/brpc/brpc/blob/master/src/butil/errno.h)可获得error_code的描述,berror()可获得[system errno](http://www.cplusplus.com/reference/cerrno/errno/)的描述。**ErrorText() != berror(ErrorCode())**,ErrorText()会包含更具体的错误信息。brpc默认包含berror,你可以直接使用。
brpc中常见错误的打印内容列表如下:
......
......@@ -47,14 +47,14 @@ WARNING: 12-26 10:01:25: * 0 [src/brpc/input_messenger.cpp:132][4294969345] Au
左上角的两个选择框作用分别是:
- View:当前正在看的profile。选择<new profile>表示新建一个。新建完毕后,View选择框中会出现新profile,URL也会被修改为对应的地址。这意味着你可以通过粘贴URL分享结果,点击链接的人将看到和你一模一样的结果,而不是重做profiling的结果。你可以在框中选择之前的profile查看。历史profiie保留最近的32个,可通过[--max_profiles_kept](http://brpc.baidu.com:8765/flags/max_profiles_kept)调整。
- View:当前正在看的profile。选择\<new profile\>表示新建一个。新建完毕后,View选择框中会出现新profile,URL也会被修改为对应的地址。这意味着你可以通过粘贴URL分享结果,点击链接的人将看到和你一模一样的结果,而不是重做profiling的结果。你可以在框中选择之前的profile查看。历史profiie保留最近的32个,可通过[--max_profiles_kept](http://brpc.baidu.com:8765/flags/max_profiles_kept)调整。
- Diff:和选择的profile做对比。<none>表示什么都不选。如果你选择了之前的某个profile,那么将看到View框中的profile相比Diff框中profile的变化量。
下图演示了勾选Diff和Text的效果。
![img](../images/heap_profiler_3.gif)
你也可以使用pprof脚本(public/brpc/tools/pprof)在命令行中查看文本格式结果:
你也可以使用pprof脚本(tools/pprof)在命令行中查看文本格式结果:
```
$ tools/pprof --text db-rpc-dev00.db01:8765/pprof/heap
......
......@@ -83,7 +83,7 @@ URL的一般形式如下图:
确实,在简单使用场景下,这两者有所重复,但在复杂场景中,两者差别很大,比如:
- 访问挂在bns下的多个http server。此时Channel.Init传入的是bns节点名称,对uri()的赋值则是包含Host的完整URL(比如"www.foo.com/index.html?name=value"),BNS下所有的http server都会看到"Host: [www.foo.com](http://www.foo.com/)";uri()也可以是只包含路径的URL,比如"/index.html?name=value",框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
- 访问挂在bns下的多个http server。此时Channel.Init传入的是bns节点名称,对uri()的赋值则是包含Host的完整URL(比如"www.foo.com/index.html?name=value"),BNS下所有的http server都会看到"Host: www.foo.com";uri()也可以是只包含路径的URL,比如"/index.html?name=value",框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
- 通过http proxy访问目标server。此时Channel.Init传入的是proxy server的地址,但uri()填入的是目标server的URL。
# 常见设置
......
ub是百度内广泛使用的老RPC框架,在迁移ub服务时不可避免地需要[访问ub-server](ub_client.md)或被ub-client访问。ub使用的协议种类很多,但都以nshead作为二进制包的头部,这类服务在brpc中统称为**“nshead service”**
nshead后大都使用mcpack/compack作为序列化格式,注意这不是“协议”。"协议"除了序列化格式,还涉及到各种特殊字段的定义,一种序列化格式可能会衍生出很多协议。ub没有定义标准协议,所以即使都使用mcpack/compack,产品线的通信协议也是五花八门,无法互通。鉴于此,我们提供了一套接口,让用户能够灵活的处理自己产品线的协议,同时享受brpc提供的builtin services等一系列框架福利。
nshead后大都使用mcpack/compack作为序列化格式,注意这不是“协议”。"协议"除了序列化格式,还涉及到各种特殊字段的定义,一种序列化格式可能会衍生出很多协议。ub没有定义标准协议,所以即使都使用mcpackcompack,产品线的通信协议也是五花八门,无法互通。鉴于此,我们提供了一套接口,让用户能够灵活的处理自己产品线的协议,同时享受brpc提供的builtin services等一系列框架福利。
# 使用ubrpc的服务
......@@ -13,7 +13,7 @@ ubrpc协议的基本形式是nshead+compack或mcpack2,但compack或mcpack2中
使用脚本[idl2proto](https://github.com/brpc/brpc/blob/master/tools/idl2proto)把idl文件自动转化为proto文件,下面是转化后的proto文件。
```protobuf
// Converted from echo.idl by public/mcpack2pb/idl2proto
// Converted from echo.idl by brpc/tools/idl2proto
import "idl_options.proto";
option (idl_support) = true;
option cc_generic_services = true;
......@@ -60,15 +60,12 @@ service EchoService {
};
```
## 设置protoc和mcpack2pb的参数
## 以插件方式运行protoc
注意--mcpack_out要和--cpp_out一致,你可以先设成--mcpack_out=.,执行comake2或bcloud后看错误信息中的--cpp_out的值,再把--mcpack_out设成一样的
BRPC_PATH代表brpc产出的路径(包含bin include等目录),PROTOBUF_INCLUDE_PATH代表protobuf的包含路径。注意--mcpack_out要和--cpp_out一致
```pyton
PROTOC(ENV.WorkRoot()+"/third-64/protobuf/bin/protoc")
PROTOFLAGS("--plugin=protoc-gen-mcpack=" + ENV.WorkRoot() + "/public/mcpack2pb/protoc-gen-mcpack --mcpack_out=.")
PROTOFLAGS('--proto_path=' + ENV.WorkRoot() + '/public/mcpack2pb/')
PROTOFLAGS('--proto_path=' + ENV.WorkRoot() + '/third-64/protobuf/include/')
```shell
protoc --plugin=protoc-gen-mcpack=$BRPC_PATH/bin/protoc-gen-mcpack --cpp_out=. --mcpack_out=. --proto_path=$BRPC_PATH/include --proto_path=PROTOBUF_INCLUDE_PATH
```
## 实现生成的Service基类
......@@ -172,7 +169,7 @@ idl是mcpack/compack的前端,用户只要在idl文件中描述schema,就可
> **这个服务在继续使用mcpack/compack作为序列化格式,相比protobuf占用成倍的带宽和打包时间。**
为了解决这个问题,我们提供了[mcpack2pb](idl_protobuf.md),允许把protobuf作为mcpack/compack的前端。你只要写一份proto文件,就可以同时解析mcpack/compack和protobuf格式的请求。使用这个方法,使用idl描述的服务的可以平滑地改造为使用proto文件描述,而不用修改上游client(仍然使用mcpack/compack)。你产品线的服务可以逐个地从mcpack/compack/idl切换为protobuf,从而享受到性能提升,带宽节省,全新开发体验等好处。你可以自行在NsheadService使用public/mcpack2pb,也可以联系我们,提供更高质量的协议支持。
为了解决这个问题,我们提供了[mcpack2pb](mcpack2pb.md),允许把protobuf作为mcpack/compack的前端。你只要写一份proto文件,就可以同时解析mcpack/compack和protobuf格式的请求。使用这个方法,使用idl描述的服务的可以平滑地改造为使用proto文件描述,而不用修改上游client(仍然使用mcpack/compack)。你产品线的服务可以逐个地从mcpack/compack/idl切换为protobuf,从而享受到性能提升,带宽节省,全新开发体验等好处。你可以自行在NsheadService使用src/mcpack2pb,也可以联系我们,提供更高质量的协议支持。
# 使用nshead+protobuf的服务
......@@ -231,4 +228,3 @@ public:
                                          NsheadMessage* nshead_res) const = 0;
};
```
......@@ -3,7 +3,7 @@ rpc_press无需写代码就压测各种rpc server,目前支持的协议有:
- 标准协议
- hulu-pbrpc协议
- sofa-pbrpc协议
- public/pbrpc协议(老版pbrpc协议)
- public_pbrpc协议(老版pbrpc协议)
- nova-pbrpc协议
# 获取工具
......@@ -73,7 +73,7 @@ dummy_server启动时会在终端打印日志,一般按住ctrl点击那个链
![img](../images/rpc_press_2.png)
你可以通过-dummy_port参数修改dummy_server的端口,但请确保端口在8000到8999范围内,否则总是无法在浏览器中访问。
你可以通过-dummy_port参数修改dummy_server的端口,请确保端口可以在浏览器中访问。
如果你无法打开浏览器,命令行中也会定期打印信息:
......
......@@ -51,7 +51,7 @@ brpc提供了[SampleIterator](https://github.com/brpc/brpc/blob/master/src/brpc/
brpc::SampleIterator it("./rpc_data/rpc_dump/echo_server");
for (SampleRequest* req = it->Next(); req != NULL; req = it->Next()) {
...
// req->meta的类型是brpc::RpcDumpMeta,定义在protocol/brpc/rpc_dump.proto
// req->meta的类型是brpc::RpcDumpMeta,定义在src/brpc/rpc_dump.proto
// req->request的类型是butil::IOBuf,对应格式说明中的"serialized request"
// 使用结束后必须delete req。
}
......
rpc_view可以查看端口不在8000-8999的server的内置服务。之前如果一个服务的端口不在8000-8999,我们只能在命令行下使用curl查看它的内置服务,没有历史趋势和动态曲线,也无法点击链接,排查问题不方便。rpc_view是一个特殊的http proxy:把对它的所有访问都转为对目标server的访问。只要把rpc_view启动在8000-8999端口,我们就能通过它看到原本不能直接看到的server了。
rpc_view可以转发端口被限的server的内置服务。像百度内如果一个服务的端口不在8000-8999,就只能在命令行下使用curl查看它的内置服务,没有历史趋势和动态曲线,也无法点击链接,排查问题不方便。rpc_view是一个特殊的http proxy:把对它的所有访问都转为对目标server的访问。只要把rpc_view的端口能在浏览器中被访问,我们就能通过它看到原本不能直接看到的server了。
# 获取工具
......
......@@ -272,7 +272,7 @@ $ curl -d '{"message":"hello"}' http://brpc.baidu.com:8765/EchoService/Echo
## json<=>pb
json通过名字与pb字段一一对应,结构层次也应匹配。json中一定要包含pb的required字段,否则转化会失败,对应请求会被拒绝。json中可以包含pb中没有定义的字段,但不会作为pb的unknown字段被继续传递。转化规则详见[json <=> protobuf](idl_protobuf.md)
json通过名字与pb字段一一对应,结构层次也应匹配。json中一定要包含pb的required字段,否则转化会失败,对应请求会被拒绝。json中可以包含pb中没有定义的字段,但不会作为pb的unknown字段被继续传递。转化规则详见[json <=> protobuf](json2pb.md)
r34532后增加选项-pb_enum_as_number,开启后pb中的enum会转化为它的数值而不是名字,比如在`enum MyEnum { Foo = 1; Bar = 2; };`中不开启此选项时MyEnum类型的字段会转化为"Foo"或"Bar",开启后为1或2。此选项同时影响client发出的请求和server返回的回复。由于转化为名字相比数值有更好的前后兼容性,此选项只应用于兼容无法处理enum为名字的场景。
......@@ -314,7 +314,7 @@ server端会自动尝试其支持的协议,无需用户指定。`cntl->protoco
options.nshead_service = new brpc::policy::NovaServiceAdaptor;
```
- public/pbrpc协议,显示为"public_pbrpc" (r32206前显示为"nshead_server"),默认不启用,开启方式:
- public_pbrpc协议,显示为"public_pbrpc" (r32206前显示为"nshead_server"),默认不启用,开启方式:
```c++
#include <brpc/policy/public_pbrpc_protocol.h>
......
......@@ -18,7 +18,7 @@
## 多线程reactor
[kylin](http://websvn.work.baidu.com/repos/public/list/trunk/kylin/?revision=HEAD), [boost::asio](http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio.html)为典型。一般由一个或多个线程分别运行event dispatcher,待事件发生后把event handler交给一个worker thread执行。由于百度内以SMP机器为主,这种可以利用多核的结构更加合适,多线程交换信息的方式也比多进程更多更简单,所以往往能让多核的负载更加均匀。不过由于cache一致性的限制,多线程reactor模型并不能获得线性于核数的扩展性,在特定的场景中,粗糙的多线程reactor实现跑在24核上甚至没有精致的单线程reactor实现跑在1个核上快。reactor有proactor变种,即用异步IO代替event dispatcher,boost::asio[在windows下](http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx)就是proactor。
kylin, [boost::asio](http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio.html)为典型。一般由一个或多个线程分别运行event dispatcher,待事件发生后把event handler交给一个worker thread执行。由于百度内以SMP机器为主,这种可以利用多核的结构更加合适,多线程交换信息的方式也比多进程更多更简单,所以往往能让多核的负载更加均匀。不过由于cache一致性的限制,多线程reactor模型并不能获得线性于核数的扩展性,在特定的场景中,粗糙的多线程reactor实现跑在24核上甚至没有精致的单线程reactor实现跑在1个核上快。reactor有proactor变种,即用异步IO代替event dispatcher,boost::asio[在windows下](http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx)就是proactor。
多线程reactor的运行方式如下:
......
......@@ -9,7 +9,7 @@ r31687后,brpc支持通过protobuf访问ubrpc,不需要baidu-rpc-ub,也不
1.[idl2proto](https://github.com/brpc/brpc/blob/master/tools/idl2proto)把idl文件转化为proto文件,老版本idl2proto不会转化idl中的service,需要手动转化。
```protobuf
// Converted from echo.idl by public/mcpack2pb/idl2proto
// Converted from echo.idl by brpc/tools/idl2proto
import "idl_options.proto";
option (idl_support) = true;
option cc_generic_services = true;
......@@ -59,13 +59,10 @@ r31687后,brpc支持通过protobuf访问ubrpc,不需要baidu-rpc-ub,也不
2. 插入如下片段以使用代码生成插件。
注意--mcpack_out要和--cpp_out一致,你可以先设成--mcpack_out=.,执行comake2bcloud后看错误信息中的--cpp_out的值,再把--mcpack_out设成一样的
BRPC_PATH代表brpc产出的路径(包含bin include等目录),PROTOBUF_INCLUDE_PATH代表protobuf的包含路径。注意--mcpack_out要和--cpp_out一致
```python
PROTOC(ENV.WorkRoot()+"/third-64/protobuf/bin/protoc")
PROTOFLAGS("--plugin=protoc-gen-mcpack=" + ENV.WorkRoot() + "/public/mcpack2pb/protoc-gen-mcpack --mcpack_out=.")
PROTOFLAGS('--proto_path=' + ENV.WorkRoot() + 'public/mcpack2pb/')
PROTOFLAGS('--proto_path=' + ENV.WorkRoot() + 'third-64/protobuf/include/')
```shell
protoc --plugin=protoc-gen-mcpack=$BRPC_PATH/bin/protoc-gen-mcpack --cpp_out=. --mcpack_out=. --proto_path=$BRPC_PATH/include --proto_path=PROTOBUF_INCLUDE_PATH
```
3. channel发起访问。
......@@ -371,6 +368,3 @@ channel.CallMethod(NULL, &cntl, &request, &response, NULL); // 假设channel
// Process response. response.data() is the buffer, response.size() is the length.
```
[public/bvar](https://github.com/brpc/brpc/tree/master/src/bvar/)是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值,它利用了thread local存储避免了cache bouncing,相比UbMonitor几乎不会给程序增加性能开销,也快于竞争频繁的原子操作。brpc集成了bvar,[/vars](http://brpc.baidu.com:8765/vars)可查看所有曝光的bvar,[/vars/VARNAME](http://brpc.baidu.com:8765/vars/rpc_socket_count)可查阅某个bvar,增加计数器的方法请查看[bvar](bvar.md)。brpc大量使用了bvar提供统计数值,当你需要在多线程环境中计数并展现时,应该第一时间想到bvar。但bvar不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读得合并所有写过的线程中的数据,而不可避免地变慢了。当你读写都很频繁并得基于数值做一些逻辑判断时,你不应该用bvar。
[bvar](https://github.com/brpc/brpc/tree/master/src/bvar/)是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值,它利用了thread local存储避免了cache bouncing,相比UbMonitor几乎不会给程序增加性能开销,也快于竞争频繁的原子操作。brpc集成了bvar,[/vars](http://brpc.baidu.com:8765/vars)可查看所有曝光的bvar,[/vars/VARNAME](http://brpc.baidu.com:8765/vars/rpc_socket_count)可查阅某个bvar,增加计数器的方法请查看[bvar](bvar.md)。brpc大量使用了bvar提供统计数值,当你需要在多线程环境中计数并展现时,应该第一时间想到bvar。但bvar不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读得合并所有写过的线程中的数据,而不可避免地变慢了。当你读写都很频繁并得基于数值做一些逻辑判断时,你不应该用bvar。
## 查询方法
......
......@@ -512,7 +512,7 @@ Channel的默认协议是标准协议, 可通过设置ChannelOptions.protocol换
- PROTOCOL_NOVA_PBRPC 或 "nova_pbrpc", 网盟的协议, 默认为连接池.
- PROTOCOL_HTTP 或 "http", http协议, 默认为连接池(Keep-Alive). 具体方法见[访问HTTP服务](http_client.md).
- PROTOCOL_SOFA_PBRPC 或 "sofa_pbrpc", sofa-pbrpc的协议, 默认为单连接.
- PROTOCOL_PUBLIC_PBRPC 或 "public_pbrpc", public/pbrpc的协议, 默认为连接池.
- PROTOCOL_PUBLIC_PBRPC 或 "public_pbrpc", public_pbrpc的协议, 默认为连接池.
- PROTOCOL_UBRPC_COMPACK 或 "ubrpc_compack", public/ubrpc的协议, 使用compack打包, 默认为连接池. 具体方法见[ubrpc (by protobuf)](ub_client.md). 相关的还有PROTOCOL_UBRPC_MCPACK2或ubrpc_mcpack2, 使用mcpack2打包.
- PROTOCOL_NSHEAD_CLIENT 或 "nshead_client", 这是发送brpc-ub中所有UBXXXRequest需要的协议, 默认为连接池. 具体方法见[访问ub](ub_client.md).
- PROTOCOL_NSHEAD 或 "nshead", 这是brpc中发送NsheadMessage需要的协议, 默认为连接池. 注意发送NsheadMessage的效果等同于发送brpc-ub中的UBRawBufferRequest, 但更加方便一点. 具体方法见[nshead+blob](ub_client.md#nshead-blob) .
......@@ -716,13 +716,13 @@ struct ChannelOptions {
### Q: Invalid address=`bns://group.user-persona.dumi.nj03'是什么意思
```
FATAL 04-07 20:00:03 7778 public/brpc/src/brpc/channel.cpp:123] Invalid address=`bns://group.user-persona.dumi.nj03'. You should use Init(naming_service_name, load_balancer_name, options) to access multiple servers.
FATAL 04-07 20:00:03 7778 src/brpc/channel.cpp:123] Invalid address=`bns://group.user-persona.dumi.nj03'. You should use Init(naming_service_name, load_balancer_name, options) to access multiple servers.
```
访问bns要使用三个参数的Init, 它第二个参数是load_balancer_name, 而你这里用的是两个参数的Init, 框架当你是访问单点, 就会报这个错.
### Q: 两个产品线都使用protobuf, 为什么不能互相访问
协议 !=protobuf. protobuf负责打包, 协议负责定字段. 打包格式相同不意味着字段可以互通. 协议中可能会包含多个protobuf包, 以及额外的长度、校验码、magic number等等. 协议的互通是通过在RPC框架内转化为统一的编程接口完成的, 而不是在protobuf层面. 从广义上来说, protobuf也可以作为打包框架使用, 生成其他序列化格式的包, 像[idl<=>protobuf](idl_protobuf.md)就是通过protobuf生成了解析idl的代码.
协议 !=protobuf. protobuf负责打包, 协议负责定字段. 打包格式相同不意味着字段可以互通. 协议中可能会包含多个protobuf包, 以及额外的长度、校验码、magic number等等. 协议的互通是通过在RPC框架内转化为统一的编程接口完成的, 而不是在protobuf层面. 从广义上来说, protobuf也可以作为打包框架使用, 生成其他序列化格式的包, 像[idl<=>protobuf](mcpack2pb.md)就是通过protobuf生成了解析idl的代码.
### Q: 为什么C++ client/server 能够互相通信, 和其他语言的client/server 通信会报序列化失败的错误
......@@ -736,7 +736,7 @@ FATAL 04-07 20:00:03 7778 public/brpc/src/brpc/channel.cpp:123] Invalid address=
1. 创建一个[bthread_id](https://github.com/brpc/brpc/blob/master/src/bthread/id.h)作为本次RPC的correlation_id.
2. 根据Channel的创建方式, 从进程级的[SocketMap](https://github.com/brpc/brpc/blob/master/src/brpc/socket_map.h)中或从[LoadBalancer](https://github.com/brpc/brpc/blob/master/src/brpc/load_balancer.h)中选择一台下游server作为本次RPC发送的目的地.
3. 根据连接方式(单连接、连接池、短连接), 选择一个[Socket](https://svn.baidu.com/public/trunk/baidu-rpc/src/baidu/rpc/socket.h).
3. 根据连接方式(单连接、连接池、短连接), 选择一个[Socket](https://github.com/brpc/brpc/blob/master/src/brpc/socket.h).
4. 如果开启验证且当前Socket没有被验证过时, 第一个请求进入验证分支, 其余请求会阻塞直到第一个包含认证信息的请求写入Socket. 这是因为server端只对第一个请求进行验证.
5. 根据Channel的协议, 选择对应的序列化函数把request序列化至[IOBuf](https://github.com/brpc/brpc/blob/master/src/butil/iobuf.h).
6. 如果配置了超时, 设置定时器. 从这个点开始要避免使用Controller对象, 因为在设定定时器后->有可能触发超时机制->调用到用户的异步回调->用户在回调中析构Controller.
......
......@@ -21,7 +21,7 @@
#include "echo.pb.h"
DEFINE_bool(send_attachment, true, "Carry attachment along with requests");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8003", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -22,7 +22,7 @@
#include <brpc/channel.h>
#include "echo.pb.h"
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -20,7 +20,7 @@
#include <brpc/channel.h>
#include "echo.pb.h"
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -32,7 +32,7 @@ DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_int32(depth, 0, "number of loop calls");
// Don't send too frequently in this example
DEFINE_int32(sleep_ms, 100, "milliseconds to sleep after each RPC");
......
......@@ -29,7 +29,7 @@ DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(server, "file://server_list", "Mapping to servers");
DEFINE_string(load_balancer, "rr", "Name of load balancer");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
......
......@@ -21,7 +21,7 @@
#include "echo.pb.h"
DEFINE_string(attachment, "foo", "Carry this along with requests");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -25,7 +25,7 @@ DEFINE_string(server, "0.0.0.0:8000", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
DEFINE_int32(max_retry, 3, "Max retries(not including the first RPC)");
DEFINE_string(protocol, "sofa_pbrpc", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "sofa_pbrpc", "Protocol type. Defined in src/brpc/options.proto");
int main(int argc, char* argv[]) {
// Parse gflags. We recommend you to use gflags as well.
......
syntax="proto2";
// Converted from echo.idl by public/mcpack2pb/idl2proto
// Converted from echo.idl by brpc/tools/idl2proto
import "idl_options.proto";
option (idl_support) = true;
option cc_generic_services = true;
......
......@@ -26,7 +26,7 @@ DEFINE_int32(thread_num, 50, "Number of threads to send requests");
DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8002", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -28,7 +28,7 @@
DEFINE_int32(thread_num, 50, "Number of threads to send requests");
DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "file://server_list", "Addresses of servers");
DEFINE_string(load_balancer, "rr", "Name of load balancer");
......
// Converted from echo.idl by public/mcpack2pb/idl2proto
// Converted from echo.idl by brpc/tools/idl2proto
syntax="proto2";
import "idl_options.proto";
option (idl_support) = true;
......
......@@ -31,7 +31,7 @@ DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(server, "0.0.0.0:8002", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
......
......@@ -30,7 +30,7 @@ DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(server, "file://server_list", "Mapping to servers");
DEFINE_string(load_balancer, "rr", "Name of load balancer");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
......
......@@ -26,7 +26,7 @@ DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(starting_server, "0.0.0.0:8114", "IP Address of the first server, port of i-th server is `first-port + i'");
DEFINE_string(load_balancer, "rr", "Name of load balancer");
DEFINE_int32(timeout_ms, 100, "RPC timeout in milliseconds");
......
......@@ -25,7 +25,7 @@ DEFINE_int32(thread_num, 50, "Number of threads to send requests");
DEFINE_bool(use_bthread, false, "Use bthread to send requests");
DEFINE_int32(attachment_size, 0, "Carry so many byte attachment along with requests");
DEFINE_int32(request_size, 16, "Bytes of each request");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in protocol/brpc/options.proto");
DEFINE_string(protocol, "baidu_std", "Protocol type. Defined in src/brpc/options.proto");
DEFINE_string(connection_type, "", "Connection type. Available values: single, pooled, short");
DEFINE_string(server, "0.0.0.0:8002", "IP Address of server");
DEFINE_string(load_balancer, "", "The algorithm for load balancing");
......
......@@ -26,7 +26,7 @@ namespace brpc {
// NOTE: impl. are in brpc/protocol.cpp
// Convert a case-insensitive string to corresponding ProtocolType which is
// defined in protocol/brpc/options.proto
// defined in src/brpc/options.proto
// Returns: PROTOCOL_UNKNOWN on error.
ProtocolType StringToProtocolType(const butil::StringPiece& type,
bool print_log_on_unknown);
......
......@@ -67,7 +67,7 @@ struct ChannelOptions {
// Maximum: INT_MAX
int max_retry;
// Serialization protocol, defined in protocol/brpc/options.proto
// Serialization protocol, defined in src/brpc/options.proto
// NOTE: You can assign name of the protocol to this field as well, for
// Example: options.protocol = "baidu_std";
AdaptiveProtocolType protocol;
......
......@@ -369,7 +369,7 @@ static void GlobalInitializeOrDieImpl() {
PackPublicPbrpcRequest,
NULL, ProcessPublicPbrpcResponse,
NULL, NULL, NULL,
// public/pbrpc server implementation
// public_pbrpc server implementation
// doesn't support full duplex
CONNECTION_TYPE_POOLED_AND_SHORT,
"public_pbrpc" };
......
......@@ -34,7 +34,7 @@
namespace brpc {
namespace policy {
// Notes on public/pbrpc Protocol:
// Notes on public_pbrpc Protocol:
// 1 - It's based on nshead whose request has special `version' and
// `provider' field. However, these fields are not checked at
// server side
......@@ -214,7 +214,7 @@ void SerializePublicPbrpcRequest(butil::IOBuf* buf, Controller* cntl,
const google::protobuf::Message* request) {
CompressType type = cntl->request_compress_type();
if (type != COMPRESS_TYPE_NONE && type != COMPRESS_TYPE_SNAPPY) {
cntl->SetFailed(EREQUEST, "public/pbrpc doesn't support "
cntl->SetFailed(EREQUEST, "public_pbrpc doesn't support "
"compress type=%d", type);
return;
}
......
......@@ -56,7 +56,7 @@ DECLARE_uint64(max_body_size);
DECLARE_bool(log_error_text);
// 3 steps to add a new Protocol:
// Step1: Add a new ProtocolType in protocol/brpc/options.proto
// Step1: Add a new ProtocolType in src/brpc/options.proto
// as identifier of the Protocol.
// Step2: Implement callbacks of struct `Protocol' in policy/ directory.
// Step3: Register the protocol in global.cpp using `RegisterProtocol'
......
......@@ -18,10 +18,9 @@
#include "brpc/log.h"
#include "brpc/redis_command.h"
// Defined in public/iobuf/butil/iobuf.cpp
// Defined in src/butil/iobuf.cpp
void* fast_memcpy(void *__restrict dest, const void *__restrict src, size_t n);
namespace brpc {
// Much faster than snprintf(..., "%lu", d);
......
......@@ -243,10 +243,8 @@ struct ServerOptions {
// redirected by nginx or other http front-end servers), set this port
// to a port number that's ONLY accessible from Baidu's internal network
// so that you can check out the builtin services from this port while
// hiding them from public. This port is better inside 8000-8999 which
// is accessible from your web browser due to Baidu's firewall rules.
// Setting this option also enables security protection code which we
// may add constantly.
// hiding them from public. Setting this option also enables security
// protection code which we may add constantly.
// Update: this option affects Tabbed services as well.
// Default: -1
int internal_port;
......@@ -423,7 +421,7 @@ public:
int Start(int port, const ServerOptions* opt);
// Start on ip:port enclosed in butil::EndPoint which is defined in
// public/common/butil/endpoint.h
// src/butil/endpoint.h
int Start(const butil::EndPoint& ip_port, const ServerOptions* opt);
// Start on `ip_str' + any useable port in `port_range'
......
......@@ -119,7 +119,7 @@ struct BucketInfo {
// NOTE: Objects stored in FlatMap MUST be copyable.
template <typename _K, typename _T,
// Compute hash code from key.
// Use public/murmurhash3 to make better distributions.
// Use src/butil/third_party/murmurhash3 to make better distributions.
typename _Hash = DefaultHasher<_K>,
// Test equivalence between stored-key and passed-key.
// stored-key is always on LHS, passed-key is always on RHS.
......
......@@ -1343,7 +1343,7 @@ bool McpackToProtobuf::Generate(const google::protobuf::FileDescriptor* file,
ctx->OpenForInsert(cpp_name, "global_scope"), '$');
gdecl_printer.Print(
"\n// ==== declarations generated by public/mcpack2pb/protoc-gen-mcpack ====\n"
"\n// ==== declarations generated by brpc/mcpack2pb/protoc-gen-mcpack ====\n"
"DECLARE_bool(mcpack2pb_absent_field_is_error);\n");
std::set<std::string> ref_msgs;
......
......@@ -212,8 +212,7 @@ inline void OutputStream::backup(int n) {
const int64_t nbackup = saved_bytecount - _zc_stream->ByteCount();
if (nbackup != n + _size) {
CHECK(false) << "Expect output stream backward for " << n + _size
<< " bytes, actually " << nbackup
<< " bytes, make sure public/iobuf is newer than r32794";
<< " bytes, actually " << nbackup << " bytes";
}
_size = 0;
_fullsize = 0;
......
......@@ -90,7 +90,7 @@ public:
// Change data at the area. `data' must be as long as the reserved area.
void assign(const Area&, const void* data);
// Go back for n bytes. Require public/iobuf > r32794
// Go back for n bytes.
void backup(int n);
// Returns bytes pushed and cut since creation of this stream.
......
......@@ -84,7 +84,7 @@ protected:
_server._status = brpc::Server::RUNNING;
_server._options.nshead_service =
new brpc::policy::PublicPbrpcServiceAdaptor;
// public/pbrpc doesn't support authentication
// public_pbrpc doesn't support authentication
// _server._options.auth = &_auth;
EXPECT_EQ(0, pipe(_pipe_fds));
......
......@@ -81,7 +81,7 @@ sed -e ':a;N;$!ba;s/=\s*\n\+/=/g' $1 | \
primitives["float"] = 1; \
primitives["double"] = 1; \
print "// Converted from '$1' by public/mcpack2pb/idl2proto\n" \
print "// Converted from '$1' by brpc/tools/idl2proto\n" \
"syntax=\"proto2\";\n" \
"import \"idl_options.proto\";\n" \
"option (idl_support) = true;\n\n" \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment