# 运行示例程序 在命令行中运行如下命令即可在~/my_baidu_rpc/public/baidu-rpc中下载源代码编译并运行echo示例程序: > mkdir -p ~/my_baidu_rpc/public && cd ~/my_baidu_rpc/public && svn co > https://svn.baidu.com/public/trunk/baidu-rpc && cd baidu-rpc && comake2 -UB -J8 -j8 && comake2 -P > && make -sj8 && cd example/echo_c++ && comake2 -UB -J8 -j8 && comake2 -P && make -sj8 && ( > ./echo_server & ) && ./echo_client && pkill echo_server # 通过COMAKE依赖baidu-rpc 如果你的模块还没有建立,你可能得去[work.baidu.com](http://work.baidu.com/)上申请新的模块。确保你使用了[comake2](http://wiki.babel.baidu.com/twiki/bin/view/Com/Main/Comake2)。 在COMAKE文件中增加: > CONFIGS('public/baidu-rpc@ci-base') 这依赖了baidu-rpc的最新发布版本。模板可参考[echo的COMAKE文件](https://svn.baidu.com/public/trunk/baidu-rpc/example/echo_c++/COMAKE)。然后运行: ``` $ comake2 -UB # 下载所有的依赖模块 $ comake2 -P # 生成或更新Makefile $ make -sj8 # 编译 ``` 你也可以在[agile上](http://agile.baidu.com/#/builds/public/baidu-rpc@trunk) 或[scm.baidu.com](http://scm.baidu.com/)上查询baidu-rpc的已发布版本,并在COMAKE中依赖对应的静态版本。当comake2 -UB时baidu-rpc的版本会固定在你选定的版本上。注意:静态版本指的是我们发布的tag,而不是trunk上的revision。请勿依赖trunk的某个revision。 ### gcc4下的errno问题 务必在直接或间接使用baidu-rpc的C/C++项目COMAKE中添加**CPPFLAGS('-D__const__=')**,防止[gcc4下的errno问题](http://wiki.baidu.com/display/RPC/thread-local#thread-local-gcc4下的errno问题)。 ## comake出错 老版本comake2(比如2.1.3.2304)不支持ci-base版本,如果comake2报如下的错误,说明版本太老: ``` ... [status:1][err:https://svn.baidu.com/public/tags/xxx/ci-base: (Not a valid URL) ``` 你可以运行如下命令更新comake2版本后再试,确保你有修改的权限。 ``` $ cd $(dirname $(readlink -f $(which comake2)))/libcomake2 $ ./auto_update.py ``` ## 更新依赖后编译失败 一般是baidu-rpc和依赖的模块版本不匹配导致的。确保以下模块没有被指定版本,让baidu-rpc自己选择: [public/common](http://agile.baidu.com/agile/pipeline#/builds/public/common@trunk) [public/bthread](http://agile.baidu.com/agile/pipeline#/builds/public/bthread@trunk) [public/bvar](http://agile.baidu.com/agile/pipeline#/builds/public/bvar@trunk) [public/murmurhash](http://agile.baidu.com/agile/pipeline#/builds/public/murmurhash@trunk) [public/mcpack2pb](http://agile.baidu.com/agile/pipeline#/builds/public/mcpack2pb@trunk) [public/iobuf](http://agile.baidu.com/agile/pipeline#/builds/public/iobuf@trunk) [public/protobuf-json](http://agile.baidu.com/agile/pipeline#/builds/public/protobuf-json@trunk) 问题的根源在于百度的代码库不是单根的,所以每个模块都有很多独立版本, 产生非常多的组合, 有点类似于以前windows上的dll hell问题, 以baidu-rpc依赖的public/common为例: - 情况1: 产品线依赖了public/common@某tag 和 public/baidu-rpc@ci-base, 所以baidu-rpc总是会更新到最新, 而public/common则不会, 如果baidu-rpc依赖了public/common的新接口, baidu-rpc的编译就挂了. - 情况2: 产品线依赖了public/common@ci-base 和 public/baidu-rpc@某tag, 所以public/common总是会更新到最新, 但baidu-rpc不变, 如果public/common中删除了老接口, 或一些接口有调整, baidu-rpc的编译也挂了 如果去掉了public/common的依赖, 每次更新时COMAKE或BCLOUD会自动选择baidu-rpc对应版本被发布时使用的public/common版本, 比如baidu-rpc@某tag会选择该tag发布时对应的public/common版本, 一般总是可编译过的. 当然COMAKE或BCLOUD可能会对依赖打平, 如果产品线依赖的其他模块里依赖了public/common某版本且无法更改, 同时有编译问题, 只是在自己模块中去掉对public/common的依赖是不够的, 因为COMAKE或BCLOUD还是会选到那个指定的版本, 这种情况下可以在自己的COMAKE或BCLOUD中显式地依赖baidu-rpc@ci-base和public/common@ci-base. 基本原则就是都依赖ci-base一般总是对的, 不用过于担心稳定性问题. # 支持的软件栈 ## GCC | 版本 | 支持程度 | | ---- | ----------- | | 3.4 | 一直支持 | | 4.4 | 15年9月后的版本支持 | | 4.8 | 一直支持 | | 5.4 | r34255后支持 | | 7.1 | r35109后支持 | 使用其他版本的gcc可能会有warning而编译失败 (baidu-rpc把warning也视作error), 请联系我们修复。 r32023后支持C++11编译。 ## GDB 如果你使用的是opt/compiler下的gcc(4.8),那么gdb应该也应该用opt/compiler下的。 如果gdb对多线程的支持有问题,可以用这个版本,在目标机器上运行如下命令可获得gdb79可执行文件: `wget "http://hetu.baidu.com:80/api/tool/getFile?toolId=1357&fileId=1201" -O "gdb79" && chmod +x ./gdb79` ## OS RHEL4,centos 6.5,centos 4.3,ubuntu 14.04 (linuxmint 17.3) ubuntu (linuxmint)下找不到openssl/ssl.h的话请安装libssl-dev。 对于自己的机器,安装好svn和[comake2](http://wiki.babel.baidu.com/twiki/bin/view/Com/Main/Comake2#安装升级)(公司环境中才能运行auto_udpate.py)后就可以按照第一节的方法下载和运行baidu-rpc了。 ## protobuf 一直支持2.4。公司内请使用[2.4.1.1100](http://scm.baidu.com/fourversion/index.action?threeversion.id=346350&fourversion.id=668155),这个版本中为google::protobuf::NewCallback增加了重载形式,可以支持超过2个参数。 r31361后支持2.6。公司内请使用[2.6.1.400](http://scm.baidu.com/fourversion/index.action?threeversion.id=644886&fourversion.id=1139940),这个版本中为google::protobuf::NewCallback增加了重载形式,可以支持超过2个参数。 r32035后支持3.1.x,server端的arena分配暂不支持。不要求开启C++11,但要求gcc 4.8。 r35000后支持3.2.x。 ### 更换protobuf版本 baidu-rpc默认的依赖2.4,你可以在你项目的COMAKE或BCLOUD中指定不同版本的protobuf,依赖会被打平。如果baidu-rpc依赖的一些模块报告protobuf版本不匹配,可以去对应的模块clean后重编。 ### 关于NewCallback 由于protobuf 3把NewCallback设置为私有,r32035后baidu-rpc把NewCallback独立于[src/baidu/rpc/callback.h](https://svn.baidu.com/public/trunk/baidu-rpc/src/baidu/rpc/callback.h),如果你的程序出现NewCallback相关的编译错误(不论protobuf的版本),把google::protobuf::NewCallback替换为baidu::rpc::NewCallback就行了。 ### 编译.proto COMAKE[支持proto文件](http://wiki.babel.baidu.com/twiki/bin/view/Com/Main/Comake2#如何编译idl或proto文件)作为源文件,但需要通过**PROTOC**指明protobuf compiler的位置,在COMAKE文件中加入: **COMAKE** 你也可以使用用如下命令手动生成代码,详见[公司内的pb文档](http://wiki.babel.baidu.com/twiki/bin/view/Com/Main/Protobuf): ``` $ protoc --cpp_out=DEST_PATH -I=PROTO_PATH your.proto ``` 更多protobuf问题请先阅读[google官方文档](https://developers.google.com/protocol-buffers/docs/reference/overview),再阅读[公司内文档](http://wiki.babel.baidu.com/twiki/bin/view/Com/Main/Protobuf),确保你已经了解protobuf的概念和基本使用方式。不确定的接口可以查看生成的.pb.h文件。 ### 同时兼容pb 3.0和pb 2.x 勿使用proto3的新类型,proto文件开头要加上syntax="proto2";,[tools/add_syntax_equal_proto2_to_all.sh](https://svn.baidu.com/public/trunk/baidu-rpc/tools/add_syntax_equal_proto2_to_all.sh)可以给目录以下的所有没有加的proto文件加上syntax="proto2"。 ## boost 要求1.56以上。r34354后开启C++11时不依赖boost。 **intrusive_ptr** r34233后改为依赖public/common中的base::intrusive_ptr,不再依赖boost中的。 **context** r34213后改为依赖public/bthread中的context,不再依赖boost中的。 r34213前如果在编译过程中出现相关的错误,可以尝试在COMAKE中显式地声明依赖: **COMAKE** **atomic** r34354后改为依赖public/common中的base::atomic,不再(直接)依赖boost中的。当开启C++11时,base::atomic基于std::atomic,否则仍基于boost::atomic。换句话说,此版本以后的baidu-rpc当开启C++11时不再依赖boost。 ## tcmalloc baidu-rpc默认**不链接**[tcmalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html),如果需要可自行依赖,在COMAKE中增加: **COMAKE** tcmalloc相比默认的ptmalloc常可提升整体性能,建议尝试。但不同的tcmalloc版本可能有巨大的性能差异。tcmalloc 2.1.0.100会使baidu-rpc示例程序的性能显著地低于使用tcmalloc 1.7.0.200和2.5.0.5977的版本。甚至使用 1.7.0.100的性能也比1.7.0.200低一些,当你的程序出现性能问题时,去掉tcmalloc或更换版本看看。 使用gcc4.8.2编译的模块, 如果依赖的是third-64/tcmalloc(gcc3.4.5编译的产出), 可能会遇到main函数前malloc线程不安全的情况,具体表现为程序在main函数之前crash或者死锁. 例如  如果你的程序在gcc4.8编译的产出中遇到这个问题,建议升级tcmalloc为源码编译. tcmalloc的另一个常见问题是它不像默认的ptmalloc那样及时的归还系统内存,所以在出现非法内存访问时,可能不会立刻crash,而最终crash在不相关的地方,甚至不crash。当你的程序出现诡异的内存问题时,也记得去掉tcmalloc看看。 如果要使用[cpu profiler](http://wiki.baidu.com/display/RPC/cpu+profiler)或[heap profiler](http://wiki.baidu.com/display/RPC/heap+profiler),请链接tcmalloc,这两个profiler是基于tcmalloc开发的。[contention profiler](http://wiki.baidu.com/display/RPC/contention+profiler)不要求tcmalloc。 不想链接tcmalloc时请注意:不仅要去掉对tcmalloc模块的依赖,还得检查下是否删除了-DBAIDU_RPC_ENABLE_CPU_PROFILER 或 -DBAIDU_RPC_ENABLE_HEAP_PROFILER等baidu-rpc的宏。 ## gflags 经验证支持2.0至[2.21](https://github.com/gflags/gflags/tree/v2.2.1) ## valgrind 在r30539后,在valgrind中运行程序时加上**-has_valgrind** (确保你的程序使用了[gflags](http://wiki.baidu.com/pages/viewpage.action?pageId=71698818)) > 例如valgrind ./my_program > -has_valgrind。如果没有开启的话,valgrind无法识别bthread的栈从而可能crash。 > > 老版本的valgrind(比如3.2)似乎不支持,请使用新一点的版本(比如3.8),可以用[jumbo](http://jumbo.baidu.com/)安装。 在r34944后,-has_valgrind被移除,程序会自动判断是否在valgrind中。 ## openssl r35109后支持1.1 # 新特性 对用户有意义的新特性,以方便用户调研使用。 | 版本 | 功能 | 描述 | | --------- | --------------------------- | ---------------------------------------- | | `r33446 ` | 开启-usercode_in_pthread无死锁风险 | 之前有。 | | `r33424 ` | 增加开关-log_hostname | 开启后会在每条日志后加上本机名。对于汇总的日志查询工具有用。 | | `r33323 ` | 默认发布工具 | 编译baidu-rpc时rpc_press, rpc_view, rpc_replay, parallel_http也会一并编译,并能在产品库中获得。要注意的是,产品库默认以gcc 3.4编译,在新机器上可能无法直接运行,需要对一些so做软链。 | | `r33306 ` | 增加工具parallel_http | 可同时访问数万个http url, 远快于curl(即使批量后台运行) | | `r32844 ` | 支持http-flv | 另一种广泛用于直播的流媒体协议 | | `r32803 ` | 支持同时发起大量异步访问 | 重构了bthread_id_list_t,从静态容量变为了动态容量。 | | `r32668 ` | 支持RTMP | 一种广泛用于直播的流媒体协议(仍在完善中) | | `r32560 ` | 支持NamingServiceFilter | 用于过滤名字服务返回的节点列表 | | `r32536 ` | 初始化bthread | `ServerOptions增加了bthread_init_fn等参数用于在server启动前初始化一些bthread。` | | `r32420 ` | 支持nshead_mcpack | 可用protobuf处理nshead+mcpack的协议 | | `r32401 ` | 受控的日志打印 | `LOG_ONCE:只打印一次 LOG_EVERY_N:每过N次打印一次 LOG_EVERY_SECOND:每秒打印一次` | | `r32399 ` | 不可修改的flags | 加上-immutable_flags程序的/flags页面就无法被修改了 | | `r32328 ` | 获取RPC延时 | Controller.latency_us()会返回对应的RPC延时,同步异步都支持。 | | `r32301 ` | 显示RTT | [/connections](http://brpc.baidu.com:8765/connections)页面会显示内核统计的smooth RTT了。 | | `r32279 ` | 支持凤巢ITP协议 | 详见[ITP](http://wiki.baidu.com/pages/viewpage.action?pageId=184259578) | | `r32097` | 支持Restful开发 | 用户可定制访问每个方法的URL,详见[RestfulURL](http://wiki.baidu.com/pages/viewpage.action?pageId=213828736#id-实现HTTPService-RestfulURL) | | `r32034 ` | 支持protobuf 3.0 | `Server端的Arena分配仍不支持。mcpack2pb, protobuf-json等周边工具仍待迁移。` | | `r32015 ` | 访问redis-server | [访问Redis](http://wiki.baidu.com/pages/viewpage.action?pageId=213828705) | | `r32009` | RetryPolicy | 可定制重试策略,详见[重试](http://wiki.baidu.com/pages/viewpage.action?pageId=213828685#id-创建和访问Client-错误值得重试) | | `r32009 ` | rpc_view | 可在浏览器中查看端口不在[8000-8999]的内置服务,详见[rpc_view](http://wiki.baidu.com/pages/viewpage.action?pageId=167651918) | | `r31986 ` | rpc_press | 代替了pbrpcpress,详见[rpc_press](http://wiki.baidu.com/pages/viewpage.action?pageId=97645422) | | `r31901 ` | contention profiler | 可分析在锁上的等待时间,详见[contention profiler](http://wiki.baidu.com/pages/viewpage.action?pageId=165876314) | | `r31658 ` | rpc dump & replay | 详见[rpc_replay](http://wiki.baidu.com/pages/viewpage.action?pageId=158707916) | # FAQ ### Q: baidu-rpc会不会发布稳定版本 本项目是主干开发,最新的改动在[trunk](https://svn.baidu.com/public/trunk/baidu-rpc/),发布在[agile上](http://agile.baidu.com/#/builds/public/baidu-rpc@trunk)。我们会尽量保持已有接口不变,升级新版本一般不会break代码。由于开发节奏快,我们没有发布Releasing Branch (RB)的计划。 使用ci-base是更安全的选择。老版本的使用者更稀疏一些,bug会更加隐秘,发现得更晚。这种注意不到的bug会真正影响到策略的判断和迭代。而ci-base你在用,其他产品线也在用,问题很快能被发现和纠正。 如果正在运行的baidu-rpc版本被发现了用户有感的bug,我们会给每个baidu-rpc server实例推送对应的bug信息,以提示产品线尽快升级,提示内容如下所示: FATAL: 01-23 11:11:43: adx * 14542 src/baidu/rpc/trackme.cpp:141] Your baidu-rpc (r34140) is affected by: [r34123-r34140] base::IOBuf::append(Movable) may leak memory; ### Q: SSL相关的链接问题 在1.0.171.31586之**前**的版本中,可能出现如下的core,请在COMAKE的LDFLAGS中去掉-lssl -lcrypto,加上-ldl -lz。原因在于baidu-rpc链接的third-64/openssl和系统提供的冲突。 在1.0.171.31586之**后**的版本中,为了提高对不同平台的兼容性,baidu-rpc不再静态链接openssl,可能在链接时出现undefined reference,请在COMAKE的LDFLAGS中加上-lssl -lcrypto。 ``` #0 0x000000302af6f950 in strcmp () from /lib64/tls/libc.so.6 #1 0x000000302cc992a3 in OBJ_NAME_new_index () from /lib64/libcrypto.so.4 #2 0x000000302cc959a0 in lh_free () from /lib64/libcrypto.so.4 #3 0x000000302cc95cc2 in lh_insert () from /lib64/libcrypto.so.4 #4 0x000000302cc99469 in OBJ_NAME_add () from /lib64/libcrypto.so.4 #5 0x000000000078a8a5 in SSL_library_init () at webfoot_item.cpp:21 #6 0x0000000000613b0d in RegisterAllExtensionsOrDieImpl () at src/baidu/rpc/policy/register_all_extensions.cpp:97 #7 0x000000302b809a10 in pthread_once () from /lib64/tls/libpthread.so.0 #8 0x0000000000613a31 in baidu::rpc::policy::RegisterAllExtensionsOrDie () at src/baidu/rpc/policy/register_all_extensions.cpp:238 #9 0x00000000005ccaac in Channel (this=0xb69c40) at src/baidu/rpc/channel.cpp:68 #10 0x000000000059e0f8 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at test_ei_srv_client.cpp:8 #11 0x000000000059e159 in global constructors keyed to main () at test_ei_srv_client.cpp:19 #12 0x0000000000903696 in __do_global_ctors_aux () at ./src/base/spinlock.h:49 #13 0x000000000059b028 in _init () #14 0x0000000000903610 in __libc_csu_init () at ./src/base/spinlock.h:49 #15 0x00000000009035d1 in __libc_csu_init () at ./src/base/spinlock.h:49 #16 0x000000302af1c45f in __libc_start_main () from /lib64/tls/libc.so.6 #17 0x000000000059deaa in _start () #18 0x0000007fbffff1a8 in ?? () #19 0x000000000000001c in ?? () ``` ### Q: 为什么C++ client/server 能够互相通信, 和其他语言的client/server 通信会报序列化失败的错误 检查一下C++ 版本是否开启了压缩 (Controller::set_compress_type), 目前 python/JAVA 版的rpc框架还没有实现压缩,互相返回会出现问题。 ### Q: 两个产品线都使用protobuf,为什么不能互相访问 协议 != protobuf。protobuf负责打包,协议负责定字段。打包格式相同不意味着字段可以互通。协议中可能会包含多个protobuf包,以及额外的长度、校验码、magic number等等。协议的互通是通过在RPC框架内转化为统一的编程接口完成的,而不是在protobuf层面。从广义上来说,protobuf也可以作为打包框架使用,生成其他序列化格式的包,像[idl <=> protobuf](http://wiki.baidu.com/pages/viewpage.action?pageId=144820547)就是通过protobuf生成了解析idl的代码。 ### Q: protobuf打印了UTF-8相关的错误日志 ``` // protobuf 2.4 google/protobuf/wire_format.cc:1059] Encountered string containing invalid UTF-8 data while parsing protocol buffer. Strings must contain only UTF-8; use the 'bytes' type for raw bytes. // protobuf 2.6 google/protobuf/wire_format.cc:1091] String field 'key' contains invalid UTF-8 data when serializing a protocol buffer. Use the 'bytes' type if you intend to send raw bytes ``` 原因:pb中的string必须是utf-8编码,非utf-8编码的字符串必须用bytes存储。 解决方式: 1. [推荐] 把proto中对应字段的类型从string改为bytes。string和bytes的二进制格式是一样的,所以这个改动不会造成新老消息的不兼容。这两个类型生成的函数也是一样的,用户代码不需要修改。 2. 定义宏NDEBUG。这个检查会被跳过。 注意:pb 2.4不会打印出问题的字段名,pb 2.6会,如果你需要快速定位出问题的字段,用pb 2.6