Go语言的RPC介绍(含Protobuf-RPC)
2015-08-22 18:53
886 查看
标准库的RPC
RPC是远程调用的简称, 简单的说就是要像调用本地函数一样调用服务器的函数.Go语言的标准库已经提供了RPC框架和不同的RPC实现.
下面是一个服务器的例子:
?
rpc.Register用于注册RPC服务, 默认的名字是对象的类型名字(这里是
Echo).
如果需要指定特殊的名字, 可以用
rpc.RegisterName进行注册.
被注册对象的类型所有满足以下规则的方法会被导出到RPC服务接口:
?
然后
rpc.HandleHTTP用于指定 RPC 的传输协议, 这里是采用 http 协议作为RPC调用的载体. 用户也可以用
rpc.ServeConn接口,
定制自己的传输协议.
客户端可以这样调用
Echo.Hi接口:
?
rpc.DialHTTP和RPC服务器进行一个链接(协议必须匹配).
然后通过返回的
client对象进行远程函数调用. 函数的名字是由
client.Call第一个参数指定(是一个字符串).
基于HTTP的RPC调用一般是在调试时使用, 默认可以通过浏览
"127.0.0.1:1234/debug/rpc"页面查看RPC的统计信息.
回到顶部
基于 JSON 的 RPC 调用
在上面的RPC例子中, 我们采用了默认的HTTP协议作为RPC调用的传输载体.因为内置
net/rpc包接口设计的缺陷, 我们无法使用
jsonrpc等定制的编码作为
rpc.DialHTTP的底层协议.
如果需要让
jsonrpc支持
rpc.DialHTTP函数,
需要调整rpc的接口.
以前有个Issue2738是针对这个问题. 我曾提交的 CL10704046 补丁用于修复这个问题.
不过因为涉及到增加rpc的接口, 官方没有接受(因为自己重写一个
DialHTTP会更简单).
除了传输协议, 还有可以指定一个RPC编码协议, 用于编码/节目RPC调用的函数参数和返回值. RPC调用不指定编码协议时, 默认采用Go语言特有的
gob编码协议.
因为, 其他语言一般都不支持Go语言的
gob协议, 因此如果需要跨语言RPC调用就需要
采用通用的编码协议.
Go的标准库还提供了一个
"net/rpc/jsonrpc"包, 用于提供基于JSON编码的RPC支持.
服务器部分只需要用
rpc.ServeCodec指定json编码协议就可以了:
?
jsonrpc.Dial代替
rpc.Dial就可以了:
?
jsonrpc和Go语言进行通讯, 需要封装一个和
jsonrpc
匹配的库.
关于
jsonrpc的实现细节这里就不展开讲了, 感兴趣的话可以参考这篇文章: JSON-RPC:
a tale of interfaces.
回到顶部
基于 Protobuf 的 RPC 调用
Protobuf 是 Google 公司开发的编码协议. 它的优势是编码后的数据体积比较小(并不是压缩算法), 比较适合用于命令的传输编码.Protobuf 官方团队提供 Java/C++/Python 几个语言的支持, Go语言的版本由Go团队提供支持, 其他语言由第三方支持.
Protobuf 的语言规范中可以定义RPC接口. 但是在Go语言和C++版本的Protobuf中都没有生成RPC的实现.
不过作者在 Go语言版本的Protobuf基础上开发了 RPC 的实现 protorpc, 同时提供的
protoc-gen-go命令可以生成相应的RPC代码.
项目地址: https://code.google.com/p/protorpc/
该实现支持Go语言和C++语言, 在Protobuf官方wiki的第三方RPC实现列表中有介绍:https://code.google.com/p/protobuf/wiki/ThirdPartyAddOns#RPC_Implementations
要使用 protorpc, 需要先在proto文件定义接口(
arith.pb/arith.proto):
?
cc_generic_services选择控制是否输出RPC代码.
因此, 需要设置
cc_generic_services为
true.
然后下载 protoc-2.5.0-win32.zip, 解压后可以得到一个
protoc.exe的编译命令.
然后使用下面的命令获取 protorpc 和对应的
protoc-gen-go插件.
?
protoc.exe和
protoc-gen-go.exe都在
$PATH中.
然后运行以下命令将前面的接口文件转换为Go代码:
?
arith.pb/arith.pb.go.
下面是基于 Protobuf-RPC 的服务器:
?
"./arith.pb"的名字为
arith,
在
arith.pb/arith.proto文件中定义(这2个可能不同名, 导入时要小心).
arith.ArithRequest和
arith.ArithResponse是RPC接口的输入和输出参数,
也是在在
arith.pb/arith.proto文件中定义的.
同时生成的还有一个
arith.ListenAndServeArithService函数, 用于启动RPC服务. 该函数的第三个参数是RPC的服务对象, 必须要满足
arith.EchoService接口的定义.
客户端的使用也很简单, 只要一个
arith.DialArithService就可以链接了:
?
arith.DialArithService返回了一个
stub对象,
该对象已经绑定了RPC的各种方法, 可以直接调用(不需要用字符串指定方法名字):
?
采用标准的Protobuf协议, 便于和其他语言交互
自带的
protoc-gen-go插件可以生成RPC的代码, 简化使用
服务器注册和调用客户端都是具体类型而不是字符串和
interface{}, 这样可以由编译器保证安全
底层采用了
snappy压缩传输的数据, 提高效率
不足之处是使用流程比标准RPC要繁复(需要将proto转换为Go代码).
回到顶部
C++ 调用 Go 提供的 Protobuf-RPC 服务
protorpc 同时也提供了 C++ 语言的实现.C++版本的安装如下:
hg clone https://code.google.com/p/protorpc.cxx/[/code]cd protorpc.cxx
build with cmake
C++ 版本 的 protorpc 对protoc.exe扩展了一个--cxx_out选项, 用于生成RPC的代码:
?
--cxx_out选项生成的代码除了RPC支持外, 还有xml的序列化和反序列化支持.
下面是 C++ 的客户端链接 Go 语言版本的 服务器:
?
更多的例子请参考: rpcserver.cc
和 rpcclient.cc
回到顶部
总结
Go语言的RPC客户端是一个使用简单, 而且功能强大的RPC库. 基于标准的RPC库我们可以方便的定制自己的RPC实现(传输协议和串行化协议都可以定制).不过在开发 protorpc 的过程中也发现了
net/rpc包的一些不足之处:
内置的
HTTP协议的RPC的串行化协议和传输协议耦合过于紧密, 用户扩展的协议无法支持内置的
HTTP传输协议(因为
rpc.Server和
rpc.Client接口缺陷导致的问题)
rpc.Server只能注册
rpc.ServerCodec,
而不能注册工厂函数. 而
jsonrpc.NewServerCodec需要依赖先建立链接(
conn参数),
这样导致了
HTTP协议只能支持内置的
gob协议
rpc.Client的问题和
rpc.Server类似
因为Go1需要保证API的兼容性, 因此上述的问题只能希望在未来的Go2能得到改善.
相关文章推荐
- Bingo部署成功 纪念一下
- Good Bye 2014 D. New Year Santa Network 树形dp
- ZJU 2562 More Divisors (反素数)
- hdu4760Good Firewall(Trie树)
- Chrome浏览器设置小窗口视频
- Codeforces 27 E Number With The Given Amount Of Divisors
- hdu-3966 Aragorn's Story(树链剖分,点权)
- poj 2909 Goldbach's Conjecture (哥德巴赫猜想)
- pymongo中的连接操作:Connection()与MongoClient()
- Good Bye 2014 C. New Year Book Reading 贪心
- Good Bye 2014 B. New Year Permutation 并查集 最短路 floyed算法
- 基于Google Material Design设计开发,模块包括图片浏览,视频爽看 ,音乐轻听以及二维码扫描
- Codeforces Round #313 (Div. 2) C. Gerald's Hexagon
- Go 1.5中值得关注的几个变化
- 投资问题,lingo程序
- Go 的垃圾回收机制在实践中有哪些需要注意的地方?
- Go语言教程汇总
- Go语言中使用panic和recover简化错误处理
- Go获取命令行参数及信号量处理
- Go各种类型转换及函数的高级用法