女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

抖音內(nèi)部使用的Go基礎庫開源,高性能動態(tài)處理RPC數(shù)據(jù)

OSC開源社區(qū) ? 來源:OSC開源社區(qū) ? 2023-03-23 10:12 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

01

背景

當前,Thrift 是字節(jié)內(nèi)部主要使用的 RPC 序列化協(xié)議,在 CloudWeGo/Kitex 項目中優(yōu)化和使用后,性能相比使用支持泛型編解碼的協(xié)議如 JSON 有較大優(yōu)勢。但是在和業(yè)務團隊進行深入合作優(yōu)化的過程中,我們發(fā)現(xiàn)一些特殊業(yè)務場景并不能享受靜態(tài)化代碼生成所帶來的高性能:
  1. 動態(tài)反射:動態(tài)地 讀取、修改、裁剪 數(shù)據(jù)包中某些字段,如隱私合規(guī)場景中字段屏蔽;
  2. 數(shù)據(jù)編排:組合多個子數(shù)據(jù)包進行 排序、過濾、位移、歸并 等操作,如某些 BFF (Backend For Frontent) 服務;
  3. 協(xié)議轉(zhuǎn)換:作為代理將某種協(xié)議的數(shù)據(jù)轉(zhuǎn)換另一種協(xié)議,如 http-rpc 協(xié)議轉(zhuǎn)換網(wǎng)關。
  4. 泛化調(diào)用:需要秒級熱更新或迭代非常頻繁的 RPC 服務,如大量 Kitex 泛化調(diào)用(generic-call)用戶

不難發(fā)現(xiàn),這些業(yè)務場景都具有難以統(tǒng)一定義靜態(tài)IDL的特點。即使可以通過分布式 sidecar 技術規(guī)避這個問題,也往往因為業(yè)務需要動態(tài)更新而放棄傳統(tǒng)代碼生成方式,訴諸某些自研或開源的 Thrift 泛型編解碼庫進行泛化 RPC 調(diào)用。我們經(jīng)過性能分析發(fā)現(xiàn),目前這些庫相比代碼生成方式有巨大的性能下降。以字節(jié)某 BFF 服務為例,僅僅 Thrift 泛化調(diào)用產(chǎn)生的 CPU 開銷占比就將近 40%,這幾乎是正常 Thrift RPC 服務的4到8倍。因此,我們自研了一套能動態(tài)處理 RPC 數(shù)據(jù)(不需要代碼生成)同時保證高性能的 Go 基礎庫 —— dynamicgo。

02

設計與實現(xiàn)

首先要搞清楚當前這些泛化調(diào)用庫性能為什么差呢?其核心原因是:采用了某種低效泛型容器來承載中間處理過程中的數(shù)據(jù)(典型如 thrift-iterator 中的 map[string]interface{})。眾所周知,Go 的堆內(nèi)存管理代價是極高的 (GC +heap bitmap),而采用 interface 不可避免會帶來大量的內(nèi)存分配。但實際上相當多的業(yè)務場景并不真正需要這些中間表示。比如 http-thrift API 網(wǎng)關中的純協(xié)議轉(zhuǎn)換場景,其本質(zhì)訴求只是將 JSON(或其它協(xié)議)數(shù)據(jù)依據(jù)用戶 IDL 轉(zhuǎn)換為 Thrift 編碼(反之亦然),完全可以基于輸入的數(shù)據(jù)流逐字進行翻譯。同樣,我們也統(tǒng)計了抖音某 BFF 服務中泛化調(diào)用的具體代碼,發(fā)現(xiàn)真正需要進行讀(Get)和寫(Set)操作的字段占整個數(shù)據(jù)包字段不到5%,這種場景下完全可以對不需要的字段進行跳過(Skip)處理而不是反序列化。而 dynamicgo 的核心設計思想是:基于 原始字節(jié)流 和 動態(tài)類型描述 原地(in-place) 進行數(shù)據(jù)處理與轉(zhuǎn)換。為此,我們針對不同的場景設計了不同的 API 去實現(xiàn)這個目標。動態(tài)反射

對于 thrift 反射代理的使用場景,歸納起來有如下使用需求:

  1. 有一套完整結構自描述能力,可表達 scalar 數(shù)據(jù)類型, 也可表達嵌套結構的映射、序列等關系;
  2. 支持增刪查改(Get/Set/Index/Delete/Add)與遍歷(ForEach);
  3. 保證數(shù)據(jù)可并發(fā)讀,但是不需要支持并發(fā)寫。等價于 map[string]interface{} 或 []interface{}

