国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

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

3天內不再提示

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

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

掃碼添加小助手

加入工程師交流群

01

背景

當前,Thrift 是字節(jié)內部主要使用的 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é)議轉換:作為代理將某種協(xié)議的數(shù)據(jù)轉換另一種協(xié)議,如 http-rpc 協(xié)議轉換網(wǎng)關。
  4. 泛化調用:需要秒級熱更新或迭代非常頻繁的 RPC 服務,如大量 Kitex 泛化調用(generic-call)用戶

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

02

設計與實現(xiàn)

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

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

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

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

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

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

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

與前面兩個場景稍微有所不同,數(shù)據(jù)編排場景下可能涉及數(shù)據(jù)位置的改變(異構轉換),并且往往會訪問大量數(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 的引用,沒有轉換 interface 帶來的二進制編解碼開銷;其次,我們的設計保證所有樹節(jié)點 PathNode 的內存結構是完全一樣,并且由于父子關系的底層核心容器是 slice, 我們又可以更進一步采用內存池技術,將整個 DOM 樹的子節(jié)點內存分配與釋放都進行池化從而避免調用 go 堆內存管理。測試結果表明,在理想場景下(后續(xù)反序列化的DOM樹節(jié)點數(shù)量小于等于之前反序列化節(jié)點數(shù)量的最大值——這由于內存池本身的緩沖效應基本可以保證),內存分配次數(shù)可為0,性能提升200%!(見【性能測試-全量序列化/反序列化】部分)。

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é)議轉換、全量序列化/反序列化 三套 API,并以代碼生成庫kitex/FastAPI、泛化調用庫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:代碼生成/泛化調用方式裁剪——先反序列化全量數(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、為泛化調用方式的 1/12 ~ 1/15,并隨著數(shù)據(jù)量級增大優(yōu)勢加大;
  • dynamicgo thrift 裁剪 開銷接近于代碼生成方式、約為泛化調用方式的 1/10~1/6,并且隨著數(shù)據(jù)量級增大優(yōu)勢減弱。

協(xié)議轉換

1. 代碼

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

2. 用例

  • JSON2thrift:JSON 數(shù)據(jù)轉換為等價結構的 thrift 數(shù)據(jù)
  • thrift2JSON:將 thrift 數(shù)據(jù)轉換為等價結構的 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é)議轉換開銷約為代碼生成方式的 1~2/3、泛化調用方式的 1/4~1/9,并且隨著數(shù)據(jù)量級增大優(yōu)勢加大;

全量序列化/反序列化

1. 代碼

dynamicgo/testdata/baseline_tg_test.go#BenchmarkThriftGetAll

2. 用例

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

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

3. 結果

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

4. 結論

  • dynamicgo 全量序列化 開銷約為代碼生成方式的 6~3倍、泛化調用方式的 1/4~1/2,并且隨著數(shù)據(jù)量級增大優(yōu)勢減弱;
  • Dynamigo 全量反序列化+內存復用 場景下開銷約為代碼生成方式的 1.8~0.7、泛化調用方式的 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é)議轉換(JSON<>thrift 協(xié)議轉換)。

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

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

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

項目地址

GitHub:https://github.com/cloudwego

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


審核編輯 :李倩


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

    關注

    1

    文章

    151

    瀏覽量

    20564
  • 開源
    +關注

    關注

    3

    文章

    4207

    瀏覽量

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

    關注

    0

    文章

    270

    瀏覽量

    25600

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

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

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    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 ?3772次閱讀

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

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

    支付在APP內正式上線

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

    再回應起訴騰訊

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

    快手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ā)之內置RPC

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

    拒絕小屏 躺著大屏刷

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

    電商 API 接口:開啟小店直播帶貨數(shù)據(jù)新洞察

    ? 在數(shù)字化電商浪潮中,小店憑借直播帶貨模式迅速崛起,成為品牌和商家的新戰(zhàn)場。然而,如何從海量直播數(shù)據(jù)中提取有價值的洞察,優(yōu)化銷售策略?
    的頭像 發(fā)表于 08-20 15:20 ?1082次閱讀
    <b class='flag-5'>抖</b><b class='flag-5'>音</b>電商 API 接口:開啟<b class='flag-5'>抖</b><b class='flag-5'>音</b>小店直播帶貨<b class='flag-5'>數(shù)據(jù)</b>新洞察

    巧用電商 API,精準分析商品種草效果

    API,結合數(shù)據(jù)分析,實現(xiàn)精準量化種草效果。文章結構清晰,從基礎概念到實踐步驟,逐步指導您操作。所有方法基于真實電商場景,確??煽啃院涂刹僮餍浴?一、電商 API 簡介與接入
    的頭像 發(fā)表于 08-20 15:29 ?1161次閱讀
    巧用<b class='flag-5'>抖</b><b class='flag-5'>音</b>電商 API,精準分析<b class='flag-5'>抖</b><b class='flag-5'>音</b>商品種草效果

    揭秘電商 API,讓小店粉絲增長有跡可循

    ? 在當今短視頻電商時代,已成為商家必爭之地。但如何精準追蹤粉絲增長,優(yōu)化營銷策略?電商 API(應用程序接口)正是關鍵。它讓商家通過數(shù)據(jù)
    的頭像 發(fā)表于 08-20 15:46 ?843次閱讀
    揭秘<b class='flag-5'>抖</b><b class='flag-5'>音</b>電商 API,讓<b class='flag-5'>抖</b><b class='flag-5'>音</b>小店粉絲增長有跡可循

    電商 API 接口:平臺電商活動熱度實時監(jiān)測

    數(shù)據(jù)接入方式,支持實時獲取和分析活動熱度指標。本文將詳細介紹這一接口的功能、應用方法及優(yōu)勢。 電商 API 接口概述 電商 API
    的頭像 發(fā)表于 08-21 15:30 ?784次閱讀
    <b class='flag-5'>抖</b><b class='flag-5'>音</b>電商 API 接口:<b class='flag-5'>抖</b><b class='flag-5'>音</b>平臺電商活動熱度實時監(jiān)測