Commit e9775fbe authored by gejun's avatar gejun

Split intro part in README into overview.md

parent 5ccc531f
......@@ -2,39 +2,7 @@
[![Build Status](https://travis-ci.org/brpc/brpc.svg?branch=master)](https://travis-ci.org/brpc/brpc)
# What is RPC?
Most machines on internet communicate with each other via [TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite). However, TCP/IP only guarantees reliable data transmissions. We need to abstract more to build services:
* What is the format of data transmission? Different machines and networks may have different byte-orders, directly sending in-memory data is not suitable. Fields in the data are added, modified or removed gradually, how do newer services talk with older services?
* Can TCP connection be reused for multiple requests to reduce overhead? Can multiple requests be sent through one TCP connection simultaneously?
* How to talk with a cluster with many machines?
* What should I do when the connection is broken? What if the server does not respond?
* ...
[RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) addresses the above issues by abstracting network communications as "clients accessing functions on servers": client sends a request to server, wait until server receives -> processes -> responds to the request, then do actions according to the result.
![rpc.png](docs/images/rpc.png)
Let's see how the issues are solved.
* RPC needs serialization which is done by [protobuf](https://github.com/google/protobuf) pretty well. Users fill requests in format of protobuf::Message, do RPC, and fetch results from responses in protobuf::Message. protobuf has good forward and backward compatibility for users to change fields and build services incrementally. For http services, [json](http://www.json.org/) is used for serialization extensively.
* Establishment and re-using of connections is transparent to users, but users can make choices like [different connection types](docs/en/client.md#connection-type): short, pooled, single.
* Machines are discovered by a Naming Service, which can be implemented by [DNS](https://en.wikipedia.org/wiki/Domain_Name_System), [ZooKeeper](https://zookeeper.apache.org/) or [etcd](https://github.com/coreos/etcd). Inside Baidu, we use BNS (Baidu Naming Service). brpc provides ["list://" and "file://"](docs/en/client.md#naming-service) as well. Users specify load balancing algorithms to choose one machine for each request from all machines, including: round-robin, randomized, [consistent-hashing](docs/cn/consistent_hashing.md)(murmurhash3 or md5) and [locality-aware](docs/cn/lalb.md).
* RPC retries when the connection is broken. When server does not respond within the given time, client fails with a timeout error.
# Where can I use RPC?
Almost all network communications.
RPC can't do everything surely, otherwise we don't need the layer of TCP/IP. But in most network communications, RPC meets requirements and isolates the underlying details.
Common doubts on RPC:
- My data is binary and large, using protobuf will be slow. First, this is possibly a wrong feeling and you will have to test it and prove it with [profilers](docs/cn/cpu_profiler.md). Second, many protocols support carrying binary data along with protobuf requests and bypass the serialization.
- I'm sending streaming data which can't be processed by RPC. Actually many protocols in RPC can handle streaming data, including [ProgressiveReader in http](docs/en/http_client.md#progressively-download), streams in h2, [streaming rpc](docs/en/streaming_rpc.md), and RTMP which is a specialized streaming protocol.
- I don't need replies. With some inductions, we know that in your scenario requests can be dropped at any stage because the client is always unaware of the situation. Are you really sure this is acceptable? Even if you don't need the reply, we recommend sending back small-sized replies, which are unlikely to be performance bottlenecks and will probably provide valuable clues when debugging complex bugs.
# What is ![brpc](docs/images/logo.png)?
# ![brpc](docs/images/logo.png)
A industrial-grade RPC framework used throughout [Baidu](http://ir.baidu.com/phoenix.zhtml?c=188488&p=irol-irhome), with **600,000+** instances(not counting clients) and **500+** kinds of services, called "**baidu-rpc**" inside Baidu. Only C++ implementation is opensourced right now.
......@@ -56,48 +24,10 @@ You can use it to:
* Get [better latency and throughput](#better-latency-and-throughput).
* [Extend brpc](docs/en/new_protocol.md) with the protocols used in your organization quickly, or customize components, including [naming services](docs/cn/load_balancing.md#名字服务) (dns, zk, etcd), [load balancers](docs/cn/load_balancing.md#负载均衡) (rr, random, consistent hashing)
# Advantages of brpc
### More friendly API
Only 3 (major) user headers: [Server](https://github.com/brpc/brpc/blob/master/src/brpc/server.h), [Channel](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h), [Controller](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h), corresponding to server-side, client-side and parameter-set respectively. You don't have to worry about "How to initialize XXXManager", "How to layer all these components together", "What's the relationship between XXXController and XXXContext". All you need to do is simple:
* Build service? include [brpc/server.h](https://github.com/brpc/brpc/blob/master/src/brpc/server.h) and follow the comments or [examples](https://github.com/brpc/brpc/blob/master/example/echo_c++/server.cpp).
* Access service? include [brpc/channel.h](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h) and follow the comments or [examples](https://github.com/brpc/brpc/blob/master/example/echo_c++/client.cpp).
* Tweak parameters? Checkout [brpc/controller.h](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h). Note that the class is shared by server and channel. Methods are separated into 3 parts: client-side, server-side and both-side.
We tried to make simple things simple. Take naming service as an example. In older RPC implementations you may need to copy a pile of obscure code to make it work, however, in brpc accessing BNS is expressed as `Init("bns://node-name", ...)`, DNS is `Init("http://domain-name", ...)` and local machine list is `Init("file:///home/work/server.list", ...)`. Without any explanation, you know what it means.
### Make services more reliable
brpc is extensively used in Baidu:
* map-reduce service & table storages
* high-performance computing & model training
* all sorts of indexing & ranking servers
* ….
It's been proven.
brpc pays special attentions to development and maintenance efficency, you can [view internal status of servers](docs/en/builtin_service.md) in web browser or with curl, analyze [cpu hotspots](docs/cn/cpu_profiler.md), [heap allocations](docs/cn/heap_profiler.md) and [lock contentions](docs/cn/contention_profiler.md) of online services, measure stats by [bvar](docs/en/bvar.md) which is viewable in [/vars](docs/en/vars.md).
### Better latency and throughput
Although almost all RPC implementations claim that they're "high-performant", the numbers are probably just numbers. Being really high-performant in different scenarios is difficult. To unify communication infra inside Baidu, brpc goes much deeper at performance than other implementations.
* Reading and parsing requests from different clients is fully parallelized and users don't need to distinguish between "IO-threads" and "Processing-threads". Other implementations probably have "IO-threads" and "Processing-threads" and hash file descriptors(fd) into IO-threads. When a IO-thread handles one of its fds, other fds in the thread can't be handled. If a message is large, other fds are significantly delayed. Although different IO-threads run in parallel, you won't have many IO-threads since they don't have too much to do generally except reading/parsing from fds. If you have 10 IO-threads, one fd may affect 10% of all fds, which is unacceptable to industrial online services (requiring 99.99% availability). The problem will be worse when fds are distributed unevenly accross IO-threads (unfortunately common), or the service is multi-tenancy (common in cloud services). In brpc, reading from different fds is parallelized and even processing different messages from one fd is parallelized as well. Parsing a large message does not block other messages from the same fd, not to mention other fds. More details can be found [here](docs/en/io.md#receiving-messages).
* Writing into one fd and multiple fds is highly concurrent. When multiple threads write into the same fd (common for multiplexed connections), the first thread directly writes in-place and other threads submit their write requests in [wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom) manner. One fd can be written into 5,000,000 16-byte messages per second by a couple of highly-contended threads. More details can be found [here](docs/en/io.md#sending-messages).
* Minimal locks. High-QPS services can utilize all CPU power on the machine. For example, [creating bthreads](docs/cn/memory_management.md) for processing requests, [setting up timeout](docs/cn/timer_keeping.md), [finding RPC contexts](docs/cn/bthread_id.md) according to response, [recording performance counters](docs/en/bvar.md) are all highly concurrent. Users see very few contentions (via [contention profiler](docs/cn/contention_profiler.md)) caused by RPC framework even if the service runs at 500,000+ QPS.
* Server adjusts thread number according to load. Traditional implementations set number of threads according to latency to avoid limiting the throughput. brpc creates a new [bthread](docs/cn/bthread.md) for each request and ends the bthread when the request is done, which automatically adjusts thread number according to load.
Check [benchmark](docs/cn/benchmark.md) for a comparison between brpc and other implementations.
# Try it!
* Read [building steps](docs/cn/getting_started.md) to get started.
* Play with [examples](https://github.com/brpc/brpc/tree/master/example/).
* Read [overview](docs/en/overview.md) to know where brpc can be used and its advantages.
* Read [building steps](docs/cn/getting_started.md) to get started and play with [examples](https://github.com/brpc/brpc/tree/master/example/).
* Docs:
* [Performance benchmark](docs/cn/benchmark.md)
* [bvar](docs/en/bvar.md)
......@@ -162,3 +92,17 @@ Check [benchmark](docs/cn/benchmark.md) for a comparison between brpc and other
* [联盟DSP](docs/cn/case_baidu_dsp.md)
* [ELF学习框架](docs/cn/case_elf.md)
* [云平台代理服务](docs/cn/case_ubrpc.md)
# Contribute code
brpc welcomes contributions, especially those on adapting different platforms and extending protocols.
Make sure the code meets following requirements before submitting your PR:
- Conforms to [google C++ coding style](https://google.github.io/styleguide/cppguide.html)
- The code appears where it should be. For example the code to support an extra protocol should not be put in general classes like server.cpp, channel.cpp, while a general modification would better not be hidden inside a very specific protocol.
- Has unittests.
Check following items after submitting the PR:
- Compilations and unittests in [travis-ci](https://travis-ci.org/brpc/brpc) are passed.
\ No newline at end of file
......@@ -2,41 +2,7 @@
[![Build Status](https://travis-ci.org/brpc/brpc.svg?branch=master)](https://travis-ci.org/brpc/brpc)
# 什么是RPC?
互联网上的机器大都通过[TCP/IP协议](http://en.wikipedia.org/wiki/Internet_protocol_suite)相互访问,但TCP/IP只是往远端发送了一段二进制数据,为了建立服务还有很多问题需要抽象:
- 数据以什么格式传输?不同机器间,网络间可能是不同的字节序,直接传输内存数据显然是不合适的;随着业务变化,数据字段往往要增加或删减,怎么兼容前后不同版本的格式?
- 一个TCP连接可以被多个请求复用以减少开销么?多个请求可以同时发往一个TCP连接么?
- 如何访问一个包含很多机器的集群?
- 连接断开时应该干什么?万一server不发送回复怎么办?
* ...
[RPC](http://en.wikipedia.org/wiki/Remote_procedure_call)可以解决这些问题,它把网络交互类比为“client访问server上的函数”:client向server发送request后开始等待,直到server收到、处理、回复client后,client又再度恢复并根据response做出反应。
![rpc.png](docs/images/rpc.png)
我们来看看上面的一些问题是如何解决的:
- RPC需要序列化,[protobuf](https://github.com/google/protobuf)在这方面做的很好。用户填写protobuf::Message类型的request,RPC结束后,从同为protobuf::Message类型的response中取出结果。protobuf有较好的前后兼容性,方便业务调整字段。http广泛使用[json](http://www.json.org/)作为序列化方法。
- 用户不需要关心连接是如何建立的,但可以选择不同的[连接方式](docs/cn/client.md#连接方式):短连接,连接池,单连接。
- 一个集群中的所有机器一般通过名字服务被发现,可基于[DNS](https://en.wikipedia.org/wiki/Domain_Name_System), [ZooKeeper](https://zookeeper.apache.org/), [etcd](https://github.com/coreos/etcd)等实现。在百度内,我们使用BNS (Baidu Naming Service)。brpc也提供["list://"和"file://"](docs/cn/client.md#名字服务)。用户可以指定负载均衡算法,让RPC每次选出一台机器发送请求,包括: round-robin, randomized, [consistent-hashing](docs/cn/consistent_hashing.md)(murmurhash3 or md5)和 [locality-aware](docs/cn/lalb.md).
- 连接断开时按用户的配置进行重试。如果server没有在给定时间内返回response,那么client会返回超时错误。
# 哪里可以使用RPC?
几乎所有的网络交互。
RPC不是万能的抽象,否则我们也不需要TCP/IP这一层了。但是在我们绝大部分的网络交互中,RPC既能解决问题,又能隔离更底层的网络问题。
对于RPC常见的质疑有:
- 我的数据非常大,用protobuf序列化太慢了。首先这可能是个伪命题,你得用[profiler](docs/cn/cpu_profiler.md)证明慢了才是真的慢,其次很多协议支持携带二进制数据以绕过序列化。
- 我传输的是流数据,RPC表达不了。事实上brpc中很多协议支持传递流式数据,包括[http中的ProgressiveReader](docs/cn/http_client.md#持续下载), h2的streams, [streaming rpc](docs/cn/streaming_rpc.md), 和专门的流式协议RTMP。
- 我的场景不需要回复。简单推理可知,你的场景中请求可丢可不丢,可处理也可不处理,因为client总是无法感知,你真的确认这是OK的?即使场景真的不需要,我们仍然建议用最小的结构体回复,因为这不大会是瓶颈,并且追查复杂bug时可能是很有价值的线索。
# 什么是![brpc](docs/images/logo.png)?
# ![brpc](docs/images/logo.png)
百度内最常使用的工业级RPC框架, 有超过**600,000**个实例(不包含client)和**500**多种服务, 在百度内叫做"**baidu-rpc**". 目前只开源C++版本。
......@@ -59,46 +25,10 @@ RPC不是万能的抽象,否则我们也不需要TCP/IP这一层了。但是
* 获得[更好的延时和吞吐](#更好的延时和吞吐).
* 把你组织中使用的协议快速地[加入brpc](docs/cn/new_protocol.md),或定制各类组件, 包括[名字服务](docs/cn/load_balancing.md#名字服务) (dns, zk, etcd), [负载均衡](docs/cn/load_balancing.md#负载均衡) (rr, random, consistent hashing)
# brpc的优势
### 更友好的接口
只有三个(主要的)用户类: [Server](https://github.com/brpc/brpc/blob/master/src/brpc/server.h), [Channel](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h), [Controller](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h), 分别对应server端,client端,参数集合. 你不必推敲诸如"如何初始化XXXManager", "如何组合各种组件", "XXXController的XXXContext间的关系是什么"。要做的很简单:
* 建服务? 包含[brpc/server.h](https://github.com/brpc/brpc/blob/master/src/brpc/server.h)并参考注释或[示例](https://github.com/brpc/brpc/blob/master/example/echo_c++/server.cpp).
* 访问服务? 包含[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",相信不用解释,你也能明白这些代表什么。
### 使服务更加可靠
brpc在百度内被广泛使用:
* map-reduce服务和table存储
* 高性能计算和模型训练
* 各种索引和排序服务
* ….
它是一个经历过考验的实现。
brpc特别重视开发和维护效率, 你可以通过浏览器或curl[查看server内部状态](docs/cn/builtin_service.md), 分析在线服务的[cpu热点](docs/cn/cpu_profiler.md), [内存分配](docs/cn/heap_profiler.md)[锁竞争](docs/cn/contention_profiler.md), 通过[bvar](docs/cn/bvar.md)统计各种指标并通过[/vars](docs/cn/vars.md)查看。
### 更好的延时和吞吐
虽然大部分RPC实现都声称“高性能”,但数字仅仅是数字,要在广泛的场景中做到高性能仍是困难的。为了统一百度内的通信架构,brpc在性能方面比其他RPC走得更深。
- 对不同客户端请求的读取和解析是完全并发的,用户也不用区分”IO线程“和”处理线程"。其他实现往往会区分“IO线程”和“处理线程”,并把[fd](http://en.wikipedia.org/wiki/File_descriptor)(对应一个客户端)散列到IO线程中去。当一个IO线程在读取其中的fd时,同一个线程中的fd都无法得到处理。当一些解析变慢时,比如特别大的protobuf message,同一个IO线程中的其他fd都遭殃了。虽然不同IO线程间的fd是并发的,但你不太可能开太多IO线程,因为这类线程的事情很少,大部分时候都是闲着的。如果有10个IO线程,一个fd能影响到的”其他fd“仍有相当大的比例(10个即10%,而工业级在线检索要求99.99%以上的可用性)。这个问题在fd没有均匀地分布在IO线程中,或在多租户(multi-tenacy)环境中会更加恶化。在brpc中,对不同fd的读取是完全并发的,对同一个fd中不同消息的解析也是并发的。解析一个特别大的protobuf message不会影响同一个客户端的其他消息,更不用提其他客户端的消息了。更多细节看[这里](docs/cn/io.md#收消息)
- 对同一fd和不同fd的写出是高度并发的。当多个线程都要对一个fd写出时(常见于单连接),第一个线程会直接在原线程写出,其他线程会以[wait-free](http://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)的方式托付自己的写请求,多个线程在高度竞争下仍可以在1秒内对同一个fd写入500万个16字节的消息。更多细节看[这里](docs/cn/io.md#发消息)
- 尽量少的锁。高QPS服务可以充分利用一台机器的CPU。比如为处理请求[创建bthread](docs/cn/memory_management.md), [设置超时](docs/cn/timer_keeping.md), 根据回复[找到RPC上下文](docs/cn/bthread_id.md), [记录性能计数器](docs/cn/bvar.md)都是高度并发的。即使服务的QPS超过50万,用户也很少在[contention profiler](docs/cn/contention_profiler.md))中看到框架造成的锁竞争。
- 服务器线程数自动调节。传统的服务器需要根据下游延时的调整自身的线程数,否则吞吐可能会受影响。在brpc中,每个请求均运行在新建立的[bthread](docs/cn/bthread.md)中,请求结束后线程就结束了,所以天然会根据负载自动调节线程数。
brpc和其他实现的性能对比见[这里](docs/cn/benchmark.md)
# 试一下!
* [编译步骤](docs/cn/getting_started.md)开始.
* 一下[示例程序](https://github.com/brpc/brpc/tree/master/example/).
* 通过[概述](docs/cn/overview.md)了解哪里可以用brpc及其优势。
* 阅读[编译步骤](docs/cn/getting_started.md)了解如何开始使用, 之后可以运行一下[示例程序](https://github.com/brpc/brpc/tree/master/example/).
* 文档:
* [性能测试](docs/cn/benchmark.md)
* [bvar](docs/cn/bvar.md)
......@@ -163,3 +93,17 @@ brpc和其他实现的性能对比见[这里](docs/cn/benchmark.md)。
* [联盟DSP](docs/cn/case_baidu_dsp.md)
* [ELF学习框架](docs/cn/case_elf.md)
* [云平台代理服务](docs/cn/case_ubrpc.md)
# 贡献代码
brpc欢迎贡献代码,特别是对不同平台,协议的扩展代码。
提交PR前请确认你的代码符合如下要求:
* 符合[google C++代码规范](https://google.github.io/styleguide/cppguide.html)
* 代码出现的位置和其定位相符。比如对于某特定协议的扩展代码不该出现在server.cpp, channel.cpp这些较为通用的类中,而一些非常通用的改动也不该深藏在某个特定协议的cpp中。
* 有对应的单测代码。
提交PR后请检查如下内容:
* [travis-ci](https://travis-ci.org/brpc/brpc)中的编译和单测均已成功。
\ No newline at end of file
[English version](README.md)
[![Build Status](https://travis-ci.org/brpc/brpc.svg?branch=master)](https://travis-ci.org/brpc/brpc)
# 什么是RPC?
互联网上的机器大都通过[TCP/IP协议](http://en.wikipedia.org/wiki/Internet_protocol_suite)相互访问,但TCP/IP只是往远端发送了一段二进制数据,为了建立服务还有很多问题需要抽象:
- 数据以什么格式传输?不同机器间,网络间可能是不同的字节序,直接传输内存数据显然是不合适的;随着业务变化,数据字段往往要增加或删减,怎么兼容前后不同版本的格式?
- 一个TCP连接可以被多个请求复用以减少开销么?多个请求可以同时发往一个TCP连接么?
- 如何访问一个包含很多机器的集群?
- 连接断开时应该干什么?万一server不发送回复怎么办?
* ...
[RPC](http://en.wikipedia.org/wiki/Remote_procedure_call)可以解决这些问题,它把网络交互类比为“client访问server上的函数”:client向server发送request后开始等待,直到server收到、处理、回复client后,client又再度恢复并根据response做出反应。
![rpc.png](../images/rpc.png)
我们来看看上面的一些问题是如何解决的:
- RPC需要序列化,[protobuf](https://github.com/google/protobuf)在这方面做的很好。用户填写protobuf::Message类型的request,RPC结束后,从同为protobuf::Message类型的response中取出结果。protobuf有较好的前后兼容性,方便业务调整字段。http广泛使用[json](http://www.json.org/)作为序列化方法。
- 用户不需要关心连接是如何建立的,但可以选择不同的[连接方式](client.md#连接方式):短连接,连接池,单连接。
- 一个集群中的所有机器一般通过名字服务被发现,可基于[DNS](https://en.wikipedia.org/wiki/Domain_Name_System), [ZooKeeper](https://zookeeper.apache.org/), [etcd](https://github.com/coreos/etcd)等实现。在百度内,我们使用BNS (Baidu Naming Service)。brpc也提供["list://"和"file://"](client.md#名字服务)。用户可以指定负载均衡算法,让RPC每次选出一台机器发送请求,包括: round-robin, randomized, [consistent-hashing](consistent_hashing.md)(murmurhash3 or md5)和 [locality-aware](lalb.md).
- 连接断开时按用户的配置进行重试。如果server没有在给定时间内返回response,那么client会返回超时错误。
# 哪里可以使用RPC?
几乎所有的网络交互。
RPC不是万能的抽象,否则我们也不需要TCP/IP这一层了。但是在我们绝大部分的网络交互中,RPC既能解决问题,又能隔离更底层的网络问题。
对于RPC常见的质疑有:
- 我的数据非常大,用protobuf序列化太慢了。首先这可能是个伪命题,你得用[profiler](cpu_profiler.md)证明慢了才是真的慢,其次很多协议支持携带二进制数据以绕过序列化。
- 我传输的是流数据,RPC表达不了。事实上brpc中很多协议支持传递流式数据,包括[http中的ProgressiveReader](http_client.md#持续下载), h2的streams, [streaming rpc](streaming_rpc.md), 和专门的流式协议RTMP。
- 我的场景不需要回复。简单推理可知,你的场景中请求可丢可不丢,可处理也可不处理,因为client总是无法感知,你真的确认这是OK的?即使场景真的不需要,我们仍然建议用最小的结构体回复,因为这不大会是瓶颈,并且追查复杂bug时可能是很有价值的线索。
# 什么是![brpc](../images/logo.png)?
百度内最常使用的工业级RPC框架, 有超过**600,000**个实例(不包含client)和**500**多种服务, 在百度内叫做"**baidu-rpc**". 目前只开源C++版本。
你可以使用它:
* 搭建一个能在**同端口**支持多协议的服务, 或访问各种服务
* restful http/https, h2/h2c (与[grpc](https://github.com/grpc/grpc)兼容, 即将开源). 使用brpc的http实现比[libcurl](https://curl.haxx.se/libcurl/)方便多了。
* [redis](redis_client.md)[memcached](memcache_client.md), 线程安全,比官方client更方便。
* [rtmp](https://github.com/brpc/brpc/blob/master/src/brpc/rtmp.h)/[flv](https://en.wikipedia.org/wiki/Flash_Video)/[hls](https://en.wikipedia.org/wiki/HTTP_Live_Streaming), 可用于搭建[直播服务](live_streaming.md).
* hadoop_rpc(仍未开源)
* 基于[openucx](https://github.com/openucx/ucx)支持[rdma](https://en.wikipedia.org/wiki/Remote_direct_memory_access)(即将开源)
* 各种百度内使用的协议: [baidu_std](baidu_std.md), [streaming_rpc](streaming_rpc.md), hulu_pbrpc, [sofa_pbrpc](https://github.com/baidu/sofa-pbrpc), nova_pbrpc, public_pbrpc, ubrpc和使用nshead的各种协议.
* 从其他语言通过HTTP+json访问基于protobuf的协议.
* 基于工业级的[RAFT算法](https://raft.github.io)实现搭建[高可用](https://en.wikipedia.org/wiki/High_availability)分布式系统 (即将在[braft](https://github.com/brpc/braft)开源)
* 创建丰富的访问模式
* 服务都能以[同步](server.md)[异步](server.md#异步service)方式处理请求。
* 通过[同步](client.md#同步访问)[异步](client.md#异步访问)[半同步](client.md#半同步)访问服务。
* 使用[组合channels](combo_channel.md)声明式地简化复杂的分库或并发访问。
* [通过http](builtin_service.md)调试服务, 使用[cpu](cpu_profiler.md), [heap](heap_profiler.md), [contention](contention_profiler.md) profilers.
* 获得[更好的延时和吞吐](#更好的延时和吞吐).
* 把你组织中使用的协议快速地[加入brpc](new_protocol.md),或定制各类组件, 包括[名字服务](load_balancing.md#名字服务) (dns, zk, etcd), [负载均衡](load_balancing.md#负载均衡) (rr, random, consistent hashing)
# brpc的优势
### 更友好的接口
只有三个(主要的)用户类: [Server](https://github.com/brpc/brpc/blob/master/src/brpc/server.h), [Channel](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h), [Controller](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h), 分别对应server端,client端,参数集合. 你不必推敲诸如"如何初始化XXXManager", "如何组合各种组件", "XXXController的XXXContext间的关系是什么"。要做的很简单:
* 建服务? 包含[brpc/server.h](https://github.com/brpc/brpc/blob/master/src/brpc/server.h)并参考注释或[示例](https://github.com/brpc/brpc/blob/master/example/echo_c++/server.cpp).
* 访问服务? 包含[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",相信不用解释,你也能明白这些代表什么。
### 使服务更加可靠
brpc在百度内被广泛使用:
* map-reduce服务和table存储
* 高性能计算和模型训练
* 各种索引和排序服务
* ….
它是一个经历过考验的实现。
brpc特别重视开发和维护效率, 你可以通过浏览器或curl[查看server内部状态](builtin_service.md), 分析在线服务的[cpu热点](cpu_profiler.md), [内存分配](heap_profiler.md)[锁竞争](contention_profiler.md), 通过[bvar](bvar.md)统计各种指标并通过[/vars](vars.md)查看。
### 更好的延时和吞吐
虽然大部分RPC实现都声称“高性能”,但数字仅仅是数字,要在广泛的场景中做到高性能仍是困难的。为了统一百度内的通信架构,brpc在性能方面比其他RPC走得更深。
- 对不同客户端请求的读取和解析是完全并发的,用户也不用区分”IO线程“和”处理线程"。其他实现往往会区分“IO线程”和“处理线程”,并把[fd](http://en.wikipedia.org/wiki/File_descriptor)(对应一个客户端)散列到IO线程中去。当一个IO线程在读取其中的fd时,同一个线程中的fd都无法得到处理。当一些解析变慢时,比如特别大的protobuf message,同一个IO线程中的其他fd都遭殃了。虽然不同IO线程间的fd是并发的,但你不太可能开太多IO线程,因为这类线程的事情很少,大部分时候都是闲着的。如果有10个IO线程,一个fd能影响到的”其他fd“仍有相当大的比例(10个即10%,而工业级在线检索要求99.99%以上的可用性)。这个问题在fd没有均匀地分布在IO线程中,或在多租户(multi-tenacy)环境中会更加恶化。在brpc中,对不同fd的读取是完全并发的,对同一个fd中不同消息的解析也是并发的。解析一个特别大的protobuf message不会影响同一个客户端的其他消息,更不用提其他客户端的消息了。更多细节看[这里](io.md#收消息)
- 对同一fd和不同fd的写出是高度并发的。当多个线程都要对一个fd写出时(常见于单连接),第一个线程会直接在原线程写出,其他线程会以[wait-free](http://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)的方式托付自己的写请求,多个线程在高度竞争下仍可以在1秒内对同一个fd写入500万个16字节的消息。更多细节看[这里](io.md#发消息)
- 尽量少的锁。高QPS服务可以充分利用一台机器的CPU。比如为处理请求[创建bthread](memory_management.md), [设置超时](timer_keeping.md), 根据回复[找到RPC上下文](bthread_id.md), [记录性能计数器](bvar.md)都是高度并发的。即使服务的QPS超过50万,用户也很少在[contention profiler](contention_profiler.md))中看到框架造成的锁竞争。
- 服务器线程数自动调节。传统的服务器需要根据下游延时的调整自身的线程数,否则吞吐可能会受影响。在brpc中,每个请求均运行在新建立的[bthread](bthread.md)中,请求结束后线程就结束了,所以天然会根据负载自动调节线程数。
brpc和其他实现的性能对比见[这里](benchmark.md)
[中文版](README_cn.md)
[![Build Status](https://travis-ci.org/brpc/brpc.svg?branch=master)](https://travis-ci.org/brpc/brpc)
# What is RPC?
Most machines on internet communicate with each other via [TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite). However, TCP/IP only guarantees reliable data transmissions. We need to abstract more to build services:
* What is the format of data transmission? Different machines and networks may have different byte-orders, directly sending in-memory data is not suitable. Fields in the data are added, modified or removed gradually, how do newer services talk with older services?
* Can TCP connection be reused for multiple requests to reduce overhead? Can multiple requests be sent through one TCP connection simultaneously?
* How to talk with a cluster with many machines?
* What should I do when the connection is broken? What if the server does not respond?
* ...
[RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) addresses the above issues by abstracting network communications as "clients accessing functions on servers": client sends a request to server, wait until server receives -> processes -> responds to the request, then do actions according to the result.
![rpc.png](../images/rpc.png)
Let's see how the issues are solved.
* RPC needs serialization which is done by [protobuf](https://github.com/google/protobuf) pretty well. Users fill requests in format of protobuf::Message, do RPC, and fetch results from responses in protobuf::Message. protobuf has good forward and backward compatibility for users to change fields and build services incrementally. For http services, [json](http://www.json.org/) is used for serialization extensively.
* Establishment and re-using of connections is transparent to users, but users can make choices like [different connection types](client.md#connection-type): short, pooled, single.
* Machines are discovered by a Naming Service, which can be implemented by [DNS](https://en.wikipedia.org/wiki/Domain_Name_System), [ZooKeeper](https://zookeeper.apache.org/) or [etcd](https://github.com/coreos/etcd). Inside Baidu, we use BNS (Baidu Naming Service). brpc provides ["list://" and "file://"](client.md#naming-service) as well. Users specify load balancing algorithms to choose one machine for each request from all machines, including: round-robin, randomized, [consistent-hashing](../cn/consistent_hashing.md)(murmurhash3 or md5) and [locality-aware](../cn/lalb.md).
* RPC retries when the connection is broken. When server does not respond within the given time, client fails with a timeout error.
# Where can I use RPC?
Almost all network communications.
RPC can't do everything surely, otherwise we don't need the layer of TCP/IP. But in most network communications, RPC meets requirements and isolates the underlying details.
Common doubts on RPC:
- My data is binary and large, using protobuf will be slow. First, this is possibly a wrong feeling and you will have to test it and prove it with [profilers](../cn/cpu_profiler.md). Second, many protocols support carrying binary data along with protobuf requests and bypass the serialization.
- I'm sending streaming data which can't be processed by RPC. Actually many protocols in RPC can handle streaming data, including [ProgressiveReader in http](http_client.md#progressively-download), streams in h2, [streaming rpc](streaming_rpc.md), and RTMP which is a specialized streaming protocol.
- I don't need replies. With some inductions, we know that in your scenario requests can be dropped at any stage because the client is always unaware of the situation. Are you really sure this is acceptable? Even if you don't need the reply, we recommend sending back small-sized replies, which are unlikely to be performance bottlenecks and will probably provide valuable clues when debugging complex bugs.
# What is ![brpc](../images/logo.png)?
A industrial-grade RPC framework used throughout [Baidu](http://ir.baidu.com/phoenix.zhtml?c=188488&p=irol-irhome), with **600,000+** instances(not counting clients) and **500+** kinds of services, called "**baidu-rpc**" inside Baidu. Only C++ implementation is opensourced right now.
You can use it to:
* Build a server that can talk in multiple protocols (**on same port**), or access all sorts of services
* restful http/https, h2/h2c (compatible with [grpc](https://github.com/grpc/grpc), will be opensourced). using http in brpc is much more friendly than [libcurl](https://curl.haxx.se/libcurl/).
* [redis](redis_client.md) and [memcached](memcache_client.md), thread-safe, more friendly and performant than the official clients
* [rtmp](https://github.com/brpc/brpc/blob/master/src/brpc/rtmp.h)/[flv](https://en.wikipedia.org/wiki/Flash_Video)/[hls](https://en.wikipedia.org/wiki/HTTP_Live_Streaming), for building [live-streaming services](../cn/live_streaming.md).
* hadoop_rpc(not opensourced yet)
* [rdma](https://en.wikipedia.org/wiki/Remote_direct_memory_access) support via [openucx](https://github.com/openucx/ucx) (will be opensourced)
* all sorts of protocols used in Baidu: [baidu_std](../cn/baidu_std.md), [streaming_rpc](streaming_rpc.md), hulu_pbrpc, [sofa_pbrpc](https://github.com/baidu/sofa-pbrpc), nova_pbrpc, public_pbrpc, ubrpc, and nshead-based ones.
* Access protobuf-based protocols with HTTP+json, probably from another language.
* Build [HA](https://en.wikipedia.org/wiki/High_availability) distributed services using an industrial-grade implementation of [RAFT consensus algorithm](https://raft.github.io) (will be opensourced at [braft](https://github.com/brpc/braft))
* Create rich processing patterns
* Services can handle requests [synchronously](server.md) or [asynchronously](server.md#asynchronous-service).
* Access service [synchronously](client.md#synchronus-call) or [asynchronously](client.md#asynchronous-call), or even [semi-synchronously](client.md#semi-synchronous-call).
* Use [combo channels](combo_channel.md) to simplify complicated client patterns declaratively, including sharded and parallel accesses.
* Debug services [via http](builtin_service.md), and run [cpu](../cn/cpu_profiler.md), [heap](../cn/heap_profiler.md) and [contention](../cn/contention_profiler.md) profilers.
* Get [better latency and throughput](#better-latency-and-throughput).
* [Extend brpc](new_protocol.md) with the protocols used in your organization quickly, or customize components, including [naming services](../cn/load_balancing.md#名字服务) (dns, zk, etcd), [load balancers](../cn/load_balancing.md#负载均衡) (rr, random, consistent hashing)
# Advantages of brpc
### More friendly API
Only 3 (major) user headers: [Server](https://github.com/brpc/brpc/blob/master/src/brpc/server.h), [Channel](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h), [Controller](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h), corresponding to server-side, client-side and parameter-set respectively. You don't have to worry about "How to initialize XXXManager", "How to layer all these components together", "What's the relationship between XXXController and XXXContext". All you need to do is simple:
* Build service? include [brpc/server.h](https://github.com/brpc/brpc/blob/master/src/brpc/server.h) and follow the comments or [examples](https://github.com/brpc/brpc/blob/master/example/echo_c++/server.cpp).
* Access service? include [brpc/channel.h](https://github.com/brpc/brpc/blob/master/src/brpc/channel.h) and follow the comments or [examples](https://github.com/brpc/brpc/blob/master/example/echo_c++/client.cpp).
* Tweak parameters? Checkout [brpc/controller.h](https://github.com/brpc/brpc/blob/master/src/brpc/controller.h). Note that the class is shared by server and channel. Methods are separated into 3 parts: client-side, server-side and both-side.
We tried to make simple things simple. Take naming service as an example. In older RPC implementations you may need to copy a pile of obscure code to make it work, however, in brpc accessing BNS is expressed as `Init("bns://node-name", ...)`, DNS is `Init("http://domain-name", ...)` and local machine list is `Init("file:///home/work/server.list", ...)`. Without any explanation, you know what it means.
### Make services more reliable
brpc is extensively used in Baidu:
* map-reduce service & table storages
* high-performance computing & model training
* all sorts of indexing & ranking servers
* ….
It's been proven.
brpc pays special attentions to development and maintenance efficency, you can [view internal status of servers](builtin_service.md) in web browser or with curl, analyze [cpu hotspots](../cn/cpu_profiler.md), [heap allocations](../cn/heap_profiler.md) and [lock contentions](../cn/contention_profiler.md) of online services, measure stats by [bvar](bvar.md) which is viewable in [/vars](vars.md).
### Better latency and throughput
Although almost all RPC implementations claim that they're "high-performant", the numbers are probably just numbers. Being really high-performant in different scenarios is difficult. To unify communication infra inside Baidu, brpc goes much deeper at performance than other implementations.
* Reading and parsing requests from different clients is fully parallelized and users don't need to distinguish between "IO-threads" and "Processing-threads". Other implementations probably have "IO-threads" and "Processing-threads" and hash file descriptors(fd) into IO-threads. When a IO-thread handles one of its fds, other fds in the thread can't be handled. If a message is large, other fds are significantly delayed. Although different IO-threads run in parallel, you won't have many IO-threads since they don't have too much to do generally except reading/parsing from fds. If you have 10 IO-threads, one fd may affect 10% of all fds, which is unacceptable to industrial online services (requiring 99.99% availability). The problem will be worse when fds are distributed unevenly accross IO-threads (unfortunately common), or the service is multi-tenancy (common in cloud services). In brpc, reading from different fds is parallelized and even processing different messages from one fd is parallelized as well. Parsing a large message does not block other messages from the same fd, not to mention other fds. More details can be found [here](io.md#receiving-messages).
* Writing into one fd and multiple fds is highly concurrent. When multiple threads write into the same fd (common for multiplexed connections), the first thread directly writes in-place and other threads submit their write requests in [wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom) manner. One fd can be written into 5,000,000 16-byte messages per second by a couple of highly-contended threads. More details can be found [here](io.md#sending-messages).
* Minimal locks. High-QPS services can utilize all CPU power on the machine. For example, [creating bthreads](../cn/memory_management.md) for processing requests, [setting up timeout](../cn/timer_keeping.md), [finding RPC contexts](../cn/bthread_id.md) according to response, [recording performance counters](bvar.md) are all highly concurrent. Users see very few contentions (via [contention profiler](../cn/contention_profiler.md)) caused by RPC framework even if the service runs at 500,000+ QPS.
* Server adjusts thread number according to load. Traditional implementations set number of threads according to latency to avoid limiting the throughput. brpc creates a new [bthread](../cn/bthread.md) for each request and ends the bthread when the request is done, which automatically adjusts thread number according to load.
Check [benchmark](../cn/benchmark.md) for a comparison between brpc and other implementations.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment