sofa-pbrpc icon indicating copy to clipboard operation
sofa-pbrpc copied to clipboard

sofa-pbrpc cookie功能设计

Open zd-double opened this issue 9 years ago • 7 comments

背景

在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();
    }

zd-double avatar Mar 18 '16 03:03 zd-double

@qinzuoyan ,左言有什么建议?

zd-double avatar Mar 18 '16 04:03 zd-double

这个和sofa里面的cookie机制是一样的吗?实现上有什么区别?

qinzuoyan avatar Mar 21 '16 06:03 qinzuoyan

sofa里的cookie是在库里边实现的,即数据格式规定是kv map。这个设计在库里边增加了RpcAttachment基类、序列化反序列化接口以及用户接口,cookie作为插件在用户层继承RpcAttachment,定义了数据格式和序列化、反序列化操作等。

zd-double avatar Mar 21 '16 07:03 zd-double

恩,明白了,这个要赞,用户可定制自己的attachment,更灵活。

另外我建议,可以实现一些常见的实现,在编译的时候,可以类似protobuf一样生成一个lite库和一个full库。譬如可以在full库中提供这些常见实现:

  • Cookie,实现RpcAttachment接口;
  • BufferAttachment,实现RpcAttachment接口,用于传输大数据,避免通过Message的string字段传输时增加序列化/反序列化代价,使用者可以之间在Buffer上进行操作。这个对实现传输数据量很大的系统(譬如DFS)非常有用;
  • ZookeeperAddressProvier,实现AddressProvider接口,用于从Zookeeper动态获取server地址,参见#78 ;

qinzuoyan avatar Mar 21 '16 11:03 qinzuoyan

@qinzuoyan ,左言有时间帮忙审核一下pr#81?

zd-double avatar Apr 04 '16 14:04 zd-double

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

qinzuoyan avatar Apr 05 '16 02:04 qinzuoyan

赞!

stonehuang1024 avatar Apr 25 '16 03:04 stonehuang1024