這里我們參考了 Go reflect 的設計思想,把通過IDL解析得到的準靜態(tài)類型描述(只需跟隨 IDL 更新一次)TypeDescriptor 和 原始數(shù)據(jù)單元 Node 打包成一個完全自描述的結構——Value,提供一套完整的反射 API。

//IDL類型描述
typeTypeDescriptorinterface{
Type()Type//數(shù)據(jù)類型
Name()string//類型名稱
Key()*TypeDescriptor//formapkey
Elem()*TypeDescriptor//forsliceormapelement
Struct()*StructDescriptor//forstruct
}
//純TLV數(shù)據(jù)單元
typeNodestruct{
tType//數(shù)據(jù)類型
vunsafe.Pointer//buffer起始位置
lint//數(shù)據(jù)單元長度
}
//Node+類型描述descriptor
typeValuestruct{
Node
Descthrift.TypeDescriptor
}

這樣,只要保證 TypeDescriptor 包含的類型信息足夠豐富,以及對應的 thrift 原始字節(jié)流處理邏輯足夠健壯,甚至可以實現(xiàn)數(shù)據(jù)裁剪、聚合等各種復雜的業(yè)務場景。

協(xié)議轉(zhuǎn)換

協(xié)議轉(zhuǎn)換的過程可以通過有限狀態(tài)機(FSM)來表達。以 JSON->Thrift 流程為例,其轉(zhuǎn)換過程大致為:

  1. 預加載用戶 IDL,轉(zhuǎn)換為運行時的動態(tài)類型描述 TypeDescriptor;
  2. 從輸入字節(jié)流中讀取一個 json 值,并判斷其具體類型(object/array/string/number/bool/null):
  3. 如果是 object 類型,繼續(xù)讀取一個 key,再通過對應的 STRUCT 類型描述找到匹配字段的子類型描述;
  4. 如果是 array 類型,遞歸查找類型描述的子元素類型描述;
  5. 其它類型,直接使用當前類型描述。
  6. 基于得到的動態(tài)類型描述信息,將該值轉(zhuǎn)換為等價的 Thrift 字節(jié),寫入到輸出字節(jié)流中 ;
  7. 更新輸入和輸出字節(jié)流位置,跳回2進行循環(huán)處理,直到輸入終止(EOF)。

95a3aaf0-c8f0-11ed-bfe3-dac502259ad0.png

圖1 JSON2Thrift 數(shù)據(jù)轉(zhuǎn)換流程

整個過程可以完全做到 in-place 進行,僅需為輸出字節(jié)流分配一次內(nèi)存即可。

數(shù)據(jù)編排

與前面兩個場景稍微有所不同,數(shù)據(jù)編排場景下可能涉及數(shù)據(jù)位置的改變(異構轉(zhuǎn)換),并且往往會訪問大量數(shù)據(jù)節(jié)點(最壞復雜度O(N) )。在與抖音隱私合規(guī)團隊的合作研發(fā)中我們就發(fā)現(xiàn)了類似問題。它們的一個重要業(yè)務場景:要橫向遍歷某一個 array 的子節(jié)點,查找是否有違規(guī)數(shù)據(jù)并進行整行擦除。這種場景下,直接基于原始字節(jié)流進行查找和插入可能會帶來大量重復的skip 定位、數(shù)據(jù)拷貝開銷,最終導致性能劣化。因此我們需要一種高效的反序列化(帶有指針)結構表示來處理數(shù)據(jù)。根據(jù)以往經(jīng)驗,我們想到了DOM(Document Object Model),這種結構被廣泛運用在 JSON 的泛型解析場景中(如 rappidJSON、sonic/ast),并且性能相比 map+interface 泛型要好很多。

要用 DOM 來描述一個 Thrift 結構體,首先需要一個能準確描述數(shù)據(jù)節(jié)點之間的關系的定位方式—— Path。其類型應該包括 list index、map key 以及 struct field id等。

typePathTypeuint8

const(
PathFieldIdPathType=1+iota//STRUCT下字段ID
PathFieldName//STRUCT下字段名稱
PathIndex//SET/LIST下的序列號
PathStrKey//MAP下的stringkey
PathIntkey//MAP下的integerkey
PathObjKey//MAP下的objectkey
)

typePathNodestruct{
Path//相對父節(jié)點路徑
Node//原始數(shù)據(jù)單元
Next[]PathNode//存儲子節(jié)點
}

在 Path 的基礎上,我們組合對應的數(shù)據(jù)單元Node,然后再通過一個Next 數(shù)組動態(tài)存儲子節(jié)點,便可以組裝成一個類似于BTree的泛型結構。

