RPCX 分布式的RPC
最后更新于:2022-04-02 02:49:48
[TOC]
> [作者文章](https://colobu.com/2016/05/26/RPCX-a-distributed-rpc-dubbo-like-framework-by-Go/#RPC%E6%98%AF%E4%BB%80%E4%B9%88)
> [github](http://github.com/smallnest/rpcx)
>
## 概述
原因在于尽管这些框架(grpc ,net/rpc 等)都是为Go实现的RPC库,但是它们的功能比较单一,只是实现了点对点(End-to-End)的通讯框架。缺乏服务治理的功能,比如服务注册和发现、
负载均衡、容灾、服务监控等功能。因此我基于Go net/rpc框架实现了一个类似Dubbo的分布式框架。
* 基于net/rpc,可以将net/rpc实现的RPC项目轻松的转换为分布式的RPC
* 插件式设计,可以配置所需的插件,比如服务发现、日志、统计分析等
* 基于TCP长连接,只需很小的额外的消息头
* 支持多种编解码协议,如Gob、Json、MessagePack、gencode、ProtoBuf等
* 服务发现:服务发布、订阅、通知等,支持多种发现方式如ZooKeeper、Etcd等
* 高可用策略:失败重试(Failover)、快速失败(Failfast)
* 负载均衡:支持随机请求、轮询、低并发优先、一致性 Hash等
* 规模可扩展,可以根据性能的需求增减服务器
* 其他:调用统计、访问日志等
### 服务发现
* [Peer to Peer](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#peer2peer): 客户端直连每个服务节点。 the client connects the single service directly. It acts like the`client`type.
* [Peer to Multiple](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#multiple): 客户端可以连接多个服务。服务可以被编程式配置。
* [Zookeeper](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#zookeeper): 通过 zookeeper 寻找服务。
* [Etcd](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#etcd): 通过 etcd 寻找服务。
* [Consul](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#consul): 通过 consul 寻找服务。
* [mDNS](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#mdns): 通过 mDNS 寻找服务(支持本地服务发现)。
* [In process](https://books.studygolang.com/go-rpc-programming-guide/part2/registry.html#inprocess): 在同一进程寻找服务。客户端通过进程调用服务,不走TCP或UDP,方便调试使用。
## 客户端特性
### 故障模式:
* [Failfast](https://books.studygolang.com/go-rpc-programming-guide/part3/failmode.html#failfast):如果调用失败,立即返回错误
* [Failover](https://books.studygolang.com/go-rpc-programming-guide/part3/failmode.html#failover):选择其他节点,直到达到最大重试次数
* [Failtry](https://books.studygolang.com/go-rpc-programming-guide/part3/failmode.html#failtry):选择相同节点并重试,直到达到最大重试次数
### 负载均衡选择器:
* [Random](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#random_selector): 随机选择节点
* [Roundrobin](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#roundrobin_selector): 使用[roundrobin](https://zh.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E5%88%B6)算法选择节点
* [Consistent hashing](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#hash_selector): 如果服务路径、方法和参数一致,就选择同一个节点。使用了非常快的[jump consistent hash](https://arxiv.org/abs/1406.2294)算法。
* [Weighted](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#weighted_selector): 根据元数据里配置好的权重(`weight=xxx`)来选择节点。类似于nginx里的实现(smooth weighted algorithm)
* [Network quality](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#ping_selector): 根据`ping`的结果来选择节点。网络质量越好,该节点被选择的几率越大。
* [Geography](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#geo_selector): 如果有多个数据中心,客户端趋向于连接同一个数据机房的节点。
* [Customized Selector](https://books.studygolang.com/go-rpc-programming-guide/part3/selector.html#user_selector): 如果以上的选择器都不适合你,你可以自己定制选择器。例如一个rpcx用户写过它自己的选择器,他有2个数据中心,但是这些数据中心彼此有限制,不能使用`Network quality`来检测连接质量。
### 广播与群发
`Broadcast`表示向所有服务器发送请求,只有**所有**服务器正确返回时才会成功。此时FailMode 和 SelectMode的设置是无效的。请设置超时来避免阻塞。
`Fork`表示向所有服务器发送请求,只要**任意一**台服务器正确返回就成功。此时FailMode 和 SelectMode的设置是无效的。
```
xClient := client.NewXClient(router, conf.GetRpcFailMode(), conf.GetRpcSelectMode(), d, client.DefaultOption)
xClient.Fork()
xClient.Broadcast()
```
### 扩展点
可对一下扩展点进行扩展,Client的扩展点如下:
读取Response Header的前后
读取Response Body的前后
写Request的前后
## Benchmark
pcx基于Go net/rpc框架实现,它的插件机制并不会带来多少性能的损失
```
[root@localhost rpcx]# go test -bench . -test.benchmem
PASS
BenchmarkNetRPC_gob-16 100000 18742 ns/op 321 B/op 9 allocs/op
BenchmarkNetRPC_jsonrpc-16 100000 21360 ns/op 1170 B/op 31 allocs/op
BenchmarkNetRPC_msgp-16 100000 18617 ns/op 776 B/op 35 allocs/op
BenchmarkRPCX_gob-16 100000 18718 ns/op 320 B/op 9 allocs/op
BenchmarkRPCX_json-16 100000 21238 ns/op 1170 B/op 31 allocs/op
BenchmarkRPCX_msgp-16 100000 18635 ns/op 776 B/op 35 allocs/op
BenchmarkRPCX_gencodec-16 100000 18454 ns/op 4485 B/op 17 allocs/op
BenchmarkRPCX_protobuf-16 100000 17234 ns/op 733 B/op 13 allocs/op
```
## 安装
安装 rpcx:
`go get -u -v github.com/smallnest/rpcx/...
`
如果你想要使用 etcd 作为注册中心,加上etcd这个标签。
`go get -u -v -tags "etcd" github.com/smallnest/rpcx/...
`
如果你想要使用 quic
`go get -u -v -tags "quic etcd" github.com/smallnest/rpcx/...
`
方便起见,我推荐你安装所有的tags,即使你现在并不需要他们:
`go get -u -v -tags "reuseport quic kcp zookeeper etcd consul ping" github.com/smallnest/rpcx/...
`
tags 对应:
* quic: 支持 quic 协议
* kcp: 支持 kcp 协议
* zookeeper: 支持 zookeeper 注册中心
* etcd: 支持 etcd 注册中心
* consul: 支持 consul 注册中心
* ping: 支持 网络质量负载均衡
* reuseport: 支持 reuseport
## 问题
### undefined: resolver.BuildOption undefined: resolver.ResolveNowOption
[参考](http://54wcs.com/post/%E5%A4%84%E7%90%86go1.13%E4%B8%8Betcd.v3%E9%94%99%E8%AF%AF%E9%97%AE%E9%A2%98/)
1. 修改 go.mod
```
replace github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.0.0
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
```
`go get ./...`
';