Merge branch 'master' into nshead_rpc_dump_and_replay
@@ -42,7 +42,7 @@ before_script:
|
||||
before_install:
|
||||
- wget --no-clobber https://github.com/bazelbuild/bazel/releases/download/0.25.1/bazel_0.25.1-linux-x86_64.deb && sudo dpkg -i bazel_0.25.1-linux-x86_64.deb
|
||||
- sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config # thrift dependencies
|
||||
- wget http://www.apache.org/dist/thrift/0.11.0/thrift-0.11.0.tar.gz && tar -xf thrift-0.11.0.tar.gz && cd thrift-0.11.0/ && ./configure --prefix=/usr --with-rs=no --with-ruby=no --with-python=no --with-java=no --with-go=no --with-perl=no --with-php=no --with-csharp=no --with-erlang=no --with-lua=no --with-nodejs=no CXXFLAGS="-Wno-unused-variable" && make -j4 && sudo make install && cd -
|
||||
- wget https://archive.apache.org/dist/thrift/0.11.0/thrift-0.11.0.tar.gz && tar -xf thrift-0.11.0.tar.gz && cd thrift-0.11.0/ && ./configure --prefix=/usr --with-rs=no --with-ruby=no --with-python=no --with-java=no --with-go=no --with-perl=no --with-php=no --with-csharp=no --with-erlang=no --with-lua=no --with-nodejs=no CXXFLAGS="-Wno-unused-variable" && make -j4 && sudo make install && cd -
|
||||
|
||||
install:
|
||||
- sudo apt-get install -qq realpath libgflags-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev libgoogle-perftools-dev libboost-dev libssl-dev libevent-dev libboost-test-dev libgoogle-glog-dev
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
# A image for building/testing brpc
|
||||
FROM ubuntu:16.04
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# prepare env
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
@@ -37,6 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libsnappy-dev && \
|
||||
apt-get clean -y
|
||||
|
||||
RUN git clone https://github.com/brpc/brpc.git brpc
|
||||
RUN cd /brpc && sh config_brpc.sh --headers=/usr/include --libs=/usr/lib && \
|
||||
RUN git clone https://github.com/apache/incubator-brpc.git
|
||||
RUN cd incubator-brpc && sh config_brpc.sh --headers=/usr/include --libs=/usr/lib && \
|
||||
make -j "$(nproc)"
|
||||
|
||||
@@ -476,7 +476,7 @@ src/butil/third_party/valgrind/valgrind.h: licensed under the following terms:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
src/butil/crc32c.h, src/butil/crc32c.cc: licensed under the following terms:
|
||||
src/butil/crc32c.h, src/butil/crc32c.cc, test/crc32c_unittest.cc: licensed under the following terms:
|
||||
|
||||
Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
This source code is licensed under the BSD-style license found in the
|
||||
@@ -663,7 +663,7 @@ src/brpc/ts.cpp: licensed under the following terms:
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
src/brpc/builtin/pprof_perl.cpp: licensed under the following terms:
|
||||
src/brpc/builtin/pprof_perl.cpp, tools/pprof: licensed under the following terms:
|
||||
|
||||
Copyright (c) 1998-2007, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Apache brpc (incubating)
|
||||
Copyright 2018-2020 The Apache Software Foundation
|
||||
Copyright 2018-2021 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.9.7
|
||||
1.0.0
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# brpc的应用案例集合
|
||||
|
||||
## what is this
|
||||
这里列出brpc在各个企业中的落地场景,包括企业名称,应用项目作用,集群规模和QPS统计,使用的版本信息等
|
||||
|
||||
## Why this
|
||||
列出各个案例,一来方便用户进行参考,了解brpc可以用在哪些场景下;
|
||||
二来方便社区开发者统计brpc的版本,规模等情况
|
||||
|
||||
# Case List
|
||||
## 落地case的sample (如果有多个场景,建议分开)
|
||||
* 公司名称: xxx公司
|
||||
* 落地项目: 例如app的个性化推荐系统的预测服务
|
||||
* 集群规模: 例如100台
|
||||
* QPS: 例如峰值1000万, 均值100万
|
||||
* 使用版本: 例如社区版本0.9.7
|
||||
* 信息提供者:某某
|
||||
|
||||
## brpc在 百度的落地情况
|
||||
* 公司名称: 百度
|
||||
* 落地项目: 基础架构(分布式计算、存储、数据库等),业务系统(Feed、凤巢、地图等)
|
||||
* 集群规模: 2000多个活跃模块,100w以上实例
|
||||
* 使用版本: baidu内部版本
|
||||
* 信息提供者:wwbmmm
|
||||
|
||||
## brpc在维沃的落地情况
|
||||
* 公司名称: 维沃(vivo)
|
||||
* 落地项目: 在线推荐系统
|
||||
* 使用版本: 社区版本0.9.7
|
||||
* 信息提供者:guodongxiaren
|
||||
|
||||
## brpc在爱奇艺的落地情况
|
||||
* 公司名称: 爱奇艺(iqiyi)
|
||||
* 落地项目: 广告、推荐、搜索
|
||||
* 使用版本: 基于社区版本定制
|
||||
* 集群规模: 3000+台机器(广告)
|
||||
* 信息提供者:cdjingit
|
||||
|
||||
## brpc在第四范式的落地情况
|
||||
* 公司名称: 第四范式(4paradigm)
|
||||
* 落地项目: 风控、推荐、智能运维等
|
||||
* 使用版本: 基于社区版本定制
|
||||
* 信息提供者:dl239
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,27 @@
|
||||
# 这里记录new committer相关的流程和网站
|
||||
|
||||
|
||||
## 成为committer的路程
|
||||
1. 在private邮件中发起讨论和投票
|
||||
2. 投票通过即OK
|
||||
3. 让他填写CLA并发给secretary@apache.org
|
||||
|
||||
|
||||
## 如何赋予committer在github上的权限
|
||||
|
||||
1. 加为committer
|
||||
https://whimsy.apache.org/roster/ppmc/brpc
|
||||
|
||||
2. 让他设置github id
|
||||
https://id.apache.org/
|
||||
|
||||
3. 让他访问该网址,获得github的权限
|
||||
https://gitbox.apache.org/setup/
|
||||
|
||||
|
||||
## apache 官网new committer相关的文档
|
||||
|
||||
https://community.apache.org/newcommitter.html
|
||||
|
||||
https://infra.apache.org/new-committers-guide.html
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# 值周工程师的职责如下
|
||||
|
||||
## 1. 每天查看github上brpc项目待处理的Pull Request和Issue列表,负责问题的处理
|
||||
* 包括标记issue,回复issue,关闭issue等;
|
||||
* 判断issue是否是长期Issue,如果是则标记为Pending
|
||||
* 判断Issue的类型,例如bug,enhancement, discussion等
|
||||
* 把issue分配到熟悉该模块的贡献者(可在微信群里询问谁来负责)
|
||||
|
||||
## 2. 轮值时间为一周
|
||||
* 即从周日早上到下周六晚上
|
||||
|
||||
## 3. 轮值结束需要
|
||||
* 编写值周report,并发送到dev@brpc.apache.org邮件群中
|
||||
* 提醒下一位轮值同学
|
||||
|
||||
## 4. 值周顺序如下
|
||||
* 朱佳顺 @zyearn
|
||||
* 李磊 @lorinlee
|
||||
* 王伟冰 @wwbmmm
|
||||
* 蔡道进 @cdjingit
|
||||
* 何磊 @TousakaRin
|
||||
|
||||
## 5. 值周记录如下
|
||||
|
||||
| 时间(月/日/年) | 值周人 | 值周report|
|
||||
| ---- | ---- | --- |
|
||||
| | 朱佳顺 |
|
||||
| 06/21/2021 to 06/27/2021 | 李磊 | https://lists.apache.org/thread.html/rc9eb911bc6465c16bd8bb14f9d1f7c9548e13759101f43cf0300908a%40%3Cdev.brpc.apache.org%3E
|
||||
| 06/28/2021 to 07/04/2021 | 蔡道进 | https://lists.apache.org/thread.html/r23992a4f958bea5b28b9b87a09c60790dae8d5d28f2c49aded3f1760%40%3Cdev.brpc.apache.org%3E
|
||||
| 07/05/2021 - 07/12/2021 | 何磊 | https://lists.apache.org/thread.html/r3f67bc42ecdc07b25c39aedaf30aeae79039aa1cc3e6ad99364c8178%40%3Cdev.brpc.apache.org%3E
|
||||
| 08/16/2021 - 08/22/2021 | 朱佳顺 | https://lists.apache.org/thread.html/rc03364574b40e4e9bb8112eae0500589d632011f535a4f0747c4ce5f%40%3Cdev.brpc.apache.org%3E
|
||||
| 08/23/2021 - 08/29/2021 | 李磊 | https://lists.apache.org/thread.html/r10522af87df62aa0aa48f5a279cef219db1917048108cb744e53772e%40%3Cdev.brpc.apache.org%3E
|
||||
| 08/30/2021 - 09/05/2021 | 蔡道进 |https://lists.apache.org/thread.html/r6e9846a17464581528280b43d835000da78ee700d2fa195cb92d2353%40%3Cdev.brpc.apache.org%3E
|
||||
| 09/06/2021 - 09/12/2021 | 何磊 | https://lists.apache.org/thread.html/ra10e10abca213e0e5e797a74af8a9c8810e54fd1543c108bf03a56e5%40%3Cdev.brpc.apache.org%3E
|
||||
| 09/20/2021 - 09/26/2021 | 李磊 | https://lists.apache.org/thread.html/r19c08874ad681edbc82526a09b34d3ccabe7cf168ed91935575ff557%40%3Cdev.brpc.apache.org%3E
|
||||
| 09/27/2021 - 10/03/2021 | 蔡道进 | https://lists.apache.org/thread.html/re3391d87f2e2aba55986b96b18ca375f07840bac67249fced2f851f5%40%3Cdev.brpc.apache.org%3E
|
||||
| 13/12/2021 - 19/12/2021 | 蔡道进 | https://lists.apache.org/thread/mvclsy79859mrbdso1xzm6y7yz3lg6w0
|
||||
| 01/24/2022 - 02/06/2022 | 王伟冰 | https://lists.apache.org/thread/ttgqnw4hfw0qnb7swvnn2kxb5b9hkdbo
|
||||
@@ -0,0 +1,558 @@
|
||||
brpc 发布apache release 版本流程step by step
|
||||
===
|
||||
概述:分为如下几个步骤
|
||||
1. 事前准备:包括生成签名需要的key,github上打标签,修改version文件等
|
||||
2. 发布软件包:包括制作source tarball,签名,上传到制定地点并验证
|
||||
3. 第一次投票:在dev@brpc邮件群里投票
|
||||
4. 第二次投票:在general@brpc邮件群里投票
|
||||
5. 发版通告:包括发邮件,更新brpc网站
|
||||
|
||||
|
||||
# 签名准备
|
||||
|
||||
## 1. 安装 GPG
|
||||
在[GnuPG官网](https://www.gnupg.org/download/index.html)下载安装包。 GnuPG的1.x版本和2.x版本的命令有细微差别,下列说明以`GnuPG-2.3.1`版本(OSX)为例。
|
||||
|
||||
安装完成后,执行以下命令查看版本号。
|
||||
```bash
|
||||
gpg --version
|
||||
```
|
||||
|
||||
## 2. 创建 key
|
||||
|
||||
安装完成后,执行以下命令创建key。
|
||||
|
||||
```bash
|
||||
gpg --full-gen-key
|
||||
```
|
||||
|
||||
根据提示完成创建key,注意邮箱要使用Apache邮件地址:
|
||||
```
|
||||
gpg (GnuPG) 2.3.1; Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Please select what kind of key you want:
|
||||
(1) RSA and RSA
|
||||
(2) DSA and Elgamal
|
||||
(3) DSA (sign only)
|
||||
(4) RSA (sign only)
|
||||
(9) ECC (sign and encrypt) *default*
|
||||
(10) ECC (sign only)
|
||||
(14) Existing key from card
|
||||
Your selection? 1
|
||||
RSA keys may be between 1024 and 4096 bits long.
|
||||
What keysize do you want? (3072) 4096
|
||||
Requested keysize is 4096 bits
|
||||
Please specify how long the key should be valid.
|
||||
0 = key does not expire
|
||||
<n> = key expires in n days
|
||||
<n>w = key expires in n weeks
|
||||
<n>m = key expires in n months
|
||||
<n>y = key expires in n years
|
||||
Key is valid for? (0) 0
|
||||
Key does not expire at all
|
||||
Is this correct? (y/N) y
|
||||
|
||||
GnuPG needs to construct a user ID to identify your key.
|
||||
|
||||
Real name: LorinLee
|
||||
Email address: lorinlee@apache.org
|
||||
Comment: lorinlee's key
|
||||
You selected this USER-ID:
|
||||
"LorinLee (lorinlee's key) <lorinlee@apache.org>"
|
||||
|
||||
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
|
||||
You need a Passphrase to protect your secret key. # 输入密码
|
||||
|
||||
We need to generate a lot of random bytes. It is a good idea to perform
|
||||
some other action (type on the keyboard, move the mouse, utilize the
|
||||
disks) during the prime generation; this gives the random number
|
||||
generator a better chance to gain enough entropy.
|
||||
gpg: key 92E18A11B6585834 marked as ultimately trusted
|
||||
gpg: revocation certificate stored as '/Users/lilei/.gnupg/openpgp-revocs.d/C30F211F071894258497F46392E18A11B6585834.rev'
|
||||
public and secret key created and signed.
|
||||
|
||||
pub rsa4096 2021-10-17 [SC]
|
||||
C30F211F071894258497F46392E18A11B6585834
|
||||
uid LorinLee (lorinlee's key) <lorinlee@apache.org>
|
||||
sub rsa4096 2021-10-17 [E]
|
||||
```
|
||||
|
||||
## 3. 查看生成的key
|
||||
|
||||
```bash
|
||||
gpg --list-keys
|
||||
```
|
||||
|
||||
执行结果:
|
||||
|
||||
```
|
||||
gpg: checking the trustdb
|
||||
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
|
||||
gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
|
||||
/Users/lilei/.gnupg/pubring.kbx
|
||||
----------------------------------
|
||||
pub rsa4096 2021-10-17 [SC]
|
||||
C30F211F071894258497F46392E18A11B6585834
|
||||
uid [ultimate] LorinLee (lorinlee's key) <lorinlee@apache.org>
|
||||
sub rsa4096 2021-10-17 [E]
|
||||
```
|
||||
|
||||
其中 `C30F211F071894258497F46392E18A11B6585834` 为公钥ID。
|
||||
|
||||
## 4. 将公钥公布到服务器
|
||||
|
||||
命令如下:
|
||||
|
||||
```bash
|
||||
gpg --keyserver hkp://pgp.mit.edu --send-key C30F211F071894258497F46392E18A11B6585834
|
||||
```
|
||||
|
||||
## 5. 生成 fingerprint 并上传到 apache 用户信息中
|
||||
由于公钥服务器没有检查机制,任何人都可以用你的名义上传公钥,所以没有办法保证服务器上的公钥的可靠性。通常,你可以在⽹站上公布一个公钥指纹,让其他⼈核对下载到的公钥是否为真。fingerprint参数生成公钥指纹。
|
||||
|
||||
执行如下命令查看 fingerprint:
|
||||
```
|
||||
gpg --fingerprint lorinlee(用户ID)
|
||||
```
|
||||
|
||||
输出如下:
|
||||
```
|
||||
/Users/lilei/.gnupg/pubring.kbx
|
||||
----------------------------------
|
||||
pub rsa4096 2021-10-17 [SC]
|
||||
C30F 211F 0718 9425 8497 F463 92E1 8A11 B658 5834
|
||||
uid [ultimate] LorinLee (lorinlee's key) <lorinlee@apache.org>
|
||||
sub rsa4096 2021-10-17 [E]
|
||||
```
|
||||
|
||||
将上面的 fingerprint 粘贴到⾃己的⽤户信息中: https://id.apache.org
|
||||
|
||||
# 发布包准备
|
||||
|
||||
## 1. 编辑 RELEASE_VERSION 文件
|
||||
|
||||
编辑项目根目录下`RELEASE_VERSION`文件,更新版本号,并提交至代码仓库,本文以`1.0.0`版本为例,文件内容为:
|
||||
|
||||
```
|
||||
1.0.0
|
||||
```
|
||||
|
||||
## 2. 创建发布 tag
|
||||
拉取发布分支,并推送tag
|
||||
```bash
|
||||
git clone -b ${branch} git@github.com:apache/incubator-brpc.git ~/incubator-brpc
|
||||
|
||||
cd ~/incubator-brpc
|
||||
|
||||
git tag -a 1.0.0 -m "release 1.0.0"
|
||||
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
## 3. 打包发布包
|
||||
|
||||
```bash
|
||||
git archive --format=tar 1.0.0 --prefix=apache-brpc-1.0.0-incubating-src/ | gzip > apache-brpc-1.0.0-incubating-src.tar.gz
|
||||
```
|
||||
|
||||
## 4. 生成签名文件
|
||||
|
||||
```bash
|
||||
gpg -u lorinlee@apache.org --armor --output apache-brpc-1.0.0-incubating-src.tar.gz.asc --detach-sign apache-brpc-1.0.0-incubating-src.tar.gz
|
||||
|
||||
gpg --verify apache-brpc-1.0.0-incubating-src.tar.gz.asc apache-brpc-1.0.0-incubating-src.tar.gz
|
||||
|
||||
```
|
||||
|
||||
## 5. 生成哈希文件
|
||||
|
||||
```bash
|
||||
sha512sum apache-brpc-1.0.0-incubating-src.tar.gz > apache-brpc-1.0.0-incubating-src.tar.gz.sha512
|
||||
|
||||
sha512sum --check apache-brpc-1.0.0-incubating-src.tar.gz.sha512
|
||||
```
|
||||
|
||||
# 发布至Apache SVN仓库
|
||||
|
||||
## 1. 检出 dist/dev 下的 brpc 仓库目录
|
||||
|
||||
如无本地工作目录,则先创建本地工作目录。将Apache SVN仓库克隆下来,username需要使用自己的Apache LDAP用户名
|
||||
|
||||
```bash
|
||||
mkdir -p ~/brpc_svn/dev/
|
||||
|
||||
cd ~/brpc_svn/dev/
|
||||
|
||||
svn --username=lorinlee co https://dist.apache.org/repos/dist/dev/incubator/brpc/
|
||||
|
||||
cd ~/brpc_svn/dev/brpc
|
||||
```
|
||||
|
||||
## 2. 添加GPG公钥
|
||||
|
||||
仅第一次部署的账号需要添加,只要KEYS中包含已经部署过的账户的公钥即可。
|
||||
|
||||
```
|
||||
gpg -a --export lorinlee >> KEYS
|
||||
```
|
||||
|
||||
## 3. 将待发布的代码包添加至SVN目录
|
||||
|
||||
```bash
|
||||
mkdir -p ~/brpc_svn/dev/brpc/1.0.0
|
||||
|
||||
cd ~/brpc_svn/dev/brpc/1.0.0
|
||||
|
||||
cp ~/incubator-brpc/apache-brpc-1.0.0-incubating-src.tar.gz ~/brpc_svn/dev/brpc/1.0.0
|
||||
|
||||
cp ~/incubator-brpc/apache-brpc-1.0.0-incubating-src.tar.gz.asc ~/brpc_svn/dev/brpc/1.0.0
|
||||
|
||||
cp ~/incubator-brpc/apache-brpc-1.0.0-incubating-src.tar.gz.sha512 ~/brpc_svn/dev/brpc/1.0.0
|
||||
```
|
||||
|
||||
## 4. 提交SVN
|
||||
|
||||
使用Apache LDAP账号提交SVN
|
||||
|
||||
```bash
|
||||
svn add *
|
||||
|
||||
svn --username=lorinlee commit -m "release 1.0.0"
|
||||
```
|
||||
|
||||
# 检查发布结果
|
||||
|
||||
## 1. 检查sha512哈希
|
||||
|
||||
```bash
|
||||
sha512sum --check apache-brpc-1.0.0-incubating-src.tar.gz.sha512
|
||||
```
|
||||
|
||||
## 2. 检查GPG签名
|
||||
首先导入发布人公钥。从svn仓库导入KEYS到本地环境。(发布版本的人不需要再导入,帮助做验证的人需要导入,用户名填发版人的即可)
|
||||
|
||||
```bash
|
||||
curl https://dist.apache.org/repos/dist/dev/incubator/brpc/KEYS >> KEYS
|
||||
|
||||
gpg --import KEYS
|
||||
```
|
||||
|
||||
设置信任该用户的签名,执行以下命令,填写发布人的用户名
|
||||
```bash
|
||||
gpg --edit-key lorinlee
|
||||
```
|
||||
|
||||
输出为
|
||||
```
|
||||
gpg (GnuPG) 2.3.1; Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
|
||||
Secret key is available.
|
||||
|
||||
gpg> trust
|
||||
|
||||
Please decide how far you trust this user to correctly verify other users' keys
|
||||
(by looking at passports, checking fingerprints from different sources, etc.)
|
||||
|
||||
1 = I don't know or won't say
|
||||
2 = I do NOT trust
|
||||
3 = I trust marginally
|
||||
4 = I trust fully
|
||||
5 = I trust ultimately
|
||||
m = back to the main menu
|
||||
|
||||
Your decision? 5
|
||||
Do you really want to set this key to ultimate trust? (y/N) y
|
||||
|
||||
gpg> save
|
||||
```
|
||||
|
||||
然后进行gpg签名检查。
|
||||
```
|
||||
gpg --verify apache-brpc-1.0.0-incubating-src.tar.gz.asc apache-brpc-1.0.0-incubating-src.tar.gz
|
||||
```
|
||||
|
||||
## 3. 检查发布内容
|
||||
|
||||
### 1. 对比源码包与github上的tag内容差异
|
||||
|
||||
```bash
|
||||
curl -Lo tag-1.0.0.tar.gz https://github.com/apache/incubator-brpc/archive/refs/tags/1.0.0.tar.gz
|
||||
|
||||
tar xvzf tag-1.0.0.tar.gz
|
||||
|
||||
tar xvzf apache-brpc-1.0.0-incubating-src.tar.gz
|
||||
|
||||
diff -r brpc-1.0.0 apache-brpc-1.0.0-incubating-src
|
||||
```
|
||||
|
||||
### 2. 检查源码包的文件内容
|
||||
|
||||
- 检查源码包是否包含由于包含不必要文件,致使tarball过于庞大
|
||||
- 存在LICENSE和NOTICE文件
|
||||
- NOTICE文件中的年份正确
|
||||
- 只存在文本文件,不存在二进制文件
|
||||
- 所有文件的开头都有ASF许可证
|
||||
- 能够正确编译,单元测试可以通过
|
||||
- 检查是否有多余文件或文件夹,例如空文件夹等
|
||||
- 检查第三方依赖许可证:
|
||||
- 第三方依赖的许可证兼容
|
||||
- 所有第三方依赖的许可证都在LICENSE文件中声名
|
||||
- 依赖许可证的完整版全部在license目录
|
||||
- 如果依赖的是Apache许可证并且存在NOTICE文件,那么这些NOTICE文件也需要加入到版本的NOTICE文件中
|
||||
|
||||
# 在Apache brpc社区发起投票
|
||||
|
||||
## 1. 投票阶段
|
||||
|
||||
1. brpc社区投票,发起投票邮件到dev@brpc.apache.org。PPMC需要先按文档检查版本的正确性,然后再进行投票。经过至少72小时并统计到3个+1 PPMC member票后,即可进入下一阶段。
|
||||
2. 宣布投票结果,发起投票结果邮件到dev@brpc.apache.org。
|
||||
|
||||
## 2. 投票邮件模板
|
||||
|
||||
1. Apache brpc 社区投票邮件模板
|
||||
|
||||
标题:
|
||||
```
|
||||
[VOTE] Release Apache brpc (Incubating) 1.0.0
|
||||
```
|
||||
|
||||
正文:
|
||||
```
|
||||
Hello Apache brpc (Incubating) Community,
|
||||
|
||||
This is a call for vote to release Apache brpc (Incubating) version
|
||||
1.0.0
|
||||
|
||||
[Release Note]
|
||||
- xxx
|
||||
|
||||
The release candidates:
|
||||
https://dist.apache.org/repos/dist/dev/incubator/brpc/1.0.0/
|
||||
|
||||
Git tag for the release:
|
||||
https://github.com/apache/incubator-brpc/releases/tag/1.0.0
|
||||
|
||||
Release Commit ID:
|
||||
https://github.com/apache/incubator-brpc/commit/xxx
|
||||
|
||||
Keys to verify the Release Candidate:
|
||||
https://dist.apache.org/repos/dist/dev/incubator/brpc/KEYS
|
||||
|
||||
The vote will be open for at least 72 hours or until necessary number of
|
||||
votes are reached.
|
||||
|
||||
Please vote accordingly:
|
||||
[ ] +1 approve
|
||||
[ ] +0 no opinion
|
||||
[ ] -1 disapprove with the reason
|
||||
|
||||
PMC vote is +1 binding, all others is +1 non-binding.
|
||||
|
||||
Checklist for reference:
|
||||
[ ] Download links are valid.
|
||||
[ ] Checksums and PGP signatures are valid.
|
||||
[ ] Source code distributions have correct names matching the current
|
||||
release.
|
||||
[ ] LICENSE and NOTICE files are correct for each brpc repo.
|
||||
[ ] All files have license headers if necessary.
|
||||
[ ] No compiled archives bundled in source archive.
|
||||
|
||||
Regards,
|
||||
LorinLee
|
||||
```
|
||||
|
||||
2. Apache brpc 社区宣布结果邮件模板
|
||||
|
||||
标题:
|
||||
```
|
||||
[Result] [VOTE] Release Apache brpc (Incubating) 1.0.0
|
||||
```
|
||||
|
||||
正文:
|
||||
```
|
||||
Hi all,
|
||||
|
||||
The vote to release Apache brpc (Incubating) 1.0.0 has passed.
|
||||
|
||||
The vote PASSED with 3 binding +1, 1 non binding +1 and 0 -1 votes:
|
||||
|
||||
Binding votes:
|
||||
- xxx
|
||||
- yyy
|
||||
- zzz
|
||||
|
||||
Non-binding votes:
|
||||
- aaa
|
||||
|
||||
Vote thread: xxx (vote email link in https://lists.apache.org/)
|
||||
|
||||
Thank you to all the above members to help us to verify and vote for the 1.0.0 release. We will move to IPMC voting shortly.
|
||||
|
||||
Regards,
|
||||
LorinLee
|
||||
```
|
||||
|
||||
## 3. 投票未通过
|
||||
|
||||
若社区投票未通过,则对代码仓库进行修改,重新打包,发起投票。
|
||||
|
||||
# 在Apache Incubator社区发起投票
|
||||
|
||||
## 1. 投票阶段
|
||||
|
||||
1. Incubator社区投票,发起投票邮件到general@incubator.apache.org。IPMC会进行投票。经过至少72小时并统计到3个+1 IPMC member票后,即可进入下一阶段。
|
||||
2. 宣布投票结果,发起投票结果邮件到general@incubator.apache.org。
|
||||
|
||||
## 2. 投票邮件模板
|
||||
|
||||
1. Apache Incubator 社区投票邮件模板
|
||||
|
||||
标题:
|
||||
```
|
||||
[VOTE] Release Apache brpc (Incubating) 1.0.0
|
||||
```
|
||||
|
||||
正文:
|
||||
```
|
||||
Hello IPMC,
|
||||
|
||||
The Apache brpc community has voted and approved the release of Apache
|
||||
brpc (Incubating) 1.0.0. We now kindly request the IPMC members
|
||||
review and vote for this release.
|
||||
|
||||
brpc is an industrial-grade RPC framework with extremely high performance,
|
||||
and it supports multiple protocols, full rpc features, and has many
|
||||
convenient tools. The current release provides the first official and
|
||||
stable package, resolves all of the license issues, and fixes many bugs.
|
||||
|
||||
brpc community vote thread: xxx
|
||||
|
||||
Vote result thread: xxx
|
||||
|
||||
The release candidate:
|
||||
https://dist.apache.org/repos/dist/dev/incubator/brpc/1.0.0/
|
||||
|
||||
This release has been signed with a PGP available here:
|
||||
https://dist.apache.org/repos/dist/dev/incubator/brpc/KEYS
|
||||
|
||||
Git tag for the release:
|
||||
https://github.com/apache/incubator-brpc/releases/tag/1.0.0
|
||||
|
||||
Build guide and get started instructions can be found at:
|
||||
https://github.com/apache/incubator-brpc/blob/master/docs/en/getting_started.md
|
||||
|
||||
The vote will be open for at least 72 hours or until the necessary number
|
||||
of votes is reached.
|
||||
|
||||
Please vote accordingly:
|
||||
[ ] +1 Approve the release of Apache brpc (Incubating) 1.0.0
|
||||
[ ] +0
|
||||
[ ] -1 Do not approve (please specify the reason)
|
||||
|
||||
Regards,
|
||||
Lorin Lee
|
||||
Apache brpc (Incubating)
|
||||
```
|
||||
|
||||
2. Apache Incubator 社区宣布结果邮件模板
|
||||
|
||||
标题:
|
||||
```
|
||||
[Result] [VOTE] Release Apache brpc (Incubating) 1.0.0
|
||||
```
|
||||
|
||||
正文:
|
||||
```
|
||||
Hello Incubator Community,
|
||||
|
||||
Thanks to everyone that participated. The vote to release Apache
|
||||
brpc (Incubating) version 1.0.0 in general@incuabator
|
||||
is now closed.
|
||||
|
||||
Vote thread: xxx (vote email link in https://lists.apache.org/)
|
||||
|
||||
The vote PASSED with 3 binding +1, 1 non binding +1 and 0 -1 votes:
|
||||
|
||||
Binding votes:
|
||||
- xxx
|
||||
- yyy
|
||||
- zzz
|
||||
|
||||
Non-binding votes:
|
||||
- aaa
|
||||
|
||||
I will be working on publishing the artifacts of Apache brpc
|
||||
(Incubating) 1.0.0 and post an announcement. Thanks!
|
||||
|
||||
Regards,
|
||||
Lorin Lee
|
||||
Apache brpc (Incubating)
|
||||
```
|
||||
|
||||
# 完成发布
|
||||
|
||||
## 1. 将发布包从Apache SVN仓库 dist/dev 移动至 dist/release
|
||||
|
||||
```
|
||||
svn mv https://dist.apache.org/repos/dist/dev/incubator/brpc/1.0.0 https://dist.apache.org/repos/dist/release/incubator/brpc/1.0.0 -m "release brpc 1.0.0"
|
||||
|
||||
svn delete https://dist.apache.org/repos/dist/release/incubator/brpc/KEYS -m "delete KEYS"
|
||||
|
||||
svn cp https://dist.apache.org/repos/dist/dev/incubator/brpc/KEYS https://dist.apache.org/repos/dist/release/incubator/brpc/KEYS -m "update brpc KEYS"
|
||||
```
|
||||
|
||||
## 2. Github版本发布
|
||||
|
||||
在 GitHub Releases 页面的对应版本上点击 Edit
|
||||
编辑版本号及版本说明,并点击 Publish release
|
||||
|
||||
## 3. 更新下载页面
|
||||
|
||||
等待并确认新的发布版本同步至 Apache 镜像后,更新如下页面:
|
||||
`https://brpc.apache.org/download/`,更新方式在 `https://github.com/apache/incubator-brpc-website/` 仓库中。
|
||||
|
||||
GPG签名文件和哈希校验文件的下载链接应该使用这个前缀:https://downloads.apache.org/incubator/brpc/
|
||||
|
||||
代码包的下载链接应该使用这个前缀:https://www.apache.org/dyn/closer.lua/incubator/brpc/
|
||||
|
||||
## 4. 发送邮件通知发布完成
|
||||
|
||||
发送邮件到dev@brpc.apache.org和announce@apache.org通知完成版本发布,通知邮件模板如下:
|
||||
|
||||
标题:
|
||||
```
|
||||
[ANNOUNCE] Apache brpc 1.0.0
|
||||
```
|
||||
|
||||
正文
|
||||
```
|
||||
Hi all,
|
||||
|
||||
The Apache brpc (incubating) community is pleased to announce that Apache
|
||||
brpc (incubating) 1.0.0 has been released!
|
||||
|
||||
brpc is an industrial-grade RPC framework with extremely high performance,
|
||||
and it supports multiple protocols, full rpc features, and has many
|
||||
convenient tools.
|
||||
|
||||
Brief notes of this release:
|
||||
- xxx
|
||||
- yyy
|
||||
|
||||
More details regarding Apache brpc can be found at:
|
||||
http://brpc.apache.org/
|
||||
|
||||
The release artifacts can be downloaded here:
|
||||
https://brpc.apache.org/download/
|
||||
|
||||
The release notes can be found here:
|
||||
https://github.com/apache/incubator-brpc/releases/tag/1.0.0
|
||||
|
||||
Thanks,
|
||||
Lorin Lee
|
||||
Apache brpc (Incubating)
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
# brpc 发版时候的Check List
|
||||
|
||||
## 文档背景:
|
||||
当Release Manager在dev邮件群中发起发布投票的时候,需要PMC成员对发版相关信息进行检查,如果检查通过则在邮件群中回复通过并附上检查结果。本文档就是各个检查项。
|
||||
|
||||
## Checklist 资料来源
|
||||
根据Incubator PMC Chair Justin在ApacheCon North America 2019的分享
|
||||
https://training.apache.org/topics/ApacheWay/NavigatingASFIncubator/index.html
|
||||
|
||||

|
||||
|
||||
|
||||
## 常见的问题导致-1
|
||||

|
||||
|
||||
## Vote时候的检查项
|
||||
1. Incubating in name 即下载包的文件名是否带上了incubating
|
||||
2. LICENSE and NOTICE are good
|
||||
- LICENSE是否符合Apache的要求
|
||||
- ASF允许的LICENSE:Category A(Apache V2,BSD 3,MIT etc)
|
||||
- ASF建议不放到源码中的LICENSE:Category B(EPL,MPL,CDDL,etc)
|
||||
- ASF不允许的LICENSE:Category X(GPL,LGPL,CC Non commercial,etc)
|
||||
- NOTICE是否符合Apache的要求
|
||||
3. Signatures and hashes correct
|
||||
4. All ASF files have ASF headers
|
||||
5. No unexpected binary files
|
||||
6. Must have an incubating disclaimer
|
||||
- Repo根目录下应该有DISCLAIMER文件
|
||||
- 内容是Apache统一的内容
|
||||
|
||||
|
||||
## Vote时候的常用回复
|
||||
|
||||
“+1 (binding)
|
||||
|
||||
I checked:
|
||||
- incubating in name
|
||||
- LICENSE and NOTICE are good
|
||||
- signatures and hashes correct
|
||||
- All ASF files have ASF headers
|
||||
- no unexpected binary files
|
||||
|
||||
## 注意:
|
||||
1. 不要回复简单的+1,需要加上执行的几个检查项和检查结果
|
||||
2. 给出-1的时候,同样需要给出明确的理由
|
||||
|
||||
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 223 KiB |
@@ -161,7 +161,7 @@ else
|
||||
OPENSSL_LIB=$(find_dir_of_lib ssl)
|
||||
# Inconvenient to check these headers in baidu-internal
|
||||
#PTHREAD_HDR=$(find_dir_of_header_or_die pthread.h)
|
||||
OPENSSL_HDR=$(find_dir_of_header_or_die openssl/ssl.h)
|
||||
OPENSSL_HDR=$(find_dir_of_header_or_die openssl/ssl.h mesalink/openssl/ssl.h)
|
||||
fi
|
||||
|
||||
if [ $WITH_MESALINK != 0 ]; then
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
```c++
|
||||
// Thread 1
|
||||
// ready was initialized to false
|
||||
// bool ready was initialized to false
|
||||
p.init();
|
||||
ready = true;
|
||||
```
|
||||
@@ -72,7 +72,7 @@ if (ready) {
|
||||
|
||||
```c++
|
||||
// Thread1
|
||||
// ready was initialized to false
|
||||
// std::atomic<bool> ready was initialized to false
|
||||
p.init();
|
||||
ready.store(true, std::memory_order_release);
|
||||
```
|
||||
|
||||
@@ -23,5 +23,14 @@ bthread_id的接口不太简洁,有不少API:
|
||||
|
||||
这么多接口是为了满足不同的使用流程。
|
||||
|
||||
- 发送request的流程:create -> lock -> ... register timer and send RPC ... -> unlock
|
||||
- 接收response的流程:lock -> ..process response -> call done
|
||||
- 发送request的流程:bthread_id_create -> bthread_id_lock -> ... register timer and send RPC ... -> bthread_id_unlock
|
||||
- 接收response的流程:bthread_id_lock -> ..process response -> bthread_id_unlock_and_destroy
|
||||
- 异常处理流程:timeout/socket fail -> bthread_id_error -> 执行on_error回调(这里会加锁),分两种情况
|
||||
- 请求重试/backup request: 重新register timer and send RPC -> bthread_id_unlock
|
||||
- 无法重试,最终失败:bthread_id_unlock_and_destroy
|
||||
- 同步等待RPC结束:bthread_id_join
|
||||
|
||||
为了减少等待,bthread_id做了一些优化的机制:
|
||||
|
||||
- error发生的时候,如果bthread_id已经被锁住,会把error信息放到一个pending queue中,bthread_id_error函数立即返回。当bthread_id_unlock的时候,如果pending queue里面有任务就取出来执行。
|
||||
- RPC结束的时候,如果存在用户回调,先执行一个bthread_id_about_to_destroy,让正在等待的bthread_id_lock操作立即失败,再执行用户回调(这个可能耗时较长,不可控),最后再执行bthread_id_unlock_and_destroy
|
||||
|
||||
@@ -54,7 +54,7 @@ foo::bar::g_task_pushed << 1;
|
||||
- `bvar::PerSecond<VAR>` : 获得某个bvar在一段时间内平均每秒的累加值。PerSecond也是会自动更新的衍生变量。
|
||||
- `bvar::LatencyRecorder` : 专用于记录延时和qps的变量。输入延时,平均延时/最大延时/qps/总次数 都有了。
|
||||
|
||||
**确认变量名是全局唯一的!**否则会曝光失败,如果-bvar_abort_on_same_name为true,程序会直接abort。
|
||||
**确认变量名是全局唯一的!** 否则会曝光失败,如果-bvar_abort_on_same_name为true,程序会直接abort。
|
||||
|
||||
程序中有来自各种模块不同的bvar,为避免重名,建议如此命名:**模块_类名_指标**
|
||||
|
||||
@@ -87,7 +87,7 @@ rpc_socket_count : 6 # 模块=rpc 类名=socket
|
||||
```c++
|
||||
namespace foo {
|
||||
namespace bar {
|
||||
// 注意g_read_error_minute和g_task_pushed_per_second都是衍生的bvar,会自动更新,不要声明。
|
||||
// 注意g_read_error_minute和g_task_pushed_second都是衍生的bvar,会自动更新,不要声明。
|
||||
extern bvar::Adder<int> g_read_error;
|
||||
extern bvar::LatencyRecorder g_write_latency;
|
||||
extern bvar::Adder<int> g_task_pushed;
|
||||
@@ -148,7 +148,7 @@ int expose_as(const butil::StringPiece& prefix, const butil::StringPiece& name);
|
||||
```
|
||||
全局曝光后的bvar名字便为name或prefix + name,可通过以_exposed为后缀的static函数查询。比如Variable::describe_exposed(name)会返回名为name的bvar的描述。
|
||||
|
||||
当相同名字的bvar已存在时,expose会打印FATAL日志并返回-1。如果选项**--bvar_abort_on_same_name**设为true (默认是false),程序会直接abort。
|
||||
当相同名字的bvar已存在时,expose会打印FATAL日志并返回-1。如果选项 **-bvar_abort_on_same_name**设为true (默认是false),程序会直接abort。
|
||||
|
||||
下面是一些曝光bvar的例子:
|
||||
```c++
|
||||
@@ -221,7 +221,7 @@ dump功能由如下gflags控制:
|
||||
| ------------------ | ----------------------- | ---------------------------------------- |
|
||||
| bvar_dump | false | Create a background thread dumping all bvar periodically, all bvar_dump_* flags are not effective when this flag is off |
|
||||
| bvar_dump_exclude | "" | Dump bvar excluded from these wildcards(separated by comma), empty means no exclusion |
|
||||
| bvar_dump_file | monitor/bvar.<app>.data | Dump bvar into this file |
|
||||
| bvar_dump_file | monitor/bvar.\<app\>.data | Dump bvar into this file |
|
||||
| bvar_dump_include | "" | Dump bvar matching these wildcards(separated by comma), empty means including all |
|
||||
| bvar_dump_interval | 10 | Seconds between consecutive dump |
|
||||
| bvar_dump_prefix | \<app\> | Every dumped name starts with this prefix |
|
||||
|
||||
@@ -22,11 +22,11 @@ option.enable_circuit_breaker = true;
|
||||
可选的熔断由CircuitBreaker实现,在开启了熔断之后,CircuitBreaker会记录每一个请求的处理结果,并维护一个累计出错时长,记为acc_error_cost,当acc_error_cost > max_error_cost时,熔断该节点。
|
||||
|
||||
**每次请求返回成功之后,更新max_error_cost:**
|
||||
1. 首先需要更新latency的EMA值,记为ema_latency: ema_latency = ema_latency * alpha + (1 - alpha) * latency。
|
||||
1. 首先需要更新latency的[EMA](https://en.wikipedia.org/wiki/Moving_average)值,记为ema_latency: ema_latency = ema_latency * alpha + (1 - alpha) * latency。
|
||||
2. 之后根据ema_latency更新max_error_cost: max_error_cost = window_size * max_error_rate * ema_latency。
|
||||
|
||||
|
||||
上面的window_size和max_error_rate均为gflag所指定的常量, alpha则是一个略小于1的常量,其值由window_size和下面提到的circuit_breaker_epsilon_value决定。latency则指该次请求所的耗时。
|
||||
上面的window_size和max_error_rate均为gflag所指定的常量, alpha则是一个略小于1的常量,其值由window_size和下面提到的circuit_breaker_epsilon_value决定。latency则指该次请求的耗时。
|
||||
|
||||
**每次请求返回之后,都会更新acc_error_cost:**
|
||||
1. 如果请求处理成功,则令 acc_error_cost = alpha * acc_error_cost
|
||||
@@ -40,7 +40,7 @@ option.enable_circuit_breaker = true;
|
||||
|
||||
为了允许某个节点在短时间内抖动,同时又能够剔除长期错误率较高的节点,CircuitBreaker同时维护了长短两个窗口,长窗口阈值较低,短窗口阈值较高。长窗口的主要作用是剔除那些长期错误率较高的服务。我们可以根据实际的qps及对于错误的容忍程度来调整circuit_breaker_long_window_size及circuit_breaker_long_window_error_percent。
|
||||
|
||||
短窗口则允许我们更加精细的控制熔断的灵敏度,在一些对抖动很敏感的场景,可以通过调整circuit_breaker_short_window_size和circuit_breaker_long_window_short_percent来缩短短窗口的长度、降低短窗口对于错误的容忍程度,使得出现抖动时能够快速对故障节点进行熔断。
|
||||
短窗口则允许我们更加精细的控制熔断的灵敏度,在一些对抖动很敏感的场景,可以通过调整circuit_breaker_short_window_size和circuit_breaker_short_window_error_percent来缩短短窗口的长度、降低短窗口对于错误的容忍程度,使得出现抖动时能够快速对故障节点进行熔断。
|
||||
|
||||
此外,circuit_breaker_epsilon_value可以调整窗口对于**连续抖动的容忍程度**,circuit_breaker_epsilon_value的值越低,计算公式中的alpha越小,acc_error_cost下降的速度就越快,当circuit_breaker_epsilon_value的值达到0.001时,若一整个窗口的请求都没有出错,那么正好可以把acc_error_cost降低到0。
|
||||
|
||||
|
||||
@@ -48,11 +48,15 @@ int Init(const char* server_addr, int port, const ChannelOptions* options);
|
||||
- 127.0.0.1:80
|
||||
- www.foo.com:8765
|
||||
- localhost:9000
|
||||
- [::1]:8080 # IPV6
|
||||
- unix:path.sock # Unix domain socket
|
||||
|
||||
不合法的"server_addr_and_port":
|
||||
- 127.0.0.1:90000 # 端口过大
|
||||
- 10.39.2.300:8000 # 非法的ip
|
||||
|
||||
关于IPV6和Unix domain socket的使用,详见 [EndPoint](endpoint.md)。
|
||||
|
||||
# 连接服务集群
|
||||
|
||||
```c++
|
||||
@@ -214,6 +218,8 @@ int main() {
|
||||
|
||||
即weighted round robin, 根据服务器列表配置的权重值来选择服务器。服务器被选到的机会正比于其权重值,并且该算法能保证同一服务器被选到的结果较均衡的散开。
|
||||
|
||||
实例的tag需要是表示权值的int32数字,如tag="50"。
|
||||
|
||||
### random
|
||||
|
||||
随机从列表中选择一台服务器,无需其他设置。和round robin类似,这个算法的前提也是服务器都是类似的。
|
||||
@@ -222,6 +228,8 @@ int main() {
|
||||
|
||||
即weighted random, 根据服务器列表配置的权重值来选择服务器,服务器被选到的机会正比于其权重值。
|
||||
|
||||
实例tag的要求同wrr。
|
||||
|
||||
### la
|
||||
|
||||
locality-aware,优先选择延时低的下游,直到其延时高于其他机器,无需其他设置。实现原理请查看[Locality-aware load balancing](lalb.md)。
|
||||
@@ -238,6 +246,8 @@ locality-aware,优先选择延时低的下游,直到其延时高于其他机
|
||||
|
||||
实现原理请查看[Consistent Hashing](consistent_hashing.md)。
|
||||
|
||||
其他lb不需要设置Controller.set_request_code(),如果调用了request_code也不会被lb使用,例如:lb=rr调用了Controller.set_request_code(),即使所有RPC的request_code都相同,也依然是rr。
|
||||
|
||||
### 从集群宕机后恢复时的客户端限流
|
||||
|
||||
集群宕机指的是集群中所有server都处于不可用的状态。由于健康检查机制,当集群恢复正常后,server会间隔性地上线。当某一个server上线后,所有的流量会发送过去,可能导致服务再次过载。若熔断开启,则可能导致其它server上线前该server再次熔断,集群永远无法恢复。作为解决方案,brpc提供了在集群宕机后恢复时的限流机制:当集群中没有可用server时,集群进入恢复状态,假设正好能服务所有请求的server数量为min_working_instances,当前集群可用的server数量为q,则在恢复状态时,client接受请求的概率为q/min_working_instances,否则丢弃;若一段时间hold_seconds内q保持不变,则把流量重新发送全部可用的server上,并离开恢复状态。在恢复阶段时,可以通过判断controller.ErrorCode()是否等于brpc::ERJECT来判断该次请求是否被拒绝,被拒绝的请求不会被框架重试。
|
||||
@@ -291,6 +301,12 @@ if (cntl->Failed()) {
|
||||
}
|
||||
```
|
||||
|
||||
> 警告: 请勿在持有pthread锁的情况下,调用brpc的同步CallMethod!否则很容易导致死锁。
|
||||
>
|
||||
> 解决方案(二选一):
|
||||
> 1. 将pthread锁换成bthread锁(bthread_mutex_t)
|
||||
> 1. 在CallMethod之前将锁释放
|
||||
|
||||
## 异步访问
|
||||
|
||||
指的是:给CallMethod传递一个额外的回调对象done,CallMethod在发出request后就结束了,而不是在RPC结束后。当server端返回response或发生错误(包括超时)时,done->Run()会被调用。对RPC的后续处理应该写在done->Run()里,而不是CallMethod后。
|
||||
@@ -299,7 +315,11 @@ if (cntl->Failed()) {
|
||||
|
||||
你可以独立地创建这些对象,并使用[NewCallback](#使用NewCallback)生成done,也可以把Response和Controller作为done的成员变量,[一起new出来](#继承google::protobuf::Closure),一般使用前一种方法。
|
||||
|
||||
**发起异步请求后Request和Channel也可以立刻析构**。这两样和response/controller是不同的。注意:这是说Channel的析构可以立刻发生在CallMethod**之后**,并不是说析构可以和CallMethod同时发生,删除正被另一个线程使用的Channel是未定义行为(很可能crash)。
|
||||
发起异步请求后Request可以立刻析构。(SelectiveChannel是个例外,SelectiveChannel情况下必须在请求处理完成后再释放request对象)
|
||||
|
||||
发起异步请求后Channel可以立刻析构。
|
||||
|
||||
注意:这是说Request/Channel的析构可以立刻发生在CallMethod**之后**,并不是说析构可以和CallMethod同时发生,删除正被另一个线程使用的Channel是未定义行为(很可能crash)。
|
||||
|
||||
### 使用NewCallback
|
||||
```c++
|
||||
@@ -322,7 +342,7 @@ MyService_Stub stub(&channel);
|
||||
MyRequest request; // 你不用new request,即使在异步访问中.
|
||||
request.set_foo(...);
|
||||
cntl->set_timeout_ms(...);
|
||||
stub.some_method(cntl, &request, response, google::protobuf::NewCallback(OnRPCDone, response, cntl));
|
||||
stub.some_method(cntl, &request, response, brpc::NewCallback(OnRPCDone, response, cntl));
|
||||
```
|
||||
由于protobuf 3把NewCallback设置为私有,r32035后brpc把NewCallback独立于[src/brpc/callback.h](https://github.com/brpc/brpc/blob/master/src/brpc/callback.h)(并增加了一些重载)。如果你的程序出现NewCallback相关的编译错误,把google::protobuf::NewCallback替换为brpc::NewCallback就行了。
|
||||
|
||||
@@ -505,7 +525,7 @@ Controller的特点:
|
||||
|
||||
## 线程数
|
||||
|
||||
和大部分的RPC框架不同,brpc中并没有独立的Client线程池。所有Channel和Server通过[bthread](http://wiki.baidu.com/display/RPC/bthread)共享相同的线程池. 如果你的程序同样使用了brpc的server, 仅仅需要设置Server的线程数。 或者可以通过[gflags](http://wiki.baidu.com/display/RPC/flags)设置[-bthread_concurrency](http://brpc.baidu.com:8765/flags/bthread_concurrency)来设置全局的线程数.
|
||||
和大部分的RPC框架不同,brpc中并没有独立的Client线程池。所有Channel和Server通过[bthread](bthread.md)共享相同的线程池. 如果你的程序同样使用了brpc的server, 仅仅需要设置Server的线程数。 或者可以通过[gflags](flags.md)设置[-bthread_concurrency](http://brpc.baidu.com:8765/flags/bthread_concurrency)来设置全局的线程数.
|
||||
|
||||
## 超时
|
||||
|
||||
@@ -519,7 +539,7 @@ Controller的特点:
|
||||
|
||||
## 重试
|
||||
|
||||
ChannelOptions.max_retry是该Channel上所有RPC的默认最大重试次数,Controller.set_max_retry()可修改某次RPC的值,默认值3,0表示不重试。
|
||||
ChannelOptions.max_retry是该Channel上所有RPC的默认最大重试次数,默认值3,0表示不重试。Controller.set_max_retry()可修改某次RPC的值。
|
||||
|
||||
r32111后Controller.retried_count()返回重试次数。
|
||||
|
||||
@@ -751,11 +771,11 @@ set_request_compress_type()设置request的压缩方式,默认不压缩。
|
||||
|
||||
注意:附件不会被压缩。
|
||||
|
||||
http/h2 body的压缩方法见[client压缩request body](http_client#压缩request-body)。
|
||||
http/h2 body的压缩方法见[client压缩request body](http_client.md#压缩request-body)。
|
||||
|
||||
支持的压缩方法有:
|
||||
|
||||
- brpc::CompressTypeSnappy : [snanpy压缩](http://google.github.io/snappy/),压缩和解压显著快于其他压缩方法,但压缩率最低。
|
||||
- brpc::CompressTypeSnappy : [snappy压缩](http://google.github.io/snappy/),压缩和解压显著快于其他压缩方法,但压缩率最低。
|
||||
- brpc::CompressTypeGzip : [gzip压缩](http://en.wikipedia.org/wiki/Gzip),显著慢于snappy,但压缩率高
|
||||
- brpc::CompressTypeZlib : [zlib压缩](http://en.wikipedia.org/wiki/Zlib),比gzip快10%~20%,压缩率略好于gzip,但速度仍明显慢于snappy。
|
||||
|
||||
@@ -797,7 +817,7 @@ http/h2 body的压缩方法见[client压缩request body](http_client#压缩reque
|
||||
|
||||
### Q: brpc能用unix domain socket吗
|
||||
|
||||
不能。同机TCP socket并不走网络,相比unix domain socket性能只会略微下降。一些不能用TCP socket的特殊场景可能会需要,以后可能会扩展支持。
|
||||
支持,参考 [EndPoint](endpoint.md).
|
||||
|
||||
### Q: Fail to connect to xx.xx.xx.xx:xxxx, Connection refused
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ brpc可以分析程序中的热点函数。
|
||||
1. 链接`libtcmalloc_and_profiler.a`
|
||||
1. 这么写也开启了tcmalloc,不建议单独链接cpu profiler而不链接tcmalloc,可能越界访问导致[crash](https://github.com/gperftools/gperftools/blob/master/README#L226).可能由于tcmalloc不及时归还内存,越界访问不会crash。
|
||||
2. 如果tcmalloc使用frame pointer而不是libunwind回溯栈,请确保在CXXFLAGS或CFLAGS中加上`-fno-omit-frame-pointer`,否则函数间的调用关系会丢失,最后产生的图片中都是彼此独立的函数方框。
|
||||
2. 定义宏BRPC_ENABLE_CPU_PROFILER, 一般加入编译参数-DBRPC_ENABLE_CPU_PROFILER。
|
||||
2. 定义宏BRPC_ENABLE_CPU_PROFILER, 一般加入编译参数-DBRPC_ENABLE_CPU_PROFILER。注意:BRPC_ENABLE_CPU_PROFILER宏需要定义在引用到brpc头文件(channel.h或server.h)的代码里。比如A模块引用B模块,B模块在实现中引用brpc头文件,必须在B模块的编译参数加上BRPC_ENABLE_CPU_PROFILER宏,在A模块加是没用的。
|
||||
3. 如果只是brpc client或没有使用brpc,看[这里](dummy_server.md)。
|
||||
|
||||
注意要关闭Server端的认证,否则可能会看到这个:
|
||||
@@ -23,6 +23,21 @@ FATAL: 12-26 10:01:25: * 0 [src/brpc/policy/giano_authenticator.cpp:65][429496
|
||||
WARNING: 12-26 10:01:25: * 0 [src/brpc/input_messenger.cpp:132][4294969345] Authentication failed, remote side(127.0.0.1:22989) of sockfd=5, close it
|
||||
```
|
||||
|
||||
# 查看方法
|
||||
|
||||
1. 通过builtin service的 /hotspots/cpu 页面查看
|
||||
1. 通过pprof 工具查看,如 tools/pprof --text localhost:9002/pprof/profile
|
||||
|
||||
# 控制采样频率
|
||||
|
||||
启动前设置环境变量:export CPUPROFILE_FREQUENCY=xxx
|
||||
|
||||
默认值为: 100
|
||||
|
||||
# 控制采样时间
|
||||
|
||||
url加上?seconds=秒数,如/hotspots/cpu?seconds=5
|
||||
|
||||
# 图示
|
||||
|
||||
下图是一次运行cpu profiler后的结果:
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# UDS及IPV6支持
|
||||
|
||||
butil::EndPoint已经支持UDS(Unix Domain Socket)及IPV6。
|
||||
|
||||
## 基本用法
|
||||
代码用法:
|
||||
|
||||
```cpp
|
||||
EndPoint ep;
|
||||
str2endpoint("unix:path.sock", &ep); // 初始化一个UDS的EndPoint
|
||||
str2endpoint("[::1]:8086", &ep); // 初始化一个IPV6的EndPoint
|
||||
str2endpoint("[::1]", 8086, &ep); // 初始化一个IPV6的EndPoint
|
||||
|
||||
// 获取EndPoint的类型
|
||||
sa_family_t type = get_endpoint_type(ep); // 可能为AF_INET、AF_INET6或AF_UNIX
|
||||
|
||||
// 使用EndPoint,和原来的方式一样
|
||||
LOG(DEBUG) << ep; // 打印EndPoint
|
||||
std::string ep_str = endpoint2str(ep).c_str(); // EndPoint转str
|
||||
tcp_listen(ep); // 用监听EndPoint表示的tcp端口
|
||||
tcp_connect(ep, NULL); // 用连接EndPoint表示的tcp端口
|
||||
|
||||
sockaddr_storage ss;
|
||||
socklen_t socklen = 0;
|
||||
endpoint2sockaddr(ep, &ss, &socklen); // 将EndPoint转为sockaddr结构,以便调用系统函数
|
||||
```
|
||||
|
||||
## 在brpc中使用UDS或IPV6
|
||||
|
||||
只需要在原来输入IPV4字符串的时候,填写UDS路径或IPV6地址即可,如:
|
||||
|
||||
```cpp
|
||||
server.Start("unix:path.sock", options); // 启动server监听UDS地址
|
||||
server.Start("[::0]:8086", options); // 启动server监听IPV6地址
|
||||
|
||||
channel.Init("unix:path.sock", options); // 初始化single server的Channel,访问UDS地址
|
||||
channel.Init("list://[::1]:8086,[::1]:8087", "rr", options); // 初始化带LB的Channel,访问IPV6地址
|
||||
```
|
||||
|
||||
通过 example/echo_c++ ,展示了如何使用UDS或IPV6:
|
||||
|
||||
```bash
|
||||
./echo_server -listen_addr='unix:path.sock' & # 启动Server监听UDS地址
|
||||
./echo_server -listen_addr='[::0]:8080' & # 启动Server监听IPV6端口
|
||||
|
||||
./echo_client -server='unix:path.sock' # 启动Client访问UDS地址
|
||||
./echo_client -server='[::1]:8080' # 启动Client访问IPV6端口
|
||||
```
|
||||
|
||||
## 限制
|
||||
|
||||
由于EndPoint结构被广泛地使用,为了保证对存量代码的兼容性(包括ABI兼容性),目前采用的实现方式是不修改EndPoint的ABI定义,使用原来的ip字段作为id,port字段来做为扩展标记,把真正的信息存在一个外部的数据结构中。
|
||||
|
||||
这种实现方式对于现存的仅使用IPV4的代码是完全兼容的,但对于使用UDS或IPV6的用户,有些代码是不兼容的,比如直接访问EndPoint的ip和port成员的代码。
|
||||
|
||||
关于UDS和IPV6,目前已知的一些限制:
|
||||
|
||||
- 不兼容rpcz
|
||||
- 不支持使用PortRange方式启动server
|
||||
- 不支持在ServerOption中指定internal_port
|
||||
- IPV6不支持link local地址(fe80::开头的地址)
|
||||
@@ -26,8 +26,9 @@ brpc中常见错误的打印内容列表如下:
|
||||
| 错误码 | 数值 | 重试 | 说明 | 日志 |
|
||||
| -------------- | ---- | ---- | ---------------------------------------- | ---------------------------------------- |
|
||||
| EAGAIN | 11 | 是 | 同时发送的请求过多。软限,很少出现。 | Resource temporarily unavailable |
|
||||
| ENODATA | 61 | 是 | 1. Naming Service返回的server列表为空 2. Naming Service某次变更时,所有实例都发生了修改,Naming Service更新LB的逻辑是先Remove再Add,会存在很短时间内LB实例列表为空的情况 | Fail to select server from xxx |
|
||||
| ETIMEDOUT | 110 | 是 | 连接超时。 | Connection timed out |
|
||||
| EHOSTDOWN | 112 | 是 | 找不到可用的server。server可能停止服务了,也可能正在退出中(返回了ELOGOFF)。 | "Fail to select server from …" "Not connected to … yet" |
|
||||
| EHOSTDOWN | 112 | 是 | 可能原因:一、Naming Server返回的列表不为空,但LB选不出可用的server,LB返回了EHOSTDOWN错误。具体可能原因:a.Server正在退出中(返回了ELOGOFF) b. Server因为之前的某种失败而被封禁,封禁的具体逻辑:1. 对于单连接,唯一的连接socket被SetFail即封禁,SetFail在代码里出现非常多,有很多种可能性触发 2. 对于连接池/短连接,只有错误号满足does_error_affect_main_socket时(ECONNREFUSED,ENETUNREACH,EHOSTUNREACH或EINVAL)才会封禁 3. 封禁之后,有CheckHealth线程健康检查,就是尝试去连接一下,检查间隔由SocketOptions的health_check_interval_s控制,检查正常会解封。二、使用SingleServer方式初始化Channel(没有LB),唯一的一个连接为LOGOFF或者封禁状态(同上) | "Fail to select server from …" "Not connected to … yet" |
|
||||
| ENOSERVICE | 1001 | 否 | 找不到服务,不太出现,一般会返回ENOMETHOD。 | |
|
||||
| ENOMETHOD | 1002 | 否 | 找不到方法。 | 形式广泛,常见如"Fail to find method=..." |
|
||||
| EREQUEST | 1003 | 否 | request序列化错误,client端和server端都可能设置 | 形式广泛:"Missing required fields in request: …" "Fail to parse request message, …" "Bad request" |
|
||||
|
||||
@@ -112,7 +112,7 @@ template <typename T>
|
||||
int execution_queue_join(ExecutionQueueId<T> id);
|
||||
```
|
||||
|
||||
stop和join都可以多次调用, 都会又合理的行为。stop可以随时调用而不用当心线程安全性问题。
|
||||
stop和join都可以多次调用, 都会有合理的行为。stop可以随时调用而不用当心线程安全性问题。
|
||||
|
||||
和fd的close类似,如果stop不被调用, 相应的资源会永久泄露。
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ brpc使用gflags管理配置。如果你的程序也使用gflags,那么你应
|
||||
|
||||
# Usage of gflags
|
||||
|
||||
gflags一般定义在需要它的源文件中。#include <gflags/gflags.h>后在全局scope加入DEFINE_*<type>*(*<name>*, *<default-value>*, *<description>*); 比如:
|
||||
gflags一般定义在需要它的源文件中。#include <gflags/gflags.h>后在全局scope加入DEFINE_*\<type\>*(*\<name\>*, *\<default-value\>*, *\<description\>*); 比如:
|
||||
|
||||
```c++
|
||||
#include <gflags/gflags.h>
|
||||
@@ -43,9 +43,9 @@ conf/gflags.conf: No such file or directory
|
||||
|
||||
# flagfile
|
||||
|
||||
在命令行中参数和值之间可不加等号,而在flagfile中一定要加。比如`./myapp -param 7`是ok的,但在`./myapp -flagfile=./gflags.conf`对应的gflags.conf中一定要写成**-param=7**或**--param=7**,否则就不正确且不会报错。
|
||||
在命令行中参数和值之间可不加等号,而在flagfile中一定要加。比如`./myapp -param 7`是ok的,但在`./myapp -flagfile=./gflags.conf`对应的gflags.conf中一定要写成 **-param=7** 或 **--param=7**,否则就不正确且不会报错。
|
||||
|
||||
在命令行中字符串可用单引号或双引号包围,而在flagfile中不能加。比如`./myapp -name="tom"`或`./myapp -name='tom'`都是ok的,但在`./myapp -flagfile=./gflags.conf`对应的gflags.conf中一定要写成**-name=tom**或**--name=tom**,如果写成-name="tom"的话,引号也会作为值的一部分。配置文件中的值可以有空格,比如gflags.conf中写成-name=value with spaces是ok的,参数name的值就是value with spaces,而在命令行中要用引号括起来。
|
||||
在命令行中字符串可用单引号或双引号包围,而在flagfile中不能加。比如`./myapp -name="tom"`或`./myapp -name='tom'`都是ok的,但在`./myapp -flagfile=./gflags.conf`对应的gflags.conf中一定要写成 **-name=tom** 或 **--name=tom**,如果写成-name="tom"的话,引号也会作为值的一部分。配置文件中的值可以有空格,比如gflags.conf中写成-name=value with spaces是ok的,参数name的值就是value with spaces,而在命令行中要用引号括起来。
|
||||
|
||||
flagfile中参数可由单横线(如-foo)或双横线(如--foo)打头,但不能以三横线或更多横线打头,否则的话是无效参数且不会报错!
|
||||
|
||||
|
||||
@@ -1,59 +1,61 @@
|
||||
# BUILD
|
||||
[English version](../en/getting_started.md)
|
||||
|
||||
brpc prefers static linkages of deps, so that they don't have to be installed on every machine running the app.
|
||||
# 构建
|
||||
|
||||
brpc depends on following packages:
|
||||
brpc鼓励静态链接依赖,以便于每个运行brpc服务的机器不必再安装依赖。
|
||||
|
||||
brpc有如下依赖:
|
||||
|
||||
* [gflags](https://github.com/gflags/gflags): Extensively used to define global options.
|
||||
* [protobuf](https://github.com/google/protobuf): Serializations of messages, interfaces of services.
|
||||
* [leveldb](https://github.com/google/leveldb): Required by [/rpcz](rpcz.md) to record RPCs for tracing.
|
||||
* [leveldb](https://github.com/google/leveldb): Required by [rpcz](rpcz.md) to record RPCs for tracing.
|
||||
|
||||
# Supported Environment
|
||||
# 支持的环境
|
||||
|
||||
* [Ubuntu/LinuxMint/WSL](#ubuntulinuxmintwsl)
|
||||
* [Fedora/CentOS](#fedoracentos)
|
||||
* [Linux with self-built deps](#linux-with-self-built-deps)
|
||||
* [自己构建依赖的Linux](#自己构建依赖的Linux)
|
||||
* [MacOS](#macos)
|
||||
|
||||
## Ubuntu/LinuxMint/WSL
|
||||
### Prepare deps
|
||||
### 依赖准备
|
||||
|
||||
Install common deps, [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
安装通用依赖,[gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
sudo apt-get install -y git g++ make libssl-dev libgflags-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev
|
||||
```
|
||||
|
||||
If you need to statically link leveldb:
|
||||
如果你需要静态链接leveldb:
|
||||
```shell
|
||||
sudo apt-get install -y libsnappy-dev
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
如果你要在样例中启用cpu/heap的profiler:
|
||||
```shell
|
||||
sudo apt-get install -y libgoogle-perftools-dev
|
||||
```
|
||||
|
||||
If you need to run tests, install and compile libgtest-dev (which is not compiled yet):
|
||||
如果你要运行测试,那么要安装并编译libgtest-dev(它没有被默认编译):
|
||||
```shell
|
||||
sudo apt-get install -y cmake libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libgtest* /usr/lib/ && cd -
|
||||
```
|
||||
The directory of gtest source code may be changed, try `/usr/src/googletest/googletest` if `/usr/src/gtest` is not there.
|
||||
gtest源码目录可能变动,如果`/usr/src/gtest`不存在,请尝试`/usr/src/googletest/googletest`。
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
git clone brpc, cd into the repo and run
|
||||
### 使用config_brpc.sh编译brpc
|
||||
git克隆brpc,进入到项目目录,然后运行
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers=/usr/include --libs=/usr/lib
|
||||
$ make
|
||||
```
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
修改编译器为clang,添加选项`--cxx=clang++ --cc=clang`。
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
不想链接调试符号,添加选项`--nodebugsymbols`,然后编译将会得到更轻量的二进制文件。
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
使用glog版的brpc,添加选项`--with-glog`。
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
要启用 [thrift 支持](../en/thrift.md),首先安装thrift并且添加选项`--with-thrift`。
|
||||
|
||||
**Run example**
|
||||
**运行样例**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
@@ -62,30 +64,30 @@ $ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
上述操作会链接brpc的静态库到样例中,如果你想链接brpc的共享库,请依次执行:`make clean`和`LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
**运行测试**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
### 使用cmake编译brpc
|
||||
```shell
|
||||
cmake -B build && cmake --build build -j6
|
||||
```
|
||||
To help VSCode or Emacs(LSP) to understand code correctly, add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate `compile_commands.json`
|
||||
要帮助VSCode或Emacs(LSP)去正确地理解代码,添加`-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`选项去生成`compile_commands.json`。
|
||||
|
||||
To change compiler to clang, overwrite environment variable `CC` and `CXX` to `clang` and `clang++` respectively.
|
||||
要修改编译器为clang,请修改环境变量`CC`和`CXX`为`clang`和`clang++`。
|
||||
|
||||
To not link debugging symbols, remove `build/CMakeCache.txt` and cmake with `-DWITH_DEBUG_SYMBOLS=OFF`
|
||||
不想链接调试符号,请移除`build/CMakeCache.txt`,然后用`-DWITH_DEBUG_SYMBOLS=OFF`选项执行cmake。
|
||||
|
||||
To use brpc with glog, cmake with `-DWITH_GLOG=ON`.
|
||||
想要让brpc使用glog,用`-DWITH_GLOG=ON`选项执行cmake。
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and cmake with `-DWITH_THRIFT=ON`.
|
||||
要启用 [thrift 支持](../en/thrift.md),先安装thrift,然后用`-DWITH_THRIFT=ON`选项执行cmake。
|
||||
|
||||
**Run example with cmake**
|
||||
**用cmake运行样例**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
@@ -93,9 +95,10 @@ $ cmake -B build && cmake --build build -j4
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
Examples link brpc statically, if you need to link the shared version, remove `CMakeCache.txt` and cmake with `-DLINK_SO=ON`
|
||||
|
||||
**Run tests**
|
||||
上述操作会链接brpc的静态库到样例中,如果你想链接brpc的共享库,请先移除`CMakeCache.txt`,然后用`-DLINK_SO=ON`选项重新执行cmake。
|
||||
|
||||
**运行测试**
|
||||
|
||||
```shell
|
||||
$ mkdir build && cd build && cmake -DBUILD_UNIT_TESTS=ON .. && make && make test
|
||||
@@ -103,50 +106,50 @@ $ mkdir build && cd build && cmake -DBUILD_UNIT_TESTS=ON .. && make && make test
|
||||
|
||||
## Fedora/CentOS
|
||||
|
||||
### Prepare deps
|
||||
### 依赖准备
|
||||
|
||||
CentOS needs to install EPEL generally otherwise many packages are not available by default.
|
||||
CentOS一般需要安装EPEL,否则很多包都默认不可用。
|
||||
```shell
|
||||
sudo yum install epel-release
|
||||
```
|
||||
|
||||
Install common deps:
|
||||
安装通用依赖:
|
||||
```shell
|
||||
sudo yum install git gcc-c++ make openssl-devel
|
||||
```
|
||||
|
||||
Install [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
安装 [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
sudo yum install gflags-devel protobuf-devel protobuf-compiler leveldb-devel
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
如果你要在样例中启用cpu/heap的profiler:
|
||||
```shell
|
||||
sudo yum install gperftools-devel
|
||||
```
|
||||
|
||||
If you need to run tests, install and compile gtest-devel (which is not compiled yet):
|
||||
如果你要运行测试,那么要安装ligtest-dev:
|
||||
```shell
|
||||
sudo yum install gtest-devel
|
||||
```
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
### 使用config_brpc.sh编译brpc
|
||||
|
||||
git clone brpc, cd into the repo and run
|
||||
git克隆brpc,进入项目目录然后执行:
|
||||
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers=/usr/include --libs=/usr/lib64
|
||||
$ sh config_brpc.sh --headers="/usr/include" --libs="/usr/lib64 /usr/bin"
|
||||
$ make
|
||||
```
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
修改编译器为clang,添加选项`--cxx=clang++ --cc=clang`。
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
不想链接调试符号,添加选项`--nodebugsymbols` 然后编译将会得到更轻量的二进制文件。
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
想要让brpc使用glog,添加选项:`--with-glog`。
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
要启用 [thrift 支持](../en/thrift.md),先安装thrift,然后添加选项:`--with-thrift`。
|
||||
|
||||
**Run example**
|
||||
**运行样例**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
@@ -155,50 +158,50 @@ $ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
上述操作会链接brpc的静态库到样例中,如果你想链接brpc的共享库,请依次执行:`make clean`和`LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
**运行测试**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
### 使用cmake编译brpc
|
||||
参考[这里](#使用cmake编译brpc)
|
||||
|
||||
## Linux with self-built deps
|
||||
## 自己构建依赖的Linux
|
||||
|
||||
### Prepare deps
|
||||
### 依赖准备
|
||||
|
||||
brpc builds itself to both static and shared libs by default, so it needs static and shared libs of deps to be built as well.
|
||||
brpc默认会构建出静态库和共享库,因此它也需要依赖有静态库和共享库两个版本。
|
||||
|
||||
Take [gflags](https://github.com/gflags/gflags) as example, which does not build shared lib by default, you need to pass options to `cmake` to change the behavior:
|
||||
以[gflags](https://github.com/gflags/gflags)为例,它默认不构建共享库,你需要给`cmake`指定选项去改变这一行为:
|
||||
```shell
|
||||
$ cmake . -DBUILD_SHARED_LIBS=1 -DBUILD_STATIC_LIBS=1
|
||||
$ make
|
||||
```
|
||||
|
||||
### Compile brpc
|
||||
### 编译brpc
|
||||
|
||||
Keep on with the gflags example, let `../gflags_dev` be where gflags is cloned.
|
||||
还以gflags为例,`../gflags_dev`表示gflags被克隆的位置。
|
||||
|
||||
git clone brpc. cd into the repo and run
|
||||
git克隆brpc。进入到项目目录然后运行:
|
||||
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers="../gflags_dev /usr/include" --libs="../gflags_dev /usr/lib64"
|
||||
$ make
|
||||
```
|
||||
|
||||
Here we pass multiple paths to `--headers` and `--libs` to make the script search for multiple places. You can also group all deps and brpc into one directory, then pass the directory to --headers/--libs which actually search all subdirectories recursively and will find necessary files.
|
||||
这里我们给`--headers`和`--libs`传递多个路径使得脚本能够在多个地方进行检索。你也可以打包所有依赖和brpc一起放到一个目录中,然后把目录传递给 --headers/--libs选项,它会递归搜索所有子目录直到找到必须的文件。
|
||||
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
修改编译器为clang,添加选项`--cxx=clang++ --cc=clang`。
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
不想链接调试符号,添加选项`--nodebugsymbols`,然后编译将会得到更轻量的二进制文件。
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
使用glog版的brpc,添加选项`--with-glog`。
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
要启用[thrift 支持](../en/thrift.md),首先安装thrift并且添加选项`--with-thrift`。
|
||||
|
||||
```shell
|
||||
$ ls my_dev
|
||||
@@ -208,49 +211,49 @@ $ sh config_brpc.sh --headers=.. --libs=..
|
||||
$ make
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
### 使用cmake编译brpc
|
||||
参考[这里](#使用cmake编译brpc)
|
||||
|
||||
## MacOS
|
||||
|
||||
Note: In the same running environment, the performance of the current Mac version is about 2.5 times worse than the Linux version. If your service is performance-critical, do not use MacOS as your production environment.
|
||||
注意:在相同运行环境下,当前Mac版brpc的性能比Linux版差2.5倍。如果你的服务是性能敏感的,请不要使用MacOs作为你的生产环境。
|
||||
|
||||
### Prepare deps
|
||||
### 依赖准备
|
||||
|
||||
Install common deps:
|
||||
安装通用依赖:
|
||||
```shell
|
||||
brew install openssl git gnu-getopt coreutils
|
||||
```
|
||||
|
||||
Install [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
安装[gflags](https://github.com/gflags/gflags),[protobuf](https://github.com/google/protobuf),[leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
brew install gflags protobuf leveldb
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
如果你要在样例中启用cpu/heap的profiler:
|
||||
```shell
|
||||
brew install gperftools
|
||||
```
|
||||
|
||||
If you need to run tests, download and compile googletest (which is not compiled yet):
|
||||
如果你要运行测试,那么要安装并编译googletest(它没有被默认编译):
|
||||
```shell
|
||||
git clone https://github.com/google/googletest -b release-1.10.0 && cd googletest/googletest && mkdir build && cd build && cmake -DCMAKE_CXX_FLAGS="-std=c++11" .. && make
|
||||
```
|
||||
After the compilation, copy include/ and lib/ into /usr/local/include and /usr/local/lib respectively to expose gtest to all apps
|
||||
在编译完成后,复制include/和lib/目录到/usr/local/include和/usr/local/lib目录中,以便于让所有应用都能使用gtest。
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
git clone brpc, cd into the repo and run
|
||||
### 使用config_brpc.sh编译brpc
|
||||
git克隆brpc,进入到项目目录然后运行:
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers=/usr/local/include --libs=/usr/local/lib --cc=clang --cxx=clang++
|
||||
$ make
|
||||
```
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
不想链接调试符号,添加选项`--nodebugsymbols`,然后编译将会得到更轻量的二进制文件。
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
使用glog版的brpc,添加选项`--with-glog`。
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
要启用[thrift 支持](../en/thrift.md),首先安装thrift并且添加选项`--with-thrift`。
|
||||
|
||||
**Run example**
|
||||
**运行样例**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
@@ -258,85 +261,84 @@ $ make
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
上述操作会链接brpc的静态库到样例中,如果你想链接brpc的共享库,请依次执行:`make clean`和`LINK_SO=1 make`
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
**运行测试**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
### 使用cmake编译brpc
|
||||
参考[这里](#使用cmake编译brpc)
|
||||
|
||||
# Supported deps
|
||||
# 支持的依赖
|
||||
|
||||
## GCC: 4.8-7.1
|
||||
|
||||
c++11 is turned on by default to remove dependencies on boost (atomic).
|
||||
c++11被默认启用,以去除去boost的依赖(比如atomic)。
|
||||
|
||||
The over-aligned issues in GCC7 is suppressed temporarily now.
|
||||
GCC7中over-aligned的问题暂时被禁止。
|
||||
|
||||
Using other versions of gcc may generate warnings, contact us to fix.
|
||||
使用其他版本的gcc可能会产生编译警告,请联系我们予以修复。
|
||||
|
||||
Adding `-D__const__=` to cxxflags in your makefiles is a must to avoid [errno issue in gcc4+](thread_local.md).
|
||||
请在makefile中给cxxflags增加`-D__const__=`选项以避免[gcc4+中的errno问题](thread_local.md).
|
||||
|
||||
## Clang: 3.5-4.0
|
||||
|
||||
no known issues.
|
||||
无已知问题。
|
||||
|
||||
## glibc: 2.12-2.25
|
||||
|
||||
no known issues.
|
||||
无已知问题。
|
||||
|
||||
## protobuf: 2.4+
|
||||
|
||||
Be compatible with pb 3.x and pb 2.x with the same file:
|
||||
Don't use new types in proto3 and start the proto file with `syntax="proto2";`
|
||||
[tools/add_syntax_equal_proto2_to_all.sh](https://github.com/brpc/brpc/blob/master/tools/add_syntax_equal_proto2_to_all.sh)can add `syntax="proto2"` to all proto files without it.
|
||||
同一个文件兼容pb 3.x版本和pb 2.x版本:
|
||||
不要使用proto3新增的类型,并且在proto文件的起始位置添加`syntax=proto2;`声明。
|
||||
[tools/add_syntax_equal_proto2_to_all.sh](https://github.com/brpc/brpc/blob/master/tools/add_syntax_equal_proto2_to_all.sh)这个脚本可以给所有没有这行声明的proto文件添加`syntax="proto2"`声明。
|
||||
|
||||
Arena in pb 3.x is not supported yet.
|
||||
pb 3.x中的Arena至今没被支持。
|
||||
|
||||
## gflags: 2.0-2.2.1
|
||||
|
||||
no known issues.
|
||||
无已知问题。
|
||||
|
||||
## openssl: 0.97-1.1
|
||||
|
||||
required by https.
|
||||
被https功能需要。
|
||||
|
||||
## tcmalloc: 1.7-2.5
|
||||
|
||||
brpc does **not** link [tcmalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html) by default. Users link tcmalloc on-demand.
|
||||
brpc默认**不**链接 [tcmalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html)。用户按需要链接tcmalloc。
|
||||
|
||||
Comparing to ptmalloc embedded in glibc, tcmalloc often improves performance. However different versions of tcmalloc may behave really differently. For example, tcmalloc 2.1 may make multi-threaded examples in brpc perform significantly worse(due to a spinlock in tcmalloc) than the one using tcmalloc 1.7 and 2.5. Even different minor versions may differ. When you program behave unexpectedly, remove tcmalloc or try another version.
|
||||
和glibc内置的ptmalloc相比,tcmalloc通常能提升性能。然而不同版本的tcmalloc可能表现迥异。例如:tcmalloc 2.1与 tcmalloc 1.7和2.5相比,可能会让brpc的多线程样例性能显著恶化(tcmalloc中的一个自旋锁导致的)。甚至不同的小版本号之间变现也可能不同。当你的程序表现不符合预期的时候,移除tcmalloc然后尝试其他版本。
|
||||
|
||||
Code compiled with gcc 4.8.2 and linked to a tcmalloc compiled with earlier GCC may crash or deadlock before main(), E.g:
|
||||
用gcc4.8.2编译然后链接更早版本GCC编译的tcmalloc,可能会让程序中main()函数之前挂掉或者死锁,例如:
|
||||
|
||||

|
||||
|
||||
When you meet the issue, compile tcmalloc with the same GCC.
|
||||
当你遇到这个问题的时候,请用同一个GCC重新编译tcmalloc。
|
||||
|
||||
Another common issue with tcmalloc is that it does not return memory to system as early as ptmalloc. So when there's an invalid memory access, the program may not crash directly, instead it crashes at a unrelated place, or even not crash. When you program has weird memory issues, try removing tcmalloc.
|
||||
另外一个使用tcmalloc的常见问题是,它不会像 ptmalloc一样及时地归还内存给系统。因此当有一个无效的内存访问的时候,程序可能不会直接挂掉,取而代之的是它可能在一个不相关的地方挂掉,或者甚至一直不挂掉。当你的程序出现怪异的内存问题的时候,尝试移除tcmalloc。
|
||||
|
||||
If you want to use [cpu profiler](cpu_profiler.md) or [heap profiler](heap_profiler.md), do link `libtcmalloc_and_profiler.a`. These two profilers are based on tcmalloc.[contention profiler](contention_profiler.md) does not require tcmalloc.
|
||||
如果你要使用[cpu profiler](cpu_profiler.md)或[heap profiler](heap_profiler.md),要链接`libtcmalloc_and_profiler.a`。这两个 profiler都是基于tcmalloc的。而[contention profiler](contention_profiler.md)不需要tcmalloc。
|
||||
|
||||
When you remove tcmalloc, not only remove the linkage with tcmalloc but also the macro `-DBRPC_ENABLE_CPU_PROFILER`.
|
||||
当你移除tcmalloc的时候,不仅要移除tcmalloc的链接,也要移除宏`-DBRPC_ENABLE_CPU_PROFILER`。
|
||||
|
||||
## glog: 3.3+
|
||||
|
||||
brpc implements a default [logging utility](../../src/butil/logging.h) which conflicts with glog. To replace this with glog, add *--with-glog* to config_brpc.sh or add `-DWITH_GLOG=ON` to cmake.
|
||||
brpc实现了一个默认的[日志功能](../../src/butil/logging.h)它和glog冲突。要替换成glog,可以给config_brpc.sh增加*--with-glog*选项或者给cmake增加`-DWITH_GLOG=ON`选项。
|
||||
|
||||
## valgrind: 3.8+
|
||||
|
||||
brpc detects valgrind automatically (and registers stacks of bthread). Older valgrind(say 3.2) is not supported.
|
||||
brpc会自动检测valgrind(然后注册bthread的栈)。不支持老版本的valgrind(比如3.2)。
|
||||
|
||||
## thrift: 0.9.3-0.11.0
|
||||
|
||||
no known issues.
|
||||
无已知问题。
|
||||
|
||||
# Track instances
|
||||
# 实例追踪
|
||||
|
||||
We provide a program to help you to track and monitor all brpc instances. Just run [trackme_server](https://github.com/brpc/brpc/tree/master/tools/trackme_server/) somewhere and launch need-to-be-tracked instances with -trackme_server=SERVER. The trackme_server will receive pings from instances periodically and print logs when it does. You can aggregate instance addresses from the log and call builtin services of the instances for further information.
|
||||
我们提供了一个程序去帮助你追踪和监控所有brpc实例。 只需要在某处运行 [trackme_server](https://github.com/brpc/brpc/tree/master/tools/trackme_server/) 然后再带着 -trackme_server=SERVER参数启动需要被追踪的实例。trackme_server将从实例周期性地收到ping消息然后打印日志。您可以从日志中聚合实例地址,并调用实例的内置服务以获取更多信息。
|
||||
|
||||
@@ -114,7 +114,9 @@ URL的一般形式如下图:
|
||||
|
||||
若用户没有填且URL中包含host,比如http://www.foo.com/path,则http request中会包含"Host: www.foo.com"。
|
||||
|
||||
若用户没有填且URL不包含host,比如"/index.html?name=value",则框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
|
||||
若用户没有填且URL不包含host,比如"/index.html?name=value",但如果Channel初始化的地址包含域名,则框架会以域名作为Host,比如"http://www.foo.com",该http server将会看到"Host: www.foo.com"。如果地址是"http://www.foo.com:8989",则该http server将会看到"Host: www.foo.com:8989"。
|
||||
|
||||
若用户没有填且URL不包含host,比如"/index.html?name=value",如果Channel初始化的地址也不包含域名,则框架会以目标server的ip和port为Host,地址为10.46.188.39:8989的http server将会看到"Host: 10.46.188.39:8989"。
|
||||
|
||||
对应的字段在h2中叫":authority"。
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ RPC不是万能的抽象,否则我们也不需要TCP/IP这一层了。但是
|
||||
* 访问服务? 包含[brpc/channel.h](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h)并参考注释或[示例](https://github.com/brpc/brpc/blob/master/example/echo_c++/client.cpp).
|
||||
* 调整参数? 看看[brpc/controller.h](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h). 注意这个类是Server和Channel共用的,分成了三段,分别标记为Client-side, Server-side和Both-side methods。
|
||||
|
||||
我们尝试让事情变得更加简单,以命名服务为例,在其他RPC实现中,你也许需要复制一长段晦涩的代码才可使用,而在brpc中访问BNS可以这么写"bns://node-name",DNS是`Init("http://domain-name", ...)`,本地文件列表是"file:///home/work/server.list",相信不用解释,你也能明白这些代表什么。
|
||||
我们尝试让事情变得更加简单,以命名服务为例,在其他RPC实现中,你也许需要复制一长段晦涩的代码才可使用,而在brpc中访问BNS可以这么写`"bns://node-name"`,DNS是`"http://domain-name"`,本地文件列表是`"file:///home/work/server.list"`,相信不用解释,你也能明白这些代表什么。
|
||||
|
||||
### 使服务更加可靠
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ rpc_press启动后会默认在8888端口启动一个dummy server,用于观察r
|
||||
```
|
||||
./rpc_press -proto=echo.proto -service=example.EchoService -method=Echo -server=0.0.0.0:8002 -input=./input.json -duration=0 -qps=100
|
||||
TRACE: 01-30 16:10:04: * 0 src/brpc/server.cpp:733] Server[dummy_servers] is serving on port=8888.
|
||||
TRACE: 01-30 16:10:04: * 0 src/brpc/server.cpp:742] Check out http://db-rpc-dev00.db01.baidu.com:8888 in your web browser.</code>
|
||||
TRACE: 01-30 16:10:04: * 0 src/brpc/server.cpp:742] Check out http://xxx.com:8888 in your web browser.</code>
|
||||
```
|
||||
|
||||
dummy_server启动时会在终端打印日志,一般按住ctrl点击那个链接可以直接打开对应的内置服务页面,就像这样:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
r31658后,brpc能随机地把一部分请求写入一些文件中,并通过rpc_replay工具回放。目前支持的协议有:baidu_std, hulu_pbrpc, sofa_pbrpc, nshead。
|
||||
r31658后,brpc能随机地把一部分请求写入一些文件中,并通过rpc_replay工具回放。目前支持的协议有:baidu_std, hulu_pbrpc, sofa_pbrpc, http, nshead。
|
||||
|
||||
# 获取工具
|
||||
|
||||
@@ -75,6 +75,7 @@ brpc在[tools/rpc_replay](https://github.com/brpc/brpc/tree/master/tools/rpc_rep
|
||||
- -thread_num:发送线程数,为0时会根据qps自动调节,默认为0。一般不用设置。
|
||||
- -timeout_ms:超时
|
||||
- -use_bthread:使用bthread发送,默认是。
|
||||
- -http_host:指定回放HTTP请求时的Host字段,如果非标准端口,请补全,比如:www.abc.com:8888,不指定该参数时将使用采样的原始Host字段。
|
||||
|
||||
rpc_replay会默认启动一个仅监控用的dummy server。打开后可查看回放的状况。其中rpc_replay_error是回放失败的次数。
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ rpc_view可以转发端口被限的server的内置服务。像百度内如果一
|
||||
```
|
||||
$ ./rpc_view 10.46.130.53:9970
|
||||
TRACE: 02-14 12:12:20: * 0 src/brpc/server.cpp:762] Server[rpc_view_server] is serving on port=8888.
|
||||
TRACE: 02-14 12:12:20: * 0 src/brpc/server.cpp:771] Check out http://db-rpc-dev00.db01.baidu.com:8888 in web browser.
|
||||
TRACE: 02-14 12:12:20: * 0 src/brpc/server.cpp:771] Check out http://XXX.com:8888 in web browser.
|
||||
```
|
||||
|
||||
打开rpc_view在8888端口提供的页面(在secureCRT中按住ctrl点url):
|
||||
|
||||
@@ -55,3 +55,14 @@ TRACEPRINTF("Hello rpcz %d", 123);
|
||||
```
|
||||
|
||||
这条annotation会按其发生时间插入到对应请求的rpcz中。从这个角度看,rpcz是请求级的日志。如果你用TRACEPRINTF打印了沿路的上下文,便可看到请求在每个阶段停留的时间,牵涉到的数据集和参数。这是个很有用的功能。
|
||||
|
||||
## 跨bthread传递trace上下文
|
||||
|
||||
有的业务在处理server请求的时候,会创建子bthread,在子bthread中发起rpc调用。默认情况下,子bthread中的rpc调用跟原来的请求无法建立关联,trace就会断掉。这种情况下,可以在创建子bthread时,指定BTHREAD_INHERIT_SPAN标志,来显式地建立trace上文关联,如:
|
||||
|
||||
```c++
|
||||
bthread_attr_t attr = { BTHREAD_STACKTYPE_NORMAL, BTHREAD_INHERIT_SPAN, NULL };
|
||||
bthread_start_urgent(&tid, &attr, thread_proc, arg);
|
||||
```
|
||||
|
||||
注意:使用这种方式创建子bthread来发送rpc,请确保rpc在server返回response之前完成,否则可能导致使用被释放的Span对象而出core。
|
||||
|
||||
@@ -210,7 +210,13 @@ int Start(int port, const ServerOptions* opt);
|
||||
int Start(const char *ip_str, PortRange port_range, const ServerOptions *opt); // r32009后增加
|
||||
```
|
||||
|
||||
"localhost:9000", "cq01-cos-dev00.cq01:8000", “127.0.0.1:7000"都是合法的`ip_and_port_str`。
|
||||
合法的`ip_and_port_str`:
|
||||
|
||||
- 127.0.0.1:80 # IPV4
|
||||
- [::1]:8080 # IPV6
|
||||
- unix:path.sock # Unix domain socket
|
||||
|
||||
关于IPV6和Unix domain socket的使用,详见 [EndPoint](endpoint.md)。
|
||||
|
||||
`options`为NULL时所有参数取默认值,如果你要使用非默认值,这么做就行了:
|
||||
|
||||
@@ -225,6 +231,10 @@ server.Start(..., &options);
|
||||
|
||||
一个server只能监听一个端口(不考虑ServerOptions.internal_port),需要监听N个端口就起N个Server。
|
||||
|
||||
## 多进程监听一个端口
|
||||
|
||||
启动时开启`reuse_port`这个flag,就可以多进程共同监听一个端口(底层是SO_REUSEPORT)。
|
||||
|
||||
# 停止
|
||||
|
||||
```c++
|
||||
@@ -647,6 +657,8 @@ server.MaxConcurrencyOf("example.EchoService.Echo") = "auto";
|
||||
|
||||
对于这些情况,brpc提供了pthread模式,开启**-usercode_in_pthread**后,用户代码均会在pthread中运行,原先阻塞bthread的函数转而阻塞pthread。
|
||||
|
||||
注意:开启-usercode_in_pthread后,brpc::thread_local_data()不保证能获取到值。
|
||||
|
||||
打开pthread模式后在性能上的注意点:
|
||||
|
||||
- 同步RPC都会阻塞worker pthread,server端一般需要设置更多的工作线程(ServerOptions.num_threads),调度效率会略微降低。
|
||||
@@ -683,6 +695,10 @@ pthread模式可以让一些老代码快速尝试brpc,但我们仍然建议逐
|
||||
```shell
|
||||
curl -s -m 1 <HOSTNAME>:<PORT>/flags/enable_dir_service,enable_threads_service | awk '{if($3=="false"){++falsecnt}else if($3=="Value"){isrpc=1}}END{if(isrpc!=1||falsecnt==2){print "SAFE"}else{print "NOT SAFE"}}'
|
||||
```
|
||||
### 完全禁用内置服务
|
||||
|
||||
设置ServerOptions.has_builtin_services = false,可以完全禁用内置服务。
|
||||
|
||||
### 转义外部可控的URL
|
||||
|
||||
可调用brpc::WebEscape()对url进行转义,防止恶意URI注入攻击。
|
||||
@@ -768,15 +784,16 @@ public:
|
||||
delete static_cast<MySessionLocalData*>(d);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MySessionLocalDataFactory g_session_local_data_factory;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
...
|
||||
MySessionLocalDataFactory session_local_data_factory;
|
||||
|
||||
brpc::Server server;
|
||||
brpc::ServerOptions options;
|
||||
...
|
||||
options.session_local_data_factory = &session_local_data_factory;
|
||||
options.session_local_data_factory = &g_session_local_data_factory;
|
||||
...
|
||||
```
|
||||
|
||||
@@ -859,14 +876,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
MyThreadLocalDataFactory g_thread_local_data_factory;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
...
|
||||
MyThreadLocalDataFactory thread_local_data_factory;
|
||||
|
||||
brpc::Server server;
|
||||
brpc::ServerOptions options;
|
||||
...
|
||||
options.thread_local_data_factory = &thread_local_data_factory;
|
||||
options.thread_local_data_factory = &g_thread_local_data_factory;
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
上图中字段的含义分别是:
|
||||
|
||||
- **non_service_error**: 在service处理过程之外的错误个数。比如client断开连接导致server无法成功写回response算*non_service_error*,此时service处理已结束。作为对比,服务过程中对后端服务的访问错误不是*non_service_error*。即使写出的response代表错误,此error也被记入对应的service,而不是*non_service_error*。
|
||||
- **non_service_error**: 在service处理过程之外的错误个数。当获取到合法的service,之后发生的错误就算*service_error*,否则算*non_service_error*(比如请求解析失败,service名称不存在,请求并发度超限被拒绝等)。作为对比,服务过程中对后端服务的访问错误不是*non_service_error*。即使写出的response代表错误,此error也被记入对应的service,而不是*non_service_error*。
|
||||
- **connection_count**: 向该server发起请求的连接个数。不包含记录在/vars/rpc_channel_connection_count的对外连接的个数。
|
||||
- **example.EchoService**: 服务的完整名称,包含proto中的包名。
|
||||
- **Echo (EchoRequest) returns (EchoResponse)**: 方法签名,一个服务可包含多个方法,点击request/response上的链接可查看对应的protobuf结构体。
|
||||
|
||||
@@ -135,6 +135,8 @@ TRACE: ... Items: item1 item2 item3
|
||||
|
||||
noflush支持bthread,可以实现类似于UB的pushnotice的效果,即检索线程一路打印都暂不刷出(加上noflush),直到最后检索结束时再一次性刷出。注意,如果检索过程是异步的,就不应该使用noflush,因为异步显然会跨越bthread,使noflush仍然失效。
|
||||
|
||||
> 注意:如果编译时开启了glog选项,则不支持noflush。
|
||||
|
||||
## LOG_IF
|
||||
|
||||
`LOG_IF(log_level, condition)`只有当condition成立时才会打印,相当于if (condition) { LOG() << ...; },但更加简短。比如:
|
||||
|
||||
@@ -39,7 +39,7 @@ For example: the first variable plays the role of switch, controlling accesses t
|
||||
|
||||
```c++
|
||||
// Thread 1
|
||||
// ready was initialized to false
|
||||
// bool ready was initialized to false
|
||||
p.init();
|
||||
ready = true;
|
||||
```
|
||||
@@ -72,7 +72,7 @@ Above example can be modified as follows:
|
||||
|
||||
```c++
|
||||
// Thread1
|
||||
// ready was initialized to false
|
||||
// std::atomic<bool> ready was initialized to false
|
||||
p.init();
|
||||
ready.store(true, std::memory_order_release);
|
||||
```
|
||||
|
||||
@@ -216,6 +216,8 @@ which is round robin. Always choose next server inside the list, next of the las
|
||||
|
||||
which is weighted round robin. Choose the next server according to the configured weight. The chances a server is selected is consistent with its weight, and the algorithm can make each server selection scattered.
|
||||
|
||||
The instance tag must be an int32 number representing the weight, eg. tag="50".
|
||||
|
||||
### random
|
||||
|
||||
Randomly choose one server from the list, no other settings. Similarly with round robin, the algorithm assumes that servers to access are similar.
|
||||
@@ -224,6 +226,8 @@ Randomly choose one server from the list, no other settings. Similarly with roun
|
||||
|
||||
which is weighted random. Choose the next server according to the configured weight. The chances a server is selected is consistent with its weight.
|
||||
|
||||
Requirements of instance tag is the same as wrr.
|
||||
|
||||
### la
|
||||
|
||||
which is locality-aware. Perfer servers with lower latencies, until the latency is higher than others, no other settings. Check out [Locality-aware load balancing](lalb.md) for more details.
|
||||
@@ -240,6 +244,8 @@ Do distinguish "key" and "attributes" of the request. Don't compute request_code
|
||||
|
||||
Check out [Consistent Hashing](consistent_hashing.md) for more details.
|
||||
|
||||
Other kind of lb does not need to set Controller.set_request_code(). If request code is set, it will not be used by lb. For example, lb=rr, and call Controller.set_request_code(), even if request_code is the same for every request, lb will balance the requests using the rr policy.
|
||||
|
||||
### Client-side throttling for recovery from cluster downtime
|
||||
|
||||
Cluster downtime refers to the state in which all servers in the cluster are unavailable. Due to the health check mechanism, when the cluster returns to normal, server will go online one by one. When a server is online, all traffic will be sent to it, which may cause the service to be overloaded again. If circuit breaker is enabled, server may be offline again before the other servers go online, and the cluster can never be recovered. As a solution, brpc provides a client-side throttling mechanism for recovery after cluster downtime. When no server is available in the cluster, the cluster enters recovery state. Assuming that the minimum number of servers that can serve all requests is min_working_instances, current number of servers available in the cluster is q, then in recovery state, the probability of client accepting the request is q/min_working_instances, otherwise it is discarded. If q remains unchanged for a period of time(hold_seconds), the traffic is resent to all available servers and leaves recovery state. Whether the request is rejected in recovery state is indicated by whether controller.ErrorCode() is equal to brpc::ERJECT, and the rejected request will not be retried by the framework.
|
||||
@@ -293,6 +299,12 @@ if (cntl.Failed()) {
|
||||
}
|
||||
```
|
||||
|
||||
> WARNING: Do NOT use synchronous call when you are holding a pthread lock! Otherwise it is easy to cause deadlock.
|
||||
>
|
||||
> Solution (choose one of the two):
|
||||
> 1. Replace pthread lock with bthread lock (bthread_mutex_t)
|
||||
> 1. Release the lock before CallMethod
|
||||
|
||||
## Asynchronous call
|
||||
|
||||
Pass a callback `done` to CallMethod, which resumes after sending request, rather than completion of RPC. When the response from server is received or error occurred(including timedout), done->Run() is called. Post-processing code of the RPC should be put in done->Run() instead of after CallMethod.
|
||||
@@ -301,7 +313,11 @@ Because end of CallMethod does not mean completion of RPC, response/controller m
|
||||
|
||||
You can new these objects individually and create done by [NewCallback](#use-newcallback), or make response/controller be member of done and [new them together](#Inherit-google::protobuf::Closure). Former one is recommended.
|
||||
|
||||
**Request and Channel can be destroyed immediately after asynchronous CallMethod**, which is different from response/controller. Note that "immediately" means destruction of request/Channel can happen **after** CallMethod, not during CallMethod. Deleting a Channel just being used by another thread results in undefined behavior (crash at best).
|
||||
Request can be destroyed immediately after asynchronous CallMethod. (SelectiveChannel is an exception, in the case of SelectiveChannel, the request object must be released after rpc finish)
|
||||
|
||||
Channel can be destroyed immediately after asynchronous CallMethod.
|
||||
|
||||
Note that "immediately" means destruction of Request/Channel can happen **after** CallMethod, not during CallMethod. Deleting a Channel just being used by another thread results in undefined behavior (crash at best).
|
||||
|
||||
### Use NewCallback
|
||||
```c++
|
||||
@@ -324,7 +340,7 @@ MyService_Stub stub(&channel);
|
||||
MyRequest request; // you don't have to new request, even in an asynchronous call.
|
||||
request.set_foo(...);
|
||||
cntl->set_timeout_ms(...);
|
||||
stub.some_method(cntl, &request, response, google::protobuf::NewCallback(OnRPCDone, response, cntl));
|
||||
stub.some_method(cntl, &request, response, brpc::NewCallback(OnRPCDone, response, cntl));
|
||||
```
|
||||
Since protobuf 3 changes NewCallback to private, brpc puts NewCallback in [src/brpc/callback.h](https://github.com/brpc/brpc/blob/master/src/brpc/callback.h) after r32035 (and adds more overloads). If your program has compilation issues with NewCallback, replace google::protobuf::NewCallback with brpc::NewCallback.
|
||||
|
||||
@@ -523,7 +539,7 @@ NOTE2: error code of RPC timeout is **ERPCTIMEDOUT (1008) **, ETIMEDOUT is conne
|
||||
|
||||
## Retry
|
||||
|
||||
ChannelOptions.max_retry is maximum retrying count for all RPC via the channel, Controller.set_max_retry() overrides value for one RPC. Default value is 3. 0 means no retries.
|
||||
ChannelOptions.max_retry is maximum retrying count for all RPC via the channel, Default value is 3, 0 means no retries. Controller.set_max_retry() overrides value for one RPC.
|
||||
|
||||
Controller.retried_count() returns number of retries.
|
||||
|
||||
@@ -757,7 +773,7 @@ set_request_compress_type() sets compress-type of the request, no compression by
|
||||
|
||||
NOTE: Attachment is not compressed by brpc.
|
||||
|
||||
Check out [compress request body](http_client#压缩request-body) to compress http/h2 body.
|
||||
Check out [compress request body](http_client.md#compress-request-body) to compress http/h2 body.
|
||||
|
||||
Supported compressions:
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@ Following table shows common error codes and their descriptions:
|
||||
| Error Code | Value | Retry | Description | Logging message |
|
||||
| -------------- | ----- | ----- | ---------------------------------------- | ---------------------------------------- |
|
||||
| EAGAIN | 11 | Yes | Too many requests at the same time, hardly happening as it's a soft limit. | Resource temporarily unavailable |
|
||||
| ENODATA | 61 | 是 | 1. The server list returned by Naming Service is empty. 2. When Naming Service changes with all instances modified, Naming Service updates LB by first Remove all and then Add all, the LB instance list may become empty within a short period of time. | Fail to select server from xxx |
|
||||
| ETIMEDOUT | 110 | Yes | Connection timeout. | Connection timed out |
|
||||
| EHOSTDOWN | 112 | Yes | No available server to send request. The servers may be stopped or stopping(returning ELOGOFF). | "Fail to select server from …" "Not connected to … yet" |
|
||||
| EHOSTDOWN | 112 | Yes | Possible reasons: A. The list returned by Naming Server is not empty, but LB cannot select an available server, and LB returns an EHOSTDOWN error. Specific possible reasons: a. Server is exiting (returned ELOGOFF) b. Server was blocked because of some previous failure, the specific logic of the block: 1. For single connection type, the only connection socket is blocked by SetFail, and there are many occurrences of SetFailed in the code to trigger this block. 2. For pooled/short connection type, only when the error number meets does_error_affect_main_socket (ECONNREFUSED, ENETUNREACH, EHOSTUNREACH or EINVAL) will it be blocked 3. After blocking, there is a CheckHealth thread to do health check, Just try to connect, the check interval is controlled by the health_check_interval_s of SocketOptions, and the Socket will be unblocked if it is connected successfully. B. Use the SingleServer method to initialize the Channel (without LB), and the only connection is LOGOFF or blocked (same as above) | "Fail to select server from …" "Not connected to … yet" |
|
||||
| ENOSERVICE | 1001 | No | Can't locate the service, hardly happening and usually being ENOMETHOD instead | |
|
||||
| ENOMETHOD | 1002 | No | Can't locate the method. | Misc forms, common ones are "Fail to find method=…" |
|
||||
| EREQUEST | 1003 | No | fail to serialize the request, may be set on either client-side or server-side | Misc forms: "Missing required fields in request: …" "Fail to parse request message, …" "Bad request" |
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
[中文版](../cn/getting_started.md)
|
||||
|
||||
# BUILD
|
||||
|
||||
brpc prefers static linkages of deps, so that they don't have to be installed on every machine running the app.
|
||||
|
||||
brpc depends on following packages:
|
||||
|
||||
* [gflags](https://github.com/gflags/gflags): Extensively used to define global options.
|
||||
* [protobuf](https://github.com/google/protobuf): Serializations of messages, interfaces of services.
|
||||
* [leveldb](https://github.com/google/leveldb): Required by [/rpcz](rpcz.md) to record RPCs for tracing.
|
||||
|
||||
# Supported Environment
|
||||
|
||||
* [Ubuntu/LinuxMint/WSL](#ubuntulinuxmintwsl)
|
||||
* [Fedora/CentOS](#fedoracentos)
|
||||
* [Linux with self-built deps](#linux-with-self-built-deps)
|
||||
* [MacOS](#macos)
|
||||
|
||||
## Ubuntu/LinuxMint/WSL
|
||||
### Prepare deps
|
||||
|
||||
Install common deps, [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
sudo apt-get install -y git g++ make libssl-dev libgflags-dev libprotobuf-dev libprotoc-dev protobuf-compiler libleveldb-dev
|
||||
```
|
||||
|
||||
If you need to statically link leveldb:
|
||||
```shell
|
||||
sudo apt-get install -y libsnappy-dev
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
```shell
|
||||
sudo apt-get install -y libgoogle-perftools-dev
|
||||
```
|
||||
|
||||
If you need to run tests, install and compile libgtest-dev (which is not compiled yet):
|
||||
```shell
|
||||
sudo apt-get install -y cmake libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libgtest* /usr/lib/ && cd -
|
||||
```
|
||||
The directory of gtest source code may be changed, try `/usr/src/googletest/googletest` if `/usr/src/gtest` is not there.
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
git clone brpc, cd into the repo and run
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers=/usr/include --libs=/usr/lib
|
||||
$ make
|
||||
```
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
|
||||
**Run example**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
$ make
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
```shell
|
||||
cmake -B build && cmake --build build -j6
|
||||
```
|
||||
To help VSCode or Emacs(LSP) to understand code correctly, add `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` to generate `compile_commands.json`
|
||||
|
||||
To change compiler to clang, overwrite environment variable `CC` and `CXX` to `clang` and `clang++` respectively.
|
||||
|
||||
To not link debugging symbols, remove `build/CMakeCache.txt` and cmake with `-DWITH_DEBUG_SYMBOLS=OFF`
|
||||
|
||||
To use brpc with glog, cmake with `-DWITH_GLOG=ON`.
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and cmake with `-DWITH_THRIFT=ON`.
|
||||
|
||||
**Run example with cmake**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
$ cmake -B build && cmake --build build -j4
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
Examples link brpc statically, if you need to link the shared version, remove `CMakeCache.txt` and cmake with `-DLINK_SO=ON`
|
||||
|
||||
**Run tests**
|
||||
|
||||
```shell
|
||||
$ mkdir build && cd build && cmake -DBUILD_UNIT_TESTS=ON .. && make && make test
|
||||
```
|
||||
|
||||
## Fedora/CentOS
|
||||
|
||||
### Prepare deps
|
||||
|
||||
CentOS needs to install EPEL generally otherwise many packages are not available by default.
|
||||
```shell
|
||||
sudo yum install epel-release
|
||||
```
|
||||
|
||||
Install common deps:
|
||||
```shell
|
||||
sudo yum install git gcc-c++ make openssl-devel
|
||||
```
|
||||
|
||||
Install [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
sudo yum install gflags-devel protobuf-devel protobuf-compiler leveldb-devel
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
```shell
|
||||
sudo yum install gperftools-devel
|
||||
```
|
||||
|
||||
If you need to run tests, install and compile gtest-devel (which is not compiled yet):
|
||||
```shell
|
||||
sudo yum install gtest-devel
|
||||
```
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
|
||||
git clone brpc, cd into the repo and run
|
||||
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers="/usr/include" --libs="/usr/lib64 /usr/bin"
|
||||
$ make
|
||||
```
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
|
||||
**Run example**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
$ make
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
|
||||
## Linux with self-built deps
|
||||
|
||||
### Prepare deps
|
||||
|
||||
brpc builds itself to both static and shared libs by default, so it needs static and shared libs of deps to be built as well.
|
||||
|
||||
Take [gflags](https://github.com/gflags/gflags) as example, which does not build shared lib by default, you need to pass options to `cmake` to change the behavior:
|
||||
```shell
|
||||
$ cmake . -DBUILD_SHARED_LIBS=1 -DBUILD_STATIC_LIBS=1
|
||||
$ make
|
||||
```
|
||||
|
||||
### Compile brpc
|
||||
|
||||
Keep on with the gflags example, let `../gflags_dev` be where gflags is cloned.
|
||||
|
||||
git clone brpc. cd into the repo and run
|
||||
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers="../gflags_dev /usr/include" --libs="../gflags_dev /usr/lib64"
|
||||
$ make
|
||||
```
|
||||
|
||||
Here we pass multiple paths to `--headers` and `--libs` to make the script search for multiple places. You can also group all deps and brpc into one directory, then pass the directory to --headers/--libs which actually search all subdirectories recursively and will find necessary files.
|
||||
|
||||
To change compiler to clang, add `--cxx=clang++ --cc=clang`.
|
||||
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
|
||||
```shell
|
||||
$ ls my_dev
|
||||
gflags_dev protobuf_dev leveldb_dev brpc_dev
|
||||
$ cd brpc_dev
|
||||
$ sh config_brpc.sh --headers=.. --libs=..
|
||||
$ make
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
|
||||
## MacOS
|
||||
|
||||
Note: In the same running environment, the performance of the current Mac version is about 2.5 times worse than the Linux version. If your service is performance-critical, do not use MacOS as your production environment.
|
||||
|
||||
### Prepare deps
|
||||
|
||||
Install common deps:
|
||||
```shell
|
||||
brew install openssl git gnu-getopt coreutils
|
||||
```
|
||||
|
||||
Install [gflags](https://github.com/gflags/gflags), [protobuf](https://github.com/google/protobuf), [leveldb](https://github.com/google/leveldb):
|
||||
```shell
|
||||
brew install gflags protobuf leveldb
|
||||
```
|
||||
|
||||
If you need to enable cpu/heap profilers in examples:
|
||||
```shell
|
||||
brew install gperftools
|
||||
```
|
||||
|
||||
If you need to run tests, download and compile googletest (which is not compiled yet):
|
||||
```shell
|
||||
git clone https://github.com/google/googletest -b release-1.10.0 && cd googletest/googletest && mkdir build && cd build && cmake -DCMAKE_CXX_FLAGS="-std=c++11" .. && make
|
||||
```
|
||||
After the compilation, copy include/ and lib/ into /usr/local/include and /usr/local/lib respectively to expose gtest to all apps
|
||||
|
||||
### Compile brpc with config_brpc.sh
|
||||
git clone brpc, cd into the repo and run
|
||||
```shell
|
||||
$ sh config_brpc.sh --headers=/usr/local/include --libs=/usr/local/lib --cc=clang --cxx=clang++
|
||||
$ make
|
||||
```
|
||||
To not link debugging symbols, add `--nodebugsymbols` and compiled binaries will be much smaller.
|
||||
|
||||
To use brpc with glog, add `--with-glog`.
|
||||
|
||||
To enable [thrift support](../en/thrift.md), install thrift first and add `--with-thrift`.
|
||||
|
||||
**Run example**
|
||||
|
||||
```shell
|
||||
$ cd example/echo_c++
|
||||
$ make
|
||||
$ ./echo_server &
|
||||
$ ./echo_client
|
||||
```
|
||||
|
||||
Examples link brpc statically, if you need to link the shared version, `make clean` and `LINK_SO=1 make`
|
||||
|
||||
**Run tests**
|
||||
```shell
|
||||
$ cd test
|
||||
$ make
|
||||
$ sh run_tests.sh
|
||||
```
|
||||
|
||||
### Compile brpc with cmake
|
||||
Same with [here](#compile-brpc-with-cmake)
|
||||
|
||||
# Supported deps
|
||||
|
||||
## GCC: 4.8-7.1
|
||||
|
||||
c++11 is turned on by default to remove dependencies on boost (atomic).
|
||||
|
||||
The over-aligned issues in GCC7 is suppressed temporarily now.
|
||||
|
||||
Using other versions of gcc may generate warnings, contact us to fix.
|
||||
|
||||
Adding `-D__const__=` to cxxflags in your makefiles is a must to avoid [errno issue in gcc4+](thread_local.md).
|
||||
|
||||
## Clang: 3.5-4.0
|
||||
|
||||
no known issues.
|
||||
|
||||
## glibc: 2.12-2.25
|
||||
|
||||
no known issues.
|
||||
|
||||
## protobuf: 2.4+
|
||||
|
||||
Be compatible with pb 3.x and pb 2.x with the same file:
|
||||
Don't use new types in proto3 and start the proto file with `syntax="proto2";`
|
||||
[tools/add_syntax_equal_proto2_to_all.sh](https://github.com/brpc/brpc/blob/master/tools/add_syntax_equal_proto2_to_all.sh)can add `syntax="proto2"` to all proto files without it.
|
||||
|
||||
Arena in pb 3.x is not supported yet.
|
||||
|
||||
## gflags: 2.0-2.2.1
|
||||
|
||||
no known issues.
|
||||
|
||||
## openssl: 0.97-1.1
|
||||
|
||||
required by https.
|
||||
|
||||
## tcmalloc: 1.7-2.5
|
||||
|
||||
brpc does **not** link [tcmalloc](http://goog-perftools.sourceforge.net/doc/tcmalloc.html) by default. Users link tcmalloc on-demand.
|
||||
|
||||
Comparing to ptmalloc embedded in glibc, tcmalloc often improves performance. However different versions of tcmalloc may behave really differently. For example, tcmalloc 2.1 may make multi-threaded examples in brpc perform significantly worse(due to a spinlock in tcmalloc) than the one using tcmalloc 1.7 and 2.5. Even different minor versions may differ. When you program behave unexpectedly, remove tcmalloc or try another version.
|
||||
|
||||
Code compiled with gcc 4.8.2 and linked to a tcmalloc compiled with earlier GCC may crash or deadlock before main(), E.g:
|
||||
|
||||

|
||||
|
||||
When you meet the issue, compile tcmalloc with the same GCC.
|
||||
|
||||
Another common issue with tcmalloc is that it does not return memory to system as early as ptmalloc. So when there's an invalid memory access, the program may not crash directly, instead it crashes at a unrelated place, or even not crash. When you program has weird memory issues, try removing tcmalloc.
|
||||
|
||||
If you want to use [cpu profiler](cpu_profiler.md) or [heap profiler](heap_profiler.md), do link `libtcmalloc_and_profiler.a`. These two profilers are based on tcmalloc.[contention profiler](contention_profiler.md) does not require tcmalloc.
|
||||
|
||||
When you remove tcmalloc, not only remove the linkage with tcmalloc but also the macro `-DBRPC_ENABLE_CPU_PROFILER`.
|
||||
|
||||
## glog: 3.3+
|
||||
|
||||
brpc implements a default [logging utility](../../src/butil/logging.h) which conflicts with glog. To replace this with glog, add *--with-glog* to config_brpc.sh or add `-DWITH_GLOG=ON` to cmake.
|
||||
|
||||
## valgrind: 3.8+
|
||||
|
||||
brpc detects valgrind automatically (and registers stacks of bthread). Older valgrind(say 3.2) is not supported.
|
||||
|
||||
## thrift: 0.9.3-0.11.0
|
||||
|
||||
no known issues.
|
||||
|
||||
# Track instances
|
||||
|
||||
We provide a program to help you to track and monitor all brpc instances. Just run [trackme_server](https://github.com/brpc/brpc/tree/master/tools/trackme_server/) somewhere and launch need-to-be-tracked instances with -trackme_server=SERVER. The trackme_server will receive pings from instances periodically and print logs when it does. You can aggregate instance addresses from the log and call builtin services of the instances for further information.
|
||||
@@ -115,7 +115,9 @@ If user already sets `Host` header(case insensitive), framework makes no change.
|
||||
|
||||
If user does not set `Host` header and the URL has host, for example http://www.foo.com/path, the http request contains "Host: www.foo.com".
|
||||
|
||||
If user does not set host header and the URL does not have host as well, for example "/index.html?name=value", framework sets `Host` header with IP and port of the target server. A http server at 10.46.188.39:8989 should see `Host: 10.46.188.39:8989`.
|
||||
If user does not set host header and the URL does not have host as well, for example "/index.html?name=value", but if the address initialized by the channel contains domain name. framework sets `Host` header with domain name of the target server. if this address is "http://www.foo.com", this http server should see `Host: www.foo.com`, if this address is "http://www.foo.com:8989", this http server should be see `Host: www.foo.com:8989`.
|
||||
|
||||
If user does not set host header and the URL does not have host as well, for example "/index.html?name=value", and the address initialized by the channel doesn't contain domain name. framework sets `Host` header with IP and port of the target server. A http server at 10.46.188.39:8989 should see `Host: 10.46.188.39:8989`.
|
||||
|
||||
The header is named ":authority" in h2.
|
||||
|
||||
|
||||
@@ -227,6 +227,10 @@ server.Start(..., &options);
|
||||
|
||||
One server can only listen to one port (not counting ServerOptions.internal_port). To listen to N ports, start N servers .
|
||||
|
||||
## Multi-process listening to one port
|
||||
|
||||
When the `reuse_port` flag is turned on at startup, multiple processes can listen to one port (use SO_REUSEPORT internal).
|
||||
|
||||
# Stop server
|
||||
|
||||
```c++
|
||||
@@ -647,6 +651,8 @@ User code(client-side done, server-side CallMethod) runs in bthreads with 1MB st
|
||||
|
||||
brpc offers pthread mode to solve the issues. When **-usercode_in_pthread** is turned on, user code will be run in pthreads. Functions that would block bthreads block pthreads.
|
||||
|
||||
Note: With -usercode_in_pthread on, brpc::thread_local_data() does not guarantee to return valid value.
|
||||
|
||||
Performance issues when pthread mode is on:
|
||||
|
||||
- Since synchronous RPCs block worker pthreads, server often needs more workers (ServerOptions.num_threads), and scheduling efficiencies will be slightly lower.
|
||||
@@ -683,6 +689,11 @@ Builtin services are useful, on the other hand include a lot of internal informa
|
||||
```shell
|
||||
curl -s -m 1 <HOSTNAME>:<PORT>/flags/enable_dir_service,enable_threads_service | awk '{if($3=="false"){++falsecnt}else if($3=="Value"){isrpc=1}}END{if(isrpc!=1||falsecnt==2){print "SAFE"}else{print "NOT SAFE"}}'
|
||||
```
|
||||
|
||||
### Disable built-in services completely
|
||||
|
||||
Set ServerOptions.has_builtin_services = false, you can completely disable the built-in services.
|
||||
|
||||
### Escape URLs controllable from public
|
||||
|
||||
brpc::WebEscape() escapes url to prevent injection attacks with malice.
|
||||
@@ -769,14 +780,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
MySessionLocalDataFactory g_session_local_data_factory;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
...
|
||||
MySessionLocalDataFactory session_local_data_factory;
|
||||
|
||||
brpc::Server server;
|
||||
brpc::ServerOptions options;
|
||||
...
|
||||
options.session_local_data_factory = &session_local_data_factory;
|
||||
options.session_local_data_factory = &g_session_local_data_factory;
|
||||
...
|
||||
```
|
||||
|
||||
@@ -859,14 +871,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
MyThreadLocalDataFactory g_thread_local_data_factory;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
...
|
||||
MyThreadLocalDataFactory thread_local_data_factory;
|
||||
|
||||
brpc::Server server;
|
||||
brpc::ServerOptions options;
|
||||
...
|
||||
options.thread_local_data_factory = &thread_local_data_factory;
|
||||
options.thread_local_data_factory = &g_thread_local_data_factory;
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
Meanings of the fields above:
|
||||
|
||||
- **non_service_error**: number of errors raised outside processing code of the service. For example, the error that server can't write response back due to a broken connection which had been closed by the client, is a *non_service_error* because the service processing already ends. As a contrast, failing to access back-end servers during the processing is an error of the service, not a *non_service_error*. Even if the response written out successfully stands for failure, the error is counted into the service rather than *non_service_error*.
|
||||
- **non_service_error**: number of errors raised outside processing code of the service. When a valid service is obtained, the subsequent error is regarded as *service_error*, otherwise it is regarded as *non_service_error* (such as request parsing failed, service name does not exist, request concurrency exceeding limit, etc.). As a contrast, failing to access back-end servers during the processing is an error of the service, not a *non_service_error*. Even if the response written out successfully stands for failure, the error is counted into the service rather than *non_service_error*.
|
||||
- **connection_count**: number of connections to the server from clients, not including number of outward connections which are displayed at /vars/rpc_channel_connection_count.
|
||||
- **example.EchoService**: Full name of the service, including the package name defined in proto.
|
||||
- **Echo (EchoRequest) returns (EchoResponse)**: Signature of the method. A service can have multiple methods. Click links on request/response to see schemes of the protobuf messages.
|
||||
|
||||
@@ -35,7 +35,7 @@ sh config_brpc.sh --headers=/usr/include --libs=/usr/lib64 --with-thrift
|
||||
# Or use cmake
|
||||
mkdir build && cd build && cmake ../ -DWITH_THRIFT=ON
|
||||
```
|
||||
Read [Getting Started](../cn/getting_started.md) for more compilation options.
|
||||
Read [Getting Started](getting_started.md) for more compilation options.
|
||||
|
||||
# Client accesses thrift server
|
||||
Steps:
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 193 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 298 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 147 KiB |
@@ -24,6 +24,8 @@
|
||||
|
||||
DEFINE_bool(echo_attachment, true, "Echo attachment as well");
|
||||
DEFINE_int32(port, 8000, "TCP Port of this server");
|
||||
DEFINE_string(listen_addr, "", "Server listen address, may be IPV4/IPV6/UDS."
|
||||
" If this is set, the flag port will be ignored");
|
||||
DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no "
|
||||
"read/write operations during the last `idle_timeout_s'");
|
||||
DEFINE_int32(logoff_ms, 2000, "Maximum duration of server's LOGOFF state "
|
||||
@@ -92,10 +94,19 @@ int main(int argc, char* argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
butil::EndPoint point;
|
||||
if (!FLAGS_listen_addr.empty()) {
|
||||
if (butil::str2endpoint(FLAGS_listen_addr.c_str(), &point) < 0) {
|
||||
LOG(ERROR) << "Invalid listen address:" << FLAGS_listen_addr;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
point = butil::EndPoint(butil::IP_ANY, FLAGS_port);
|
||||
}
|
||||
// Start the server.
|
||||
brpc::ServerOptions options;
|
||||
options.idle_timeout_sec = FLAGS_idle_timeout_s;
|
||||
if (server.Start(FLAGS_port, &options) != 0) {
|
||||
if (server.Start(point, &options) != 0) {
|
||||
LOG(ERROR) << "Fail to start EchoServer";
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -240,9 +240,10 @@ void Acceptor::ListConnections(std::vector<SocketId>* conn_list) {
|
||||
|
||||
void Acceptor::OnNewConnectionsUntilEAGAIN(Socket* acception) {
|
||||
while (1) {
|
||||
struct sockaddr in_addr;
|
||||
struct sockaddr_storage in_addr;
|
||||
bzero(&in_addr, sizeof(in_addr));
|
||||
socklen_t in_len = sizeof(in_addr);
|
||||
butil::fd_guard in_fd(accept(acception->fd(), &in_addr, &in_len));
|
||||
butil::fd_guard in_fd(accept(acception->fd(), (sockaddr*)&in_addr, &in_len));
|
||||
if (in_fd < 0) {
|
||||
// no EINTR because listened fd is non-blocking.
|
||||
if (errno == EAGAIN) {
|
||||
@@ -269,7 +270,7 @@ void Acceptor::OnNewConnectionsUntilEAGAIN(Socket* acception) {
|
||||
SocketOptions options;
|
||||
options.keytable_pool = am->_keytable_pool;
|
||||
options.fd = in_fd;
|
||||
options.remote_side = butil::EndPoint(*(sockaddr_in*)&in_addr);
|
||||
butil::sockaddr2endpoint(&in_addr, in_len, &options.remote_side);
|
||||
options.user = acception->user();
|
||||
options.on_edge_triggered_events = InputMessenger::OnNewMessages;
|
||||
options.initial_ssl_ctx = am->_ssl_ctx;
|
||||
|
||||
@@ -48,8 +48,6 @@ void IndexService::default_method(::google::protobuf::RpcController* controller,
|
||||
Controller *cntl = (Controller*)controller;
|
||||
cntl->http_response().set_content_type("text/plain");
|
||||
const Server* server = cntl->server();
|
||||
const butil::EndPoint my_addr(butil::my_ip(),
|
||||
server->listen_address().port);
|
||||
const bool use_html = UseHTML(cntl->http_request());
|
||||
const bool as_more = cntl->http_request().uri().GetQuery("as_more");
|
||||
if (use_html && !as_more) {
|
||||
@@ -144,8 +142,14 @@ void IndexService::default_method(::google::protobuf::RpcController* controller,
|
||||
<< " : Profiling growth of heap"
|
||||
<< (!IsHeapProfilerEnabled() ? " (disabled)" : "") << NL;
|
||||
}
|
||||
os << "curl -H 'Content-Type: application/json' -d 'JSON' " << my_addr
|
||||
<< "/ServiceName/MethodName : Call method by http+json" << NL
|
||||
os << "curl -H 'Content-Type: application/json' -d 'JSON' ";
|
||||
if (butil::is_endpoint_extended(server->listen_address())) {
|
||||
os << "<listen_address>";
|
||||
} else {
|
||||
const butil::EndPoint my_addr(butil::my_ip(), server->listen_address().port);
|
||||
os << my_addr;
|
||||
}
|
||||
os << "/ServiceName/MethodName : Call method by http+json" << NL
|
||||
|
||||
<< Path("/version", html_addr)
|
||||
<< " : Version of this server, set by Server::set_version()" << NL
|
||||
|
||||
@@ -220,7 +220,7 @@ void PProfService::heap(
|
||||
extra_desc = " (no TCMALLOC_SAMPLE_PARAMETER in env)";
|
||||
}
|
||||
cntl->SetFailed(ENOMETHOD, "Heap profiler is not enabled%s,"
|
||||
"check out http://wiki.baidu.com/display/RPC",
|
||||
"check out https://github.com/apache/incubator-brpc/blob/master/docs/cn/heap_profiler.md",
|
||||
extra_desc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ int Channel::Init(const char* server_addr, int port,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return InitSingle(point, server_addr, options);
|
||||
return InitSingle(point, server_addr, options, port);
|
||||
}
|
||||
|
||||
static int CreateSocketSSLContext(const ChannelOptions& options,
|
||||
@@ -283,20 +283,25 @@ int Channel::Init(butil::EndPoint server_addr_and_port,
|
||||
|
||||
int Channel::InitSingle(const butil::EndPoint& server_addr_and_port,
|
||||
const char* raw_server_address,
|
||||
const ChannelOptions* options) {
|
||||
const ChannelOptions* options,
|
||||
int raw_port) {
|
||||
GlobalInitializeOrDie();
|
||||
if (InitChannelOptions(options) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (_options.protocol == brpc::PROTOCOL_HTTP &&
|
||||
::strncmp(raw_server_address, "https://", 8) == 0) {
|
||||
std::string scheme;
|
||||
int* port_out = raw_port == -1 ? &raw_port: NULL;
|
||||
ParseURL(raw_server_address, &scheme, &_service_name, port_out);
|
||||
if (raw_port != -1) {
|
||||
_service_name.append(":").append(std::to_string(raw_port));
|
||||
}
|
||||
if (_options.protocol == brpc::PROTOCOL_HTTP && scheme == "https://") {
|
||||
if (_options.mutable_ssl_options()->sni_name.empty()) {
|
||||
ParseURL(raw_server_address,
|
||||
NULL, &_options.mutable_ssl_options()->sni_name, NULL);
|
||||
_options.mutable_ssl_options()->sni_name = _service_name;
|
||||
}
|
||||
}
|
||||
const int port = server_addr_and_port.port;
|
||||
if (port < 0 || port > 65535) {
|
||||
if (port < 0) {
|
||||
LOG(ERROR) << "Invalid port=" << port;
|
||||
return -1;
|
||||
}
|
||||
@@ -325,11 +330,15 @@ int Channel::Init(const char* ns_url,
|
||||
if (InitChannelOptions(options) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (_options.protocol == brpc::PROTOCOL_HTTP &&
|
||||
::strncmp(ns_url, "https://", 8) == 0) {
|
||||
std::string scheme;
|
||||
int raw_port = -1;
|
||||
ParseURL(ns_url, &scheme, &_service_name, &raw_port);
|
||||
if (raw_port != -1) {
|
||||
_service_name.append(":").append(std::to_string(raw_port));
|
||||
}
|
||||
if (_options.protocol == brpc::PROTOCOL_HTTP && scheme == "https://") {
|
||||
if (_options.mutable_ssl_options()->sni_name.empty()) {
|
||||
ParseURL(ns_url,
|
||||
NULL, &_options.mutable_ssl_options()->sni_name, NULL);
|
||||
_options.mutable_ssl_options()->sni_name = _service_name;
|
||||
}
|
||||
}
|
||||
LoadBalancerWithNaming* lb = new (std::nothrow) LoadBalancerWithNaming;
|
||||
@@ -386,6 +395,12 @@ void Channel::CallMethod(const google::protobuf::MethodDescriptor* method,
|
||||
CHECK(cntl->protocol_param().empty());
|
||||
cntl->protocol_param() = _options.protocol.param();
|
||||
}
|
||||
if (_options.protocol == brpc::PROTOCOL_HTTP) {
|
||||
URI& uri = cntl->http_request().uri();
|
||||
if (uri.host().empty() && !_service_name.empty()) {
|
||||
uri.SetHostAndPort(_service_name);
|
||||
}
|
||||
}
|
||||
cntl->_preferred_index = _preferred_index;
|
||||
cntl->_retry_policy = _options.retry_policy;
|
||||
if (_options.enable_circuit_breaker) {
|
||||
@@ -562,7 +577,7 @@ int Channel::CheckHealth() {
|
||||
return -1;
|
||||
} else {
|
||||
SocketUniquePtr tmp_sock;
|
||||
LoadBalancer::SelectIn sel_in = { 0, false, false, 0, NULL };
|
||||
LoadBalancer::SelectIn sel_in = { 0, false, true, 0, NULL };
|
||||
LoadBalancer::SelectOut sel_out(&tmp_sock);
|
||||
return _lb->SelectServer(sel_in, &sel_out);
|
||||
}
|
||||
|
||||
@@ -213,8 +213,10 @@ protected:
|
||||
int InitChannelOptions(const ChannelOptions* options);
|
||||
int InitSingle(const butil::EndPoint& server_addr_and_port,
|
||||
const char* raw_server_address,
|
||||
const ChannelOptions* options);
|
||||
const ChannelOptions* options,
|
||||
int raw_port = -1);
|
||||
|
||||
std::string _service_name;
|
||||
butil::EndPoint _server_address;
|
||||
SocketId _server_id;
|
||||
Protocol::SerializeRequest _serialize_request;
|
||||
|
||||
@@ -243,6 +243,7 @@ void Controller::ResetPods() {
|
||||
_timeout_ms = UNSET_MAGIC_NUM;
|
||||
_backup_request_ms = UNSET_MAGIC_NUM;
|
||||
_connect_timeout_ms = UNSET_MAGIC_NUM;
|
||||
_real_timeout_ms = UNSET_MAGIC_NUM;
|
||||
_deadline_us = -1;
|
||||
_timeout_id = 0;
|
||||
_begin_time_us = 0;
|
||||
@@ -308,6 +309,7 @@ void Controller::Call::Reset() {
|
||||
void Controller::set_timeout_ms(int64_t timeout_ms) {
|
||||
if (timeout_ms <= 0x7fffffff) {
|
||||
_timeout_ms = timeout_ms;
|
||||
_real_timeout_ms = timeout_ms;
|
||||
} else {
|
||||
_timeout_ms = 0x7fffffff;
|
||||
LOG(WARNING) << "timeout_ms is limited to 0x7fffffff (roughly 24 days)";
|
||||
@@ -977,6 +979,12 @@ void Controller::HandleSendFailed() {
|
||||
|
||||
void Controller::IssueRPC(int64_t start_realtime_us) {
|
||||
_current_call.begin_time_us = start_realtime_us;
|
||||
|
||||
// If has retry/backup request,we will recalculate the timeout,
|
||||
if (_real_timeout_ms > 0) {
|
||||
_real_timeout_ms -= (start_realtime_us - _begin_time_us) / 1000;
|
||||
}
|
||||
|
||||
// Clear last error, Don't clear _error_text because we append to it.
|
||||
_error_code = 0;
|
||||
|
||||
|
||||
@@ -736,6 +736,8 @@ private:
|
||||
int32_t _timeout_ms;
|
||||
int32_t _connect_timeout_ms;
|
||||
int32_t _backup_request_ms;
|
||||
// If this rpc call has retry/backup request,this var save the real timeout for current call
|
||||
int64_t _real_timeout_ms;
|
||||
// Deadline of this RPC (since the Epoch in microseconds).
|
||||
int64_t _deadline_us;
|
||||
// Timer registered to trigger RPC timeout event
|
||||
|
||||
@@ -57,6 +57,10 @@ public:
|
||||
return _cntl->_current_call.sending_sock.get();
|
||||
}
|
||||
|
||||
int64_t real_timeout_ms() {
|
||||
return _cntl->_real_timeout_ms;
|
||||
}
|
||||
|
||||
void move_in_server_receiving_sock(SocketUniquePtr& ptr) {
|
||||
CHECK(_cntl->_current_call.sending_sock == NULL);
|
||||
_cntl->_current_call.sending_sock.reset(ptr.release());
|
||||
|
||||
@@ -34,11 +34,11 @@ int LoadBalancerWithNaming::Init(const char* ns_url, const char* lb_name,
|
||||
return -1;
|
||||
}
|
||||
if (GetNamingServiceThread(&_nsthread_ptr, ns_url, options) != 0) {
|
||||
LOG(FATAL) << "Fail to get NamingServiceThread";
|
||||
LOG(ERROR) << "Fail to get NamingServiceThread";
|
||||
return -1;
|
||||
}
|
||||
if (_nsthread_ptr->AddWatcher(this, filter) != 0) {
|
||||
LOG(FATAL) << "Fail to add watcher into _server_list";
|
||||
LOG(ERROR) << "Fail to add watcher into _server_list";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -337,7 +337,7 @@ int NamingServiceThread::AddWatcher(NamingServiceWatcher* watcher,
|
||||
return -1;
|
||||
}
|
||||
BAIDU_SCOPED_LOCK(_mutex);
|
||||
if (_watchers.insert(std::make_pair(watcher, filter)).second) {
|
||||
if (_watchers.emplace(watcher, filter).second) {
|
||||
if (!_last_sockets.empty()) {
|
||||
std::vector<ServerId> added_ids;
|
||||
ServerNodeWithId2ServerId(_last_sockets, &added_ids, filter);
|
||||
|
||||
@@ -52,6 +52,12 @@ EspMessage* EspMessage::New() const {
|
||||
return new EspMessage;
|
||||
}
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
EspMessage* EspMessage::New(::google::protobuf::Arena* arena) const {
|
||||
return CreateMaybeMessage<EspMessage>(arena);
|
||||
}
|
||||
#endif
|
||||
|
||||
void EspMessage::Clear() {
|
||||
head.body_len = 0;
|
||||
body.clear();
|
||||
|
||||
@@ -54,6 +54,9 @@ public:
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
EspMessage* New() const;
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
EspMessage* New(::google::protobuf::Arena* arena) const override;
|
||||
#endif
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const EspMessage& from);
|
||||
|
||||
@@ -129,6 +129,7 @@ struct GlobalExtensions {
|
||||
#endif
|
||||
FileNamingService fns;
|
||||
ListNamingService lns;
|
||||
DomainListNamingService dlns;
|
||||
DomainNamingService dns;
|
||||
DomainNamingService dns_with_ssl;
|
||||
RemoteFileNamingService rfns;
|
||||
@@ -350,6 +351,7 @@ static void GlobalInitializeOrDieImpl() {
|
||||
#endif
|
||||
NamingServiceExtension()->RegisterOrDie("file", &g_ext->fns);
|
||||
NamingServiceExtension()->RegisterOrDie("list", &g_ext->lns);
|
||||
NamingServiceExtension()->RegisterOrDie("dlist", &g_ext->dlns);
|
||||
NamingServiceExtension()->RegisterOrDie("http", &g_ext->dns);
|
||||
NamingServiceExtension()->RegisterOrDie("https", &g_ext->dns_with_ssl);
|
||||
NamingServiceExtension()->RegisterOrDie("redis", &g_ext->dns);
|
||||
|
||||
@@ -67,31 +67,43 @@ ParseResult InputMessenger::CutInputMessage(
|
||||
// selection or by client.
|
||||
if (preferred >= 0 && preferred <= max_index
|
||||
&& _handlers[preferred].parse != NULL) {
|
||||
ParseResult result =
|
||||
_handlers[preferred].parse(&m->_read_buf, m, read_eof, _handlers[preferred].arg);
|
||||
if (result.is_ok() ||
|
||||
result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
|
||||
*index = preferred;
|
||||
return result;
|
||||
} else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
|
||||
// Critical error, return directly.
|
||||
LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
|
||||
<< "A message from " << m->remote_side()
|
||||
<< "(protocol=" << _handlers[preferred].name
|
||||
<< ") is bigger than " << FLAGS_max_body_size
|
||||
<< " bytes, the connection will be closed."
|
||||
" Set max_body_size to allow bigger messages";
|
||||
return result;
|
||||
}
|
||||
if (m->CreatedByConnect() &&
|
||||
// baidu_std may fall to streaming_rpc
|
||||
(ProtocolType)preferred != PROTOCOL_BAIDU_STD) {
|
||||
// The protocol is fixed at client-side, no need to try others.
|
||||
LOG(ERROR) << "Fail to parse response from " << m->remote_side()
|
||||
<< " by " << _handlers[preferred].name
|
||||
<< " at client-side";
|
||||
return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
|
||||
}
|
||||
int cur_index = preferred;
|
||||
do {
|
||||
ParseResult result =
|
||||
_handlers[cur_index].parse(&m->_read_buf, m, read_eof, _handlers[cur_index].arg);
|
||||
if (result.is_ok() ||
|
||||
result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
|
||||
m->set_preferred_index(cur_index);
|
||||
*index = cur_index;
|
||||
return result;
|
||||
} else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
|
||||
// Critical error, return directly.
|
||||
LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
|
||||
<< "A message from " << m->remote_side()
|
||||
<< "(protocol=" << _handlers[cur_index].name
|
||||
<< ") is bigger than " << FLAGS_max_body_size
|
||||
<< " bytes, the connection will be closed."
|
||||
" Set max_body_size to allow bigger messages";
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m->CreatedByConnect()) {
|
||||
if((ProtocolType)cur_index == PROTOCOL_BAIDU_STD) {
|
||||
// baidu_std may fall to streaming_rpc.
|
||||
cur_index = (int)PROTOCOL_STREAMING_RPC;
|
||||
continue;
|
||||
} else {
|
||||
// The protocol is fixed at client-side, no need to try others.
|
||||
LOG(ERROR) << "Fail to parse response from " << m->remote_side()
|
||||
<< " by " << _handlers[preferred].name
|
||||
<< " at client-side";
|
||||
return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
|
||||
}
|
||||
} else {
|
||||
// Try other protocols.
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
// Clear context before trying next protocol which probably has
|
||||
// an incompatible context with the current one.
|
||||
if (m->parsing_context()) {
|
||||
|
||||
@@ -63,6 +63,12 @@ MemcacheRequest* MemcacheRequest::New() const {
|
||||
return new MemcacheRequest;
|
||||
}
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
MemcacheRequest* MemcacheRequest::New(::google::protobuf::Arena* arena) const {
|
||||
return CreateMaybeMessage<MemcacheRequest>(arena);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemcacheRequest::Clear() {
|
||||
_buf.clear();
|
||||
_pipelined_count = 0;
|
||||
@@ -207,6 +213,13 @@ MemcacheResponse* MemcacheResponse::New() const {
|
||||
return new MemcacheResponse;
|
||||
}
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
MemcacheResponse*
|
||||
MemcacheResponse::New(::google::protobuf::Arena* arena) const {
|
||||
return CreateMaybeMessage<MemcacheResponse>(arena);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemcacheResponse::Clear() {
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ public:
|
||||
|
||||
// Protobuf methods.
|
||||
MemcacheRequest* New() const;
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
MemcacheRequest* New(::google::protobuf::Arena* arena) const override;
|
||||
#endif
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const MemcacheRequest& from);
|
||||
@@ -200,6 +203,9 @@ public:
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
MemcacheResponse* New() const;
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
MemcacheResponse* New(::google::protobuf::Arena* arena) const override;
|
||||
#endif
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const MemcacheResponse& from);
|
||||
|
||||
@@ -54,6 +54,12 @@ NsheadMessage* NsheadMessage::New() const {
|
||||
return new NsheadMessage;
|
||||
}
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
NsheadMessage* NsheadMessage::New(::google::protobuf::Arena* arena) const {
|
||||
return CreateMaybeMessage<NsheadMessage>(arena);
|
||||
}
|
||||
#endif
|
||||
|
||||
void NsheadMessage::Clear() {
|
||||
memset(&head, 0, sizeof(head));
|
||||
body.clear();
|
||||
|
||||
@@ -50,6 +50,9 @@ public:
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
NsheadMessage* New() const;
|
||||
#if GOOGLE_PROTOBUF_VERSION >= 3006000
|
||||
NsheadMessage* New(::google::protobuf::Arena* arena) const override;
|
||||
#endif
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const NsheadMessage& from);
|
||||
|
||||
@@ -42,6 +42,7 @@ message RpcRequestMeta {
|
||||
optional int64 span_id = 5;
|
||||
optional int64 parent_span_id = 6;
|
||||
optional string request_id = 7; // correspond to x-request-id in http header
|
||||
optional int32 timeout_ms = 8; // client's timeout setting for current call
|
||||
}
|
||||
|
||||
message RpcResponseMeta {
|
||||
|
||||
@@ -51,6 +51,9 @@ DEFINE_bool(baidu_protocol_use_fullname, true,
|
||||
"If this flag is true, baidu_std puts service.full_name in requests"
|
||||
", otherwise puts service.name (required by jprotobuf).");
|
||||
|
||||
DEFINE_bool(baidu_std_protocol_deliver_timeout_ms, false,
|
||||
"If this flag is true, baidu_std puts timeout_ms in requests.");
|
||||
|
||||
// Notes:
|
||||
// 1. 12-byte header [PRPC][body_size][meta_size]
|
||||
// 2. body_size and meta_size are in network byte order
|
||||
@@ -228,10 +231,12 @@ void SendRpcResponse(int64_t correlation_id,
|
||||
if (span) {
|
||||
span->set_response_size(res_buf.size());
|
||||
}
|
||||
if (stream_ptr) {
|
||||
CHECK(accessor.remote_stream_settings() != NULL);
|
||||
// Send rpc response over stream even if server side failed to create
|
||||
// stream for some reasons.
|
||||
if(cntl->has_remote_stream()){
|
||||
// Send the response over stream to notify that this stream connection
|
||||
// is successfully built.
|
||||
// Response_stream can be INVALID_STREAM_ID when error occurs.
|
||||
if (SendStreamData(sock, &res_buf,
|
||||
accessor.remote_stream_settings()->stream_id(),
|
||||
accessor.response_stream()) != 0) {
|
||||
@@ -239,13 +244,18 @@ void SendRpcResponse(int64_t correlation_id,
|
||||
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *sock;
|
||||
cntl->SetFailed(errcode, "Fail to write into %s",
|
||||
sock->description().c_str());
|
||||
((Stream*)stream_ptr->conn())->Close();
|
||||
if(stream_ptr) {
|
||||
((Stream*)stream_ptr->conn())->Close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Now it's ok the mark this server-side stream as connectted as all the
|
||||
// written user data would follower the RPC response.
|
||||
((Stream*)stream_ptr->conn())->SetConnected();
|
||||
} else {
|
||||
|
||||
if(stream_ptr) {
|
||||
// Now it's ok the mark this server-side stream as connectted as all the
|
||||
// written user data would follower the RPC response.
|
||||
((Stream*)stream_ptr->conn())->SetConnected();
|
||||
}
|
||||
} else{
|
||||
// Have the risk of unlimited pending responses, in which case, tell
|
||||
// users to set max_concurrency.
|
||||
Socket::WriteOptions wopt;
|
||||
@@ -346,6 +356,9 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
|
||||
if (request_meta.has_request_id()) {
|
||||
cntl->set_request_id(request_meta.request_id());
|
||||
}
|
||||
if (request_meta.has_timeout_ms()) {
|
||||
cntl->set_timeout_ms(request_meta.timeout_ms());
|
||||
}
|
||||
cntl->set_request_compress_type((CompressType)meta.compress_type());
|
||||
accessor.set_server(server)
|
||||
.set_security_mode(security_mode)
|
||||
@@ -487,7 +500,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
|
||||
req.get(), res.get(), server,
|
||||
method_status, msg->received_us());
|
||||
|
||||
// optional, just release resourse ASAP
|
||||
// optional, just release resource ASAP
|
||||
msg.reset();
|
||||
req_buf.clear();
|
||||
|
||||
@@ -552,18 +565,21 @@ void ProcessRpcResponse(InputMessageBase* msg_base) {
|
||||
|
||||
const bthread_id_t cid = { static_cast<uint64_t>(meta.correlation_id()) };
|
||||
Controller* cntl = NULL;
|
||||
|
||||
StreamId remote_stream_id = meta.has_stream_settings() ? meta.stream_settings().stream_id(): INVALID_STREAM_ID;
|
||||
|
||||
const int rc = bthread_id_lock(cid, (void**)&cntl);
|
||||
if (rc != 0) {
|
||||
LOG_IF(ERROR, rc != EINVAL && rc != EPERM)
|
||||
<< "Fail to lock correlation_id=" << cid << ": " << berror(rc);
|
||||
if (meta.has_stream_settings()) {
|
||||
if (remote_stream_id != INVALID_STREAM_ID) {
|
||||
SendStreamRst(msg->socket(), meta.stream_settings().stream_id());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ControllerPrivateAccessor accessor(cntl);
|
||||
if (meta.has_stream_settings()) {
|
||||
if (remote_stream_id != INVALID_STREAM_ID) {
|
||||
accessor.set_remote_stream_settings(
|
||||
new StreamSettings(meta.stream_settings()));
|
||||
}
|
||||
@@ -615,7 +631,7 @@ void ProcessRpcResponse(InputMessageBase* msg_base) {
|
||||
} while (0);
|
||||
// Unlocks correlation_id inside. Revert controller's
|
||||
// error code if it version check of `cid' fails
|
||||
msg.reset(); // optional, just release resourse ASAP
|
||||
msg.reset(); // optional, just release resource ASAP
|
||||
accessor.OnResponse(cid, saved_error);
|
||||
}
|
||||
|
||||
@@ -672,6 +688,13 @@ void PackRpcRequest(butil::IOBuf* req_buf,
|
||||
if (attached_size) {
|
||||
meta.set_attachment_size(attached_size);
|
||||
}
|
||||
|
||||
if (FLAGS_baidu_std_protocol_deliver_timeout_ms) {
|
||||
if (accessor.real_timeout_ms() > 0) {
|
||||
request_meta->set_timeout_ms(accessor.real_timeout_ms());
|
||||
}
|
||||
}
|
||||
|
||||
Span* span = accessor.span();
|
||||
if (span) {
|
||||
request_meta->set_trace_id(span->trace_id());
|
||||
|
||||