9604321c-c8f0-11ed-bfe3-dac502259ad0.png

圖2 thrift DOM 數(shù)據(jù)結構

這種泛型結構比 map+interface 要好在哪呢?首先,底層的數(shù)據(jù)單元 Node 都是對原始 thrift data 的引用,沒有轉(zhuǎn)換 interface 帶來的二進制編解碼開銷;其次,我們的設計保證所有樹節(jié)點 PathNode 的內(nèi)存結構是完全一樣,并且由于父子關系的底層核心容器是 slice, 我們又可以更進一步采用內(nèi)存池技術,將整個 DOM 樹的子節(jié)點內(nèi)存分配與釋放都進行池化從而避免調(diào)用 go 堆內(nèi)存管理。測試結果表明,在理想場景下(后續(xù)反序列化的DOM樹節(jié)點數(shù)量小于等于之前反序列化節(jié)點數(shù)量的最大值——這由于內(nèi)存池本身的緩沖效應基本可以保證),內(nèi)存分配次數(shù)可為0,性能提升200%?。ㄒ姟拘阅軠y試-全量序列化/反序列化】部分)。

03

性能測試

這里我們分別定義簡單(Small)、復雜(Medium) 兩個基準結構體分別在比較 不同數(shù)據(jù)量級 下的性能,同時添加簡單部分(SmallPartial)、復雜部分(MediumPartial) 兩個對應子集,用于【反射-裁剪】場景的性能比較:

  • Small:114B,6個有效字段
  • SmallPartial:small 的子集,55B,3個有效字段
  • Medium: 6455B,284個有效字段
  • MediumPartial: medium 的子集,1922B,132個有效字段

Small:https://github.com/cloudwego/dynamicgo/blob/main/testdata/idl/baseline.thrift#L3

Medium:https://github.com/cloudwego/dynamicgo/blob/main/testdata/idl/baseline.thrift#L12

SmallPartial:https://github.com/cloudwego/dynamicgo/blob/main/testdata/idl/baseline.thrift#L12

MediumPartial:https://github.com/cloudwego/dynamicgo/blob/main/testdata/idl/baseline.thrift#L36

其次,我們依據(jù)上述業(yè)務場景劃分為 反射、協(xié)議轉(zhuǎn)換、全量序列化/反序列化 三套 API,并以代碼生成庫kitex/FastAPI、泛化調(diào)用庫kitex/generic、JSON 庫sonic為基準進行性能測試。其它測試環(huán)境均保持一致:

  • Go 1.18.1
  • CPU intel i9-9880H 2.3GHZ
  • OS macOS Monterey 12.6

kitex/FastAPI:https://github.com/cloudwego/kitex/blob/aed28371eb88b2668854759ce9f4666595ebc8de/pkg/remote/codec/thrift/thrift.go

kitex/generic:https://github.com/cloudwego/kitex/tree/develop/pkg/generic

sonic:https://github.com/bytedance/sonic

反射

1. 代碼

dynamicgo/testdata/baseline_tg_test.go

2. 用例

  • GetOne:查找字節(jié)流中最后1個數(shù)據(jù)字段
  • GetMany:查找前中后5個數(shù)據(jù)字段
  • MarshalMany:將 GetMany 中的結果進行二次序列化
  • SetOne:設置最后一個數(shù)據(jù)字段
  • SetMany:設置前中后3個節(jié)點數(shù)據(jù)
  • MarshalTo:將大 Thrift 數(shù)據(jù)包裁剪為小 thrift 數(shù)據(jù)包 (Small -> SmallPartial 或 Medium -> MediumParital)
  • UnmarshalAll+MarshalPartial:代碼生成/泛化調(diào)用方式裁剪——先反序列化全量數(shù)據(jù)再序列化部分數(shù)據(jù)。效果等同于 MarshalTo。

3. 結果

  • 簡單(ns/OP)
962bbf62-c8f0-11ed-bfe3-dac502259ad0.png
  • 復雜(ns/OP)
965b93d6-c8f0-11ed-bfe3-dac502259ad0.png

4. 結論

  • dynamicgo 一次查找+寫入 開銷大約為代碼生成方式的 2 ~ 1/3、為泛化調(diào)用方式的 1/12 ~ 1/15,并隨著數(shù)據(jù)量級增大優(yōu)勢加大;
  • dynamicgo thrift 裁剪 開銷接近于代碼生成方式、約為泛化調(diào)用方式的 1/10~1/6,并且隨著數(shù)據(jù)量級增大優(yōu)勢減弱。

