基于Protobuf共享字段的分包和透传零拷贝技术

技术基于Protobuf共享字段的分包和透传零拷贝技术 基于Protobuf共享字段的分包和透传零拷贝技术https://mp.weixin.qq.com/s/isOzeuwsn_-5TUqsLcgTn

基于Protobuf共享字段的分包和透明零拷贝技术

https://mp.weixin.qq.com/s/isOzeuwsn_-5TUqsLcgTnQ

基于Protobuf共享字段的分包和透传零拷贝技术,你了解吗

原朱文杰贾云社区2021-11-10

简介|本文介绍了Protobuf共享字段Guard的实现,并将其应用于中控/召回场景,获得了显著的CPU/延迟收益。即使不使用Guard,希望本文的经验和思路也能给读者带来一些帮助和参考。

引言

在推荐系统中,用户级字段往往需要贯穿整个环节,如实验参数、行为序列、用户画像等。

召回/过滤/分类模块都需要用户特征。这时候,自然最好的方法就是从请求一开始就一次性获取信息,然后传递给路透社。此前,作者经常写道:

const getrecordeq oReq;//来自rpcRankReq或oRankReqoRankReq.mutable _ user _人像()-copy from(oreq . user _人像());

这种透明传输自然是有益的,例如,如果下游需要用户特征,则不必再次请求每个请求。尤其是当上游发起分包时,用户级特征的透明传输可以显著降低下游获取用户特征的RPC开销。

然而,RPC开销减少了,再得陇望蜀想一想,是否能直接省去这个CopyFrom的开销呢

我们知道,protobuf提供了Allocated/Release系列接口,通过直接转移指针所有权,消除了Copy或Swap的开销。

换句话说,如果指针所有权是借出的而不是转移的,那么共享字段是可以实现的。借用实际上是使用前转移字段指针,使用后立即收回(收回所有权防止删除)。这是经典的卫士抽象。

当然,即使不使用Guard,我相信上面的想法也足以提供一些帮助。我们可以直接使用pb的接口来实现:

const getrecordeq oReq;//来自rpcgetrecommandreq=omplaceereq=const _ castgetrecordeq(oReq);RankReq oRankReqoRankReq.set _ allocated _ user _人像(oMutableReq.mutable _ user _人像());客户。等级(oRankReq);oRankReq.release _ user _人像();

对于一些比较复杂的操作,比如我想复制一些字段,共享一些字段,修改一些字段(分包场景),我们在下面给出我们的解决方案。

设计

我们的卫士提供了两个接口,即连接和分离。接口如下。通过pb的反射机制,release和set_allocated可以相互绑定,实现Guard销毁时的回滚。

void AttachField(Message * pMessage,int iFieldId,Message * pfieldvvalue);消息*详细字段(消息*消息,整数);

AttachField:首先,将允许的字段集借给pMesage,并在Guard析构后回滚并释放它,以防止双重删除。

DetachField:先借出pMessage的释放字段,在Guard析构后回滚返回,防止内存泄漏。

回滚的顺序是FILO,也就是严格的逆序(因为release和set_allocated不是严格对称的,如果循环可能会有问题)。

因为C的结构和破坏也是菲洛(https://ISOCPP.org/wiki/FAQ/dtors #

order-dtors-for-locals),一定要在pb初始化后再初始化Guard

这两个接口已经足够满足在我们的业务中存在的几种抽象:

(一)主调透传/分包

把上游传递的某个字段,零拷贝传入下游的请求。此时直接Attach字段即可。

//usecase:        const AReq  oAReq;        BReq oBReq;        SharePbFieldGuard guard;        guard.AttachField(oBReq, BReq::BigFieldId, const_castAReq (oAReq).mutable_bigfield());

(二)被调分包

控制某些字段不同,而其他字段共享/相同。为了避免拷贝大字段,我们可以在拷贝前先释放这些重的字段;拷贝结束后,把重字段共享给所有的分包。使用CopyFrom好处在于,我们不需要为所有新增的字段都手动判断,只需要特殊处理重的字段即可。

//usecase:        Req  oReq;        std::vectorReq vecMultiReq(n);        SharePbFieldGuard guard;        auto* pField = guard.DetachField(oReq, Req::BigFieldId);        for(auto  oSingleReq: multiReq)        {            oSingleReq.CopyFrom(oReq);            oSingleReq.set_field(...);            guard.AttachField(oSingleReq, Req::BigFieldId, pField);}

(三)多字段共享写法(以下是一段脱敏的实际代码)

由于操作的指针都是Message*类型,可以直接用容器存储pb index到字段指针的映射关系。通过循环即可共享所有重字段。

        std::vectoruint32_t vecHeavyField{};//初始化为一组fieldId        SharePbFieldGuard oGuard;        std::unordered_mapuint32_t, ::google::protobuf::Message* mapIndex2Message;        for(auto uField: vecHeavyField)        {            mapIndex2Message[uField] = oGuard.DetachField(oReq, uField);        }        for (auto  oSingleReq: vecReq)        {            oSingleReq.CopyFrom(oReq);            //shared filed            for(auto uField: vecHeavyField)            {                oGuard.AttachField(oSingleRecallReq, uField, mapIndex2Message[uField]);            }        }

展望

安全性:因为回滚时set_allocated会delete掉原本的字段,假如成环可能会很危险,如何侦测这种情况。

性能:是否存在不使用反射,就能自动绑定set_allocated和release的方法

Repeated字段支持:怎样处理Repeatd字段不同的反射接口

(https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message#repeated-field-getters)

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/81981.html

(0)

相关推荐

  • 中国人民银行个人征信中心,怎样注册个人征信中心帐号

    技术中国人民银行个人征信中心,怎样注册个人征信中心帐号人民银行的个人信用账号不是申请的,是当你产生信用行为后人民银行系统根据你的身份证号码自动生成一个你自己的信用账号中国人民银行个人征信中心。 1. 打开中国人民银行征信

    生活 2021年10月29日
  • redis两种持久化方式的优缺点是什么

    技术redis两种持久化方式的优缺点是什么这篇文章给大家分享的是有关redis两种持久化方式的优缺点是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。 redis

    攻略 2021年11月20日
  • apr是几月,APR办理护照的时候指的什么

    技术apr是几月,APR办理护照的时候指的什么护照有效期上的APR指的是4月份的意思,10 apr 63应该是“10 apr 13”即到期时间是2013年4月10日apr是几月。1、外交护照和公务护照有效期最长不超过5年

    生活 2021年10月26日
  • 如何用Python和Pygame模块构建一个游戏框架

    技术如何用Python和Pygame模块构建一个游戏框架如何用Python和Pygame模块构建一个游戏框架,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。通

    攻略 2021年10月26日
  • C++怎么正确使用线程

    技术C++怎么正确使用线程这篇文章主要介绍“C++怎么正确使用线程”,在日常操作中,相信很多人在C++怎么正确使用线程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++怎么正确使用线程”

    攻略 2021年11月25日
  • segmentation调试方法(segmentfault脚本怎么写)

    技术Segmentation中anchor free方法怎么实现的小编给大家分享一下Segmentation中anchor free方法怎么实现的,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读

    攻略 2021年12月20日