基于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)

相关推荐

  • .net5调用WebService简单事例

    技术.net5调用WebService简单事例 .net5调用WebService简单事例1. 创建 .net5控制台项目:dotnet new console -o WebServiceConsole

    礼包 2021年11月22日
  • 如何分析Linux PIE/堆栈内存损坏漏洞CVE-2017-1000253

    技术如何进行Linux PIE/stack 内存破坏漏洞CVE-2017-1000253分析本篇文章为大家展示了如何进行Linux PIE/stack 内存破坏漏洞CVE-2017-1000253分析,内容简明扼要并且容

    2021年12月21日
  • 繁体字游戏名,带诗意的5字游戏名繁体

    技术繁体字游戏名,带诗意的5字游戏名繁体感性的世界繁体字游戏名、何须叹离别、欠我旳太哆、
    情留一点痴、
    五个字名字、
    如果爱忘了、
    陌生的你我、
    初吻给了烟、
    纯白色衬衫、
    我歌月徘徊、
    下一瓶芬达、
    芯痛,谁会疼、

    生活 2021年10月19日
  • java中如何实现生成器和迭代器

    技术java中如何实现生成器和迭代器小编给大家分享一下java中如何实现生成器和迭代器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!print

    攻略 2021年11月23日
  • 如何进行实战和剖析Sentinel 系统自适应限流

    技术如何进行实战和剖析Sentinel 系统自适应限流这篇文章将为大家详细讲解有关如何进行实战和剖析Sentinel 系统自适应限流,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定

    攻略 2021年10月21日
  • mysql如何查询前10条记录

    技术mysql如何查询前10条记录本篇内容主要讲解“mysql如何查询前10条记录”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mysql如何查询前10条记录”吧!

    攻略 2021年12月2日