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

相关推荐

  • 两位数的乘法,快速算出两位数乘法的方法

    技术两位数的乘法,快速算出两位数乘法的方法两位数乘法速算技巧原理:设两位数分别为10A B,10C D,其积为S,根据多项式展开:S=(10A B)×(10C D)=10A×10C B×10C 10A×D B×D,而所谓

    生活 2021年10月28日
  • 钱塘江观潮最佳时间和地点,钱塘江观潮最佳时间和路线

    技术钱塘江观潮最佳时间和地点,钱塘江观潮最佳时间和路线钱塘江最佳观潮地点:  “八月十八潮,壮观天下无钱塘江观潮最佳时间和地点。”这是北宋大诗人苏东坡咏赞钱塘秋潮的千古名句。千百年来,钱塘江以其奇特卓绝的江潮,不知倾倒了

    生活 2021年10月23日
  • 如何使用Spring Session 与 Spring security 完成网站登录改造

    技术如何使用Spring Session 与 Spring security 完成网站登录改造如何使用Spring Session 与 Spring security 完成网站登录改造,相信很多没有经验的人对此束手无策,

    攻略 2021年11月9日
  • 怎样挑选实木床,如何选购实木床注意问题有哪些

    技术怎样挑选实木床,如何选购实木床注意问题有哪些实木床和板式床哪个好?这是人们比较关心的问题怎样挑选实木床。目前,市场的床类有多种,有些人喜欢实木床,而有些人则喜欢板式床。其实,二者有很多不同之处,朋友们在购买时,可根据

    生活 2021年10月23日
  • 沃尔沃是哪国车,沃尔沃汽车原产地是哪个国家

    技术沃尔沃是哪国车,沃尔沃汽车原产地是哪个国家沃尔沃,英文名为Volvo,原为瑞典著名汽车品牌,又译为富豪,该品牌汽车安全性能很高沃尔沃是哪国车。沃尔沃汽车公司原是北欧最大的汽车企业,也曾经是瑞典最大的工业企业集团,其中

    生活 2021年10月21日
  • Java基础——面向对象2

    技术Java基础——面向对象2 Java基础——面向对象2Java基础——面向对象2
    继承
    子类无法使用父类的私有属性或方法
    Java中只有单继承,没有多继承
    Ctrl + h 打开继承树
    在Java中

    礼包 2021年12月15日