協(xié)議轉(zhuǎn)換

1. 代碼

  • JSON2Thrift:dynamicgo/testdata/baseline_j2t_test.go
  • ThriftToJSON:dynamicgo/testdata/baseline_t2j_test.go

2. 用例

  • JSON2thrift:JSON 數(shù)據(jù)轉(zhuǎn)換為等價結構的 thrift 數(shù)據(jù)
  • thrift2JSON:將 thrift 數(shù)據(jù)轉(zhuǎn)換為等價結構的 JSON 數(shù)據(jù)
  • sonic + kitex-fast:表示通過 sonic 處理 json 數(shù)據(jù)(有結構體),通過kitex代碼生成處理thrift數(shù)據(jù)

3. 結果

  • 簡單(ns/OP)
96762c8c-c8f0-11ed-bfe3-dac502259ad0.png
  • 復雜(ns/OP)
969ea66c-c8f0-11ed-bfe3-dac502259ad0.png

4. 結論

  • dynamicgo 協(xié)議轉(zhuǎn)換開銷約為代碼生成方式的 1~2/3、泛化調(diào)用方式的 1/4~1/9,并且隨著數(shù)據(jù)量級增大優(yōu)勢加大;

全量序列化/反序列化

1. 代碼

dynamicgo/testdata/baseline_tg_test.go#BenchmarkThriftGetAll

2. 用例

  • UnmarshalAll:反序列化所有字段。其中對于 dynamicgo 有兩種模式:

    • new:每次重新分配 DOM 內(nèi)存;
    • reuse:使用內(nèi)存池復用 DOM 內(nèi)存。
  • MarshalAll:序列化所有字段。

3. 結果

  • 簡單(ns/OP)
96b50a74-c8f0-11ed-bfe3-dac502259ad0.png
  • 復雜(ns/OP)
96cd3108-c8f0-11ed-bfe3-dac502259ad0.png

4. 結論

  • dynamicgo 全量序列化 開銷約為代碼生成方式的 6~3倍、泛化調(diào)用方式的 1/4~1/2,并且隨著數(shù)據(jù)量級增大優(yōu)勢減弱;
  • Dynamigo 全量反序列化+內(nèi)存復用 場景下開銷約為代碼生成方式的 1.8~0.7、泛化調(diào)用方式的 1/13~1/8,并且隨著數(shù)據(jù)量級增大優(yōu)勢加大。

04

應用與展望

當前,dynamicgo 已經(jīng)應用到許多重要業(yè)務場景中,包括:

  1. 業(yè)務隱私合規(guī) 中間件(thrift 反射);
  2. 抖音某 BFF 服務下游數(shù)據(jù)按需下發(fā)(thrift 裁剪);
  3. 字節(jié)跳動某 API 網(wǎng)關協(xié)議轉(zhuǎn)換(JSON<>thrift 協(xié)議轉(zhuǎn)換)。

并且逐步上線并取得收益。目前 dynamic 還在迭代中,接下來的工作包括:

  1. 集成到 Kitex 泛化調(diào)用模塊中,為更多用戶提供高性能的 thrift 泛化調(diào)用模塊;
  2. Thrift DOM 接入 DSL(GraphQL)組件,進一步提升 BFF 動態(tài)網(wǎng)關性能;
  3. 支持 Protobuf 協(xié)議。

也歡迎感興趣的個人或團隊參與進來,共同開發(fā)!

項目地址

GitHub:https://github.com/cloudwego

官網(wǎng):www.cloudwego.io


審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 編解碼
    +關注

    關注

    1

    文章

    145

    瀏覽量

    20061
  • 開源
    +關注

    關注

    3

    文章

    3645

    瀏覽量

    43675
  • 數(shù)據(jù)包

    關注

    0

    文章

    269

    瀏覽量

    24947

