sofa-pbrpc cookie功能设计
背景
在rpc的应用场景中,用户需要传输非protobuf协议封装的数据,数据的格式和操作由用户定义,这些数据最终都以字节流的方式在client和server之间传输。需要在sofa-pbrpc内部实现一套attachment机制,支持用户自定义附加数据的格式和操作,用户在client端设置附加数据,server端接受并进行操作。基于该机制为用户提供默认的Cookie插件,用于存储和传输logid等client端的状态信息。
功能
实现sofa-pbrpc attachment机制,支持用户附加数据,附加数据的定义和操作在用户层实现。并基于此机制实现cookie插件
接口设计
- 在sofa-pbrpc中实现RpcAttachment的基类,包括Serialize和Deserialize的接口,用户层实现插件继承RpcAttachment并在此基础上实现增删改查的操作,用户在client中通过RpcController的set_request_attachment的接口设置附加数据,并调用Serialize接口将用户附加数据进行序列化,Append在request_buffer之后进行发送。
- 在RpcServer端对收到的请求数据反序列化,在请求数据的末尾获取用户的附加数据,通过controller传输给用户。用户调用RpcController:: GetRequestAttachment(RpcAttachment& attach), 利用attach对象的Deserialize接口将附加数据反序列化。Server端可以对attachment数据进行增删改查
Attachment基类:
class RpcAttachment
{
public:
virtual ~RpcAttachment() { }
virtual bool Serialize(ReadBufferPtr attactment_buffer) = 0;
virtual bool Deserialize (ReadBufferPtr attachment_buffer) = 0;
};
RpcController增加接口:
RpcAttachmentPtr_request_attachment; //RPC请求的附加数据buffer
RpcAttachmentPtr _response_attachment; //RPC应答的附加数据buffer
ReadBufferPtr _request_attach_buffer; //RPC请求的附加数据buffer
ReadBufferPtr _response_attach_buffer; //RPC应答的附加数据buffer
//用户接口
//设置请求的附加数据
void SetRequestAttachment(RpcAttachment* request_attachment);
//获取请求的附加数据
void GetRequestAttachment(RpcAttachment* request_attachment);
//设置应答的附加数据
void SetResponseAttachment(RpcAttachment* response_attachment);
//获取应答的附加数据
void GetResponseAttachment(RpcAttachment* response_attachment);
//Rpc内部接口
//设置request_attachment_buffer
void SetRequestAttachmentBuffer(const ReadBufferPtr& attachment_buffer);
//获取request_attachment_buffer
const ReadBufferPtr& GetRequestBuffer() const;
//设置response_attachment_buffer
void SetResponseAttachmentBuffer(const ReadBufferPtr& attachment_buffer);
////获取response_attachment_buffer
const ReadBufferPtr& GetResponseBuffer() const;
使用方法
Cookie插件:
Class RpcCookie : public sofa::pbrpc:: RpcAttachment
{
virtual bool Serialize(ReadBufferPtr& attactment_buffer) ;
virtual bool Deserialize (const ReadBufferPtr& attachment_buffer);
void Get(const std::string key, std::string& value);
void Set(const std::string& key, const std::string value);
void Erase(const std::string& key);
void Clear();
}
Client端示例:
sofa::pbrpc::RpcController* cntl = new sofa::pbrpc::RpcController();
cntl->SetTimeout(3000);
CookiePtr cookie(new Cookie());
cookie->set("type", "sync");
cntl->SetRequestAttachment(cookie.get());
sofa::pbrpc::test::EchoRequest* request = new sofa::pbrpc::test::EchoRequest();
request->set_message("Hello from client");
sofa::pbrpc::test::EchoResponse* response = new sofa::pbrpc::test::EchoResponse();
sofa::pbrpc::test::EchoServer_Stub* stub =new sofa::pbrpc::test::EchoServer_Stub(&rpc_channel);
stub->Echo(cntl, request, response, NULL);
if (cntl->Failed())
{
SLOG(ERROR, "request failed: %s", cntl->ErrorText().c_str());
}
else
{
cookie.reset(new Cookie());
cntl->GetResponseAttachment(cookie.get());
std::string version;
cookie->Get(“version”, version);
SLOG(NOTICE, "request succeed: %s, version: %s", response->message().c_str(), version.c_str());
}
Server端示例:
virtual void Echo(google::protobuf::RpcController* controller,
const sofa::pbrpc::test::EchoRequest* request,
sofa::pbrpc::test::EchoResponse* response,
google::protobuf::Closure* done)
{
sofa::pbrpc::RpcController* cntl = static_cast<sofa::pbrpc::RpcController*>(controller);
SLOG(INFO, "Echo(): request message from %s: %s",
cntl->RemoteAddress().c_str(), request->message().c_str());
CookiePtr cookie(new Cookie());
cntl->GetRequestAttachment(cookie.get());
cookie->Set(“version”, “1.00”);
cntl->SetResponseAttachment(cookie.get());
response->set_message("echo message: " + request->message());
done->Run();
}
@qinzuoyan ,左言有什么建议?
这个和sofa里面的cookie机制是一样的吗?实现上有什么区别?
sofa里的cookie是在库里边实现的,即数据格式规定是kv map。这个设计在库里边增加了RpcAttachment基类、序列化反序列化接口以及用户接口,cookie作为插件在用户层继承RpcAttachment,定义了数据格式和序列化、反序列化操作等。
恩,明白了,这个要赞,用户可定制自己的attachment,更灵活。
另外我建议,可以实现一些常见的实现,在编译的时候,可以类似protobuf一样生成一个lite库和一个full库。譬如可以在full库中提供这些常见实现:
- Cookie,实现RpcAttachment接口;
- BufferAttachment,实现RpcAttachment接口,用于传输大数据,避免通过Message的string字段传输时增加序列化/反序列化代价,使用者可以之间在Buffer上进行操作。这个对实现传输数据量很大的系统(譬如DFS)非常有用;
- ZookeeperAddressProvier,实现AddressProvider接口,用于从Zookeeper动态获取server地址,参见#78 ;
@qinzuoyan ,左言有时间帮忙审核一下pr#81?
Ok, 最近找时间review
On Mon, Apr 4, 2016 at 10:44 PM, zd-double [email protected] wrote:
@qinzuoyan https://github.com/qinzuoyan ,左言有时间帮忙审核一下pr#81 https://github.com/baidu/sofa-pbrpc/pull/81?
— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/baidu/sofa-pbrpc/issues/79#issuecomment-205328115
赞!