您的位置:首页 > 其它

以小见大——那些基于 protobuf 的五花八门的 RPC(5 完)

2011-04-14 18:11 746 查看
赖勇浩(http://laiyonghao.com)

快刀斩乱麻,祭上最后两个 rpc 分析,再整上我自己的设计,这个系列就完结了。

protobuf-socket-rpc

好,废话不多说,看看这个 protobuf-socket-rpc,简介是 Java and Python protobuf rpc implementation using tcp/ip sockets,听说支持 java 的服务器和 python 的客户端,有点怪怪地哈?基本格式见:http://code.google.com/p/protobuf-socket-rpc/source/browse/trunk/proto/rpc.proto
,引用全文如下:

package protobuf.socketrpc;
option java_package = "com.googlecode.protobuf.socketrpc";
option java_outer_classname = "SocketRpcProtos";
message Request {
// RPC service full name
required string service_name = 1;

// RPC method name
required string method_name = 2;

// RPC request proto
required bytes request_proto = 3;
}
message Response {
// RPC response proto
optional bytes response_proto = 1;

// Error, if any
optional string error = 2;

// Was callback invoked
optional bool callback = 3 [default = false];

// Error Reason
optional ErrorReason error_reason = 4;
}
// Possible error reasons
// The server-side errors are returned in the response from the server.
// The client-side errors are returned by the client-side code when it doesn't
// have a response from the server.
enum ErrorReason {
// Server-side errors
BAD_REQUEST_DATA = 0; // Server received bad request data
BAD_REQUEST_PROTO = 1; // Server received bad request proto
SERVICE_NOT_FOUND = 2; // Service not found on server
METHOD_NOT_FOUND = 3; // Method not found on server
RPC_ERROR = 4; // Rpc threw exception on server
RPC_FAILED = 5; // Rpc failed on server

// Client-side errors (these are returned by the client-side code)
INVALID_REQUEST_PROTO = 6; // Rpc was called with invalid request proto
BAD_RESPONSE_PROTO = 7; // Server returned a bad response proto
UNKNOWN_HOST = 8; // Could not find supplied host
IO_ERROR = 9; // I/O error while communicating with server
}


很眼熟啊,是的,跟之前看过的 fepss-rpc 几乎一样,除了这里定义了更多的错误类型,连注释都几乎一模一样啊,不知道谁抄谁的。所以没啥好说的了,唯一可以唠叨一下的是它跟 fepss-rpc 都采用无 ID 的设计,所以不能 parallel pipelining,细节见(http://blog.csdn.net/lanphaday/archive/2011/04/11/6316099.aspx
)。

txprotobuf

以 Python 始,再以 Python 终,最后一个是 protocol buffers (http://code.google.com/p/protobuf/) RPC implemented using python twisted framework.,基于 twisted 的 rpc,虽然我不喜欢 twisted,但不影响我看 txprotobuf 哈。它的基本格式见:http://bazaar.launchpad.net/~proppy/txprotobuf/master/view/head:/protobuf/txprotobuf.proto
,照例全文引过来:

// Copyright (c) 2008 Johan Euphrosine
// See LICENSE for details.
message Call {
required uint32 token = 1;
required string method = 2;
required bytes request = 3;
}
message Result {
required uint32 token = 1;
required bytes response = 2;
}
message Box {
optional bytes call = 1;
optional bytes result = 2;
}


简洁,跟 casocklib 相似的设计。唯一能够说一下的就是只有 method 字段而没有 service 字段所以没有办法做到 multi-service。另外,Box 这个命名我很喜欢。

我自己的设计

本来想单独作为一篇的,后来发现前两个实在没啥好说啊,干脆就整合在一起得了。好,上代码:

enum PackageType {
HEARTBEAT = 0;
ERROR = 1;
REQUEST = 2;
RESPONSE = 3;
};
message Heartbeat {
};
message Error {
required string info = 1;
};
message Request {
required string service = 1;
required string method = 2;
optional bytes request = 3;
};
message Response {
optional bytes response = 1;
};
message Package {
required PackageType type = 1;
required uint32 identify = 2;
required bytes serialized = 3;
};
message Placeholder {
};


首先是学习 server1 定义了几种数据包的类型,不过我扩展了一下,加了心跳和错误这两种包。心跳在这里就是简单的一个空包,只是激活一下 TCP 连接,以免超时断开。如果要复杂一点的,可以参考陈硕《分布式系统的工程化开发方法》 p.51 心跳协议的设计(http://blog.csdn.net/Solstice/archive/2010/10/19/5950190.aspx
)。

message Error 很简单,只有一个 info 字段。之前也在想要不要加个数字枚举来让调用端了解一下基本出了啥错,后来我想还是不要了。主要是出错了对于调用端来说没有什么挽救手段啊,只能是往日志里写一句,然后该干啥干啥去,既然如此,又何必多此一举呢,直接把错误的文本从服务器端传过来就好了。

message Request 带了 service 和 method 字段,为的是明晰地表达咱支持 multi-service。而的 request 字段是 optional 的,为的是支持“空”参数调用 RPC。Message Response 的 optional bytes response 也是类似,为了支持“空”返回值。因为 protobuf 的 rpc 声明不支持 rpc XXX()returns() 这样的无参数无返回值的声明,所以我又在后面声明了一个 message Placeholder,这样 rpc 声明就可以写成 rpc XXX(Placeholder)returns(Placeholder)。调用代码时,可以直接写成 proxy.service.XXX() 这样子,由我们自己的 Proxy/Channel 实现去处理好这个占位参数和返回值就行了。

最后,整个连接上传输的数据包就只有一种:message Package,不论是 Heartbeat、Error、Rquest 或 Response,最后都会序列化到 Package.serialized 里去。

对比这么多实现,我的这个版本既没有像 protobuf-remote 般自由开放的调用参数机制,也没有 protobuf-rpc-pro 可以返回超大块数据的内置方案。不过我还是比较满意,太自由和太重量的方案不符合我的技术观。

我打算基于 gevent 实现这个 rpc。

===== 完 ======
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: