Go语言JSON解析届顶流:Sonic

2023-07-1308:17:04后端程序开发Comments1,857 views2字数 3203阅读模式

Sonic 是字节跳动开源的一款 Go 语言 JSON 解析库,按照官方的说法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

  • Sonic 是一个速度奇快的 JSON 序列化/反序列化库,由 JIT (即时编译)和 SIMD (单指令流多数据流)加速。
  • 对于所有大小的 json 和所有使用场景, Sonic 表现均为最佳。

自 2021 年 7 月份发布以来,Sonic 已被抖音、今日头条等业务采用,累计为字节跳动节省了数十万 CPU 核(省了好多钱啊~)。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

下面我们来看 Sonic 相比其他 JSON 解析库优势有多大,以及常见的使用举例。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

Sonic 研发背景

  • Go 本身自带标准 JSON 库:encoding/json,另外还有很多优秀的第三方库,比如:Json-iterator、Easyjson、Gjson、Sjson 等,其中 Json-iterator 最受欢迎(12.3+k Star)。
  • 字节根据样本 JSON 的 key 数量和深度分为三个量级:
    • 小(small):400B,11 key,深度 3层;
    • 中(medium):110KB,300+ key,深度 4 层(实际业务数据,其中有大量的嵌套 JSON string);
    • 大(large):550KB,10000+ key,深度 6 层。

测试结果如下:Go语言JSON解析届顶流:Sonic结果显示:目前这些 JSON 库均无法在各场景下都保持最优性能,即使是当前使用最广泛的第三方库 Json-iterator,在泛型编解码、大数据量级场景下的性能也满足不了字节的需求。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

JSON 库的基准编解码性能固然重要,但是对不同场景的最优匹配更关键 —— 于是字节走上了自研 JSON 库的道路。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

Sonic 性能测试

以下是字节根据上面的不同场景进行的测试结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

Go语言JSON解析届顶流:Sonic
小数据(400B,11 个 key,深度 3 层)
Go语言JSON解析届顶流:Sonic
中数据(110KB,300+key,深度 4 层)
Go语言JSON解析届顶流:Sonic
大数据(500KB),10000+key深度 6 层

可以看到 Sonic 在大部分场景下都有明显的优势:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

  • 平均编码性能较 Json-iterator 提升 240%,平均解码性能较 Json-iterator 提升 110%;
  • 单 key 修改能力较 Sjson 提升 75%。
  • 在生产环境中,Sonic 中也验证了良好的收益,服务高峰期占用核数减少将近 ⅓:
Go语言JSON解析届顶流:Sonic
字节某服务在 *Sonic* 上线前后的 CPU 占用(核数)对比

通过上面的测试比较结果,我们很难不想去使用 Sonic 去优化我们的业务,为我们自己的系统提效添砖加瓦~文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

Sonic 常见使用场景

解析为 map 类型

使用 Sonic 将 JSON 数据解析为 map 类型的方法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

  • 只需要调用 Sonic 的 Unmarshal 函数,并将 JSON 数据和一个空的 map 作为参数传递即可。

例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

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"])
}
Go语言JSON解析届顶流:Sonic
运行结果

解析为结构体类型

使用 Sonic 将 JSON 数据解析为结构体类型的方法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

  • 只需要定义一个结构体,用于存储解析结果,并将 JSON 数据和结构体作为参数传递给 Unmarshal 函数即可。

例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

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)
}
Go语言JSON解析届顶流:Sonic
运行结果

解析嵌套 JSON 数据

Sonic 可以解析嵌套的 JSON 数据,其实跟上面的「解析为结构体类型」原因一样,例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

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)
}
Go语言JSON解析届顶流:Sonic
运行结果

解析数组类型

Sonic 还可以解析数组类型的 JSON 数据,例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

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)
    }
}
Go语言JSON解析届顶流:Sonic
运行结果

小结

Sonic 是一款高性能的 JSON 解析库,它提供了丰富的 JSON 解析 API,包括解析为 map、结构体、嵌套 JSON 数据和数组类型等,涵盖了我们工作中几乎所有的应用场景。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

特别是对于大数据解析的场景,如果我们系统遇到了 JSON 数据解析的瓶颈,不妨试试 Sonic,看看效果,毕竟替换很方便,跟 Json-iterator 类似,平替成本很低。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/51435.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定