原文標題:抖音內(nèi)部使用的Go基礎庫開源,高性能動態(tài)處理RPC數(shù)據(jù)

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    go語言能做什么工作?

    讓程序員更容易地進行維護和修改。它融合了傳統(tǒng)編譯型語言的高效性和腳本語言的易用性和富于表達性。Go語言作為服務器編程語言,很適合處理日志、數(shù)據(jù)打包、虛擬機處理、文件系統(tǒng)、分布式系統(tǒng)、
    發(fā)表于 03-22 15:03

    香山是什么?“香山” 高性能開源 RISC-V 處理器項目介紹

    香山是什么2019 年,在中國科學院支持下,由 中國科學院計算技術研究所 牽頭發(fā)起 “香山” 高性能開源 RISC-V 處理器項目,研發(fā)出目前國際上性能最高的開源
    發(fā)表于 04-07 14:20

    基于LabView平臺的齒輪箱性能動態(tài)測試與診斷_李貴明

    基于LabView平臺的齒輪箱性能動態(tài)測試與診斷_李貴明
    發(fā)表于 03-18 09:41 ?3次下載

    移動卡全新發(fā)布免流量刷你會辦理嗎?

    “像一顆海草海草海草海草,隨波飄搖……”每天晚上睡覺前刷刷上班坐在公交車上刷刷閑著沒事總是要刷刷
    的頭像 發(fā)表于 07-16 15:14 ?7.6w次閱讀

    到底因為什么火成這樣?

    7月16日,官方正式宣布,全球月活躍用戶數(shù)超過5億。這是首次對外公布自己的全球月活躍
    的頭像 發(fā)表于 09-01 15:54 ?3237次閱讀

    怎么直播?三種方法教你怎么開直播

    很多朋友不知道怎么直播,找不到直播的入口。 小編為了學習如何在直播,也是在百度搜索了
    發(fā)表于 12-10 13:40 ?1.6w次閱讀

    數(shù)據(jù)造假等各類違規(guī)行為進行實時攔截

    截至2020年8月,包含火山版在內(nèi),的日活躍用戶已經(jīng)超過了6億。隨著的火爆,相關第三
    的頭像 發(fā)表于 12-01 09:12 ?5969次閱讀

    支付在APP內(nèi)正式上線

    1月19日 消息:據(jù)支付百科消息,支付已在APP內(nèi)正式上線,在APP內(nèi)購物結算時,除
    的頭像 發(fā)表于 01-19 15:50 ?4848次閱讀

    回應封殺騰訊外鏈傳聞

    據(jù)報道,針對近日社交媒體上流傳的“封殺騰訊”傳聞,回應稱為禁止財經(jīng)、醫(yī)療垂類外鏈引流。
    的頭像 發(fā)表于 02-02 11:35 ?2472次閱讀

    再回應起訴騰訊

    2月2日,再次以聲明形式回應對騰訊的起訴。聲明中,稱,騰訊所謂的“惡意構陷”沒有任何依據(jù);所謂“違規(guī)獲取微信用戶個人信息”不屬實;
    的頭像 發(fā)表于 02-03 09:13 ?2691次閱讀

    正式起訴騰訊壟斷

    昨天下午,微博、知乎等多個社交平臺均傳出“封殺騰訊”的消息。
    的頭像 發(fā)表于 02-03 11:03 ?2451次閱讀

    快手APP大眼特效開源實現(xiàn),甜美系小姐姐親做效果演示

    短視頻中的大眼特效有很多人玩,這篇就講一下怎么實現(xiàn)。本文為《美顏效果開源實現(xiàn),從AI到美顏全流程講解》姐妹篇,很多代碼和...
    發(fā)表于 01-26 18:45 ?1次下載
    <b class='flag-5'>抖</b><b class='flag-5'>音</b>快手APP大眼特效<b class='flag-5'>開源</b>實現(xiàn),甜美系小姐姐親做效果演示

    嵌入式Linux應用開發(fā)之內(nèi)置RPC

    標準RPC默認采用Go語言特有的gob編碼,因此從其它語言調(diào)用Go語言實現(xiàn)的RPC服務將比較困難。雖然可以通過額外的工作支持跨語言,但是
    發(fā)表于 05-13 09:46 ?869次閱讀

    拒絕小屏 躺著大屏刷

    隨著短視頻的興起,刷已經(jīng)成為大多數(shù)人茶余飯后的一種消遣方式,但盯著一塊小小的手機屏幕刷實在是有點辛苦,正確的打開方式應該是躺在沙發(fā)上使用大屏電視,這樣刷
    的頭像 發(fā)表于 07-14 11:37 ?1524次閱讀
    拒絕小屏 躺著大屏刷<b class='flag-5'>抖</b><b class='flag-5'>音</b>

    Tars框架使用NIO進行網(wǎng)絡編程的源碼分析

    Tars是騰訊開源的支持多語言的高性能RPC框架,起源于騰訊內(nèi)部2008年至今一直使用的統(tǒng)一應用框架TAF(Total Application Framework),目前支持C++、J
    的頭像 發(fā)表于 06-26 17:31 ?978次閱讀
    Tars框架使用NIO進行網(wǎng)絡編程的源碼分析