Go 語言 JSON 解析屆頂流:Sonic

Sonic 是字節跳動開源的一款 Go 語言 JSON 解析庫,按照官方的說法:

自 2021 年 7 月份發佈以來,Sonic 已被抖音、今日頭條等業務採用,累計爲字節跳動節省了數十萬 CPU 核(省了好多錢啊~)。

下面我們來看 Sonic 相比其他 JSON 解析庫優勢有多大,以及常見的使用舉例。

Sonic 研發背景

測試結果如下:結果顯示:目前這些 JSON 庫均無法在各場景下都保持最優性能,即使是當前使用最廣泛的第三方庫 Json-iterator,在泛型編解碼、大數據量級場景下的性能也滿足不了字節的需求。

JSON 庫的基準編解碼性能固然重要,但是對不同場景的最優匹配更關鍵 —— 於是字節走上了自研 JSON 庫的道路。

Sonic 性能測試

以下是字節根據上面的不同場景進行的測試結果:

中數據(110KB,300+key,深度 4 層)大數據(500KB),10000+key 深度 6 層

可以看到 Sonic 在大部分場景下都有明顯的優勢:

字節某服務在 Sonic 上線前後的 CPU 佔用(核數)對比

通過上面的測試比較結果,我們很難不想去使用 Sonic 去優化我們的業務,爲我們自己的系統提效添磚加瓦~

Sonic 常見使用場景

解析爲 map 類型

使用 Sonic 將 JSON 數據解析爲 map 類型的方法:

例如:

package main

import (
 "github.com/bytedance/sonic"
 "fmt"
)

func main() {
    var jsonStr = `{"name""Harper""age": 18}`
    var data map[string]any
    
    err := sonic.Unmarshal([]byte(jsonStr)&data)
    if err != nil {
        fmt.Println("解析失敗:", err)
    }
    
    fmt.Println(data["name"], data["age"])
}

解析爲結構體類型

使用 Sonic 將 JSON 數據解析爲結構體類型的方法:

例如:

package main

import (
 "github.com/bytedance/sonic"
 "fmt"
)

func main() {
    type Person struct {
        Name string `json:"name"`
        Age int `json:"age"`
    }

    var jsonStr = `{"name""Harper""age": 20}`
    var person Person

    err := sonic.Unmarshal([]byte(jsonStr)&person)
    if err != nil {
        fmt.Println("解析失敗:", err)
    }

    fmt.Println(person.Name, person.Age)
}

解析嵌套 JSON 數據

Sonic 可以解析嵌套的 JSON 數據,其實跟上面的「解析爲結構體類型」原因一樣,例如:

package main

import (
 "github.com/bytedance/sonic"
 "fmt"
)

func main() {
    var jsonStr = `{"name""Harper""age": 30, "address"{"city""HaiDian Beijing""country""China"}}`

    type Address struct {
        City string `json:"city"`
        Country string `json:"country"`
    }

    type Person struct {
        Name string `json:"name"`
        Age int `json:"age"`
        Address Address `json:"address"`
    }

    var person Person
    err := sonic.Unmarshal([]byte(jsonStr)&person)
    if err != nil {
        fmt.Println("解析失敗:", err)
    }
    
    fmt.Println(person.Name, person.Age, person.Address.City, person.Address.Country)
}

解析數組類型

Sonic 還可以解析數組類型的 JSON 數據,例如:

package main

import (
 "github.com/bytedance/sonic"
 "fmt"
)

func main() {
    var jsonStr = `[{"name""Harper""age": 33}{"name""Bella""age": 34}]`

    type Person struct {
        Name string `json:"name"`
        Age int `json:"age"`
    }

    var persons []Person
    err := sonic.Unmarshal([]byte(jsonStr)&persons)
    if err != nil {
        fmt.Println("解析失敗:", err)
    }
    
    for _, person := range persons {
        fmt.Println(person.Name, person.Age)
    }
}

小結

Sonic 是一款高性能的 JSON 解析庫,它提供了豐富的 JSON 解析 API,包括解析爲 map、結構體、嵌套 JSON 數據和數組類型等,涵蓋了我們工作中幾乎所有的應用場景。

特別是對於大數據解析的場景,如果我們系統遇到了 JSON 數據解析的瓶頸,不妨試試 Sonic,看看效果,畢竟替換很方便,跟 Json-iterator 類似,平替成本很低。

【參考資料】


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Ij5wNjNZ6rRbQqTYIvP_aw