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 层。
测试结果如下:结果显示:目前这些 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
可以看到 Sonic 在大部分场景下都有明显的优势:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html
平均编码性能较 Json-iterator 提升 240%,平均解码性能较 Json-iterator 提升 110%; 单 key 修改能力较 Sjson 提升 75%。 在生产环境中,Sonic 中也验证了良好的收益,服务高峰期占用核数减少将近 ⅓:
通过上面的测试比较结果,我们很难不想去使用 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"])
}
解析为结构体类型
使用 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)
}
解析嵌套 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)
}
解析数组类型
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)
}
}
小结
Sonic 是一款高性能的 JSON 解析库,它提供了丰富的 JSON 解析 API,包括解析为 map、结构体、嵌套 JSON 数据和数组类型等,涵盖了我们工作中几乎所有的应用场景。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html
特别是对于大数据解析的场景,如果我们系统遇到了 JSON 数据解析的瓶颈,不妨试试 Sonic,看看效果,毕竟替换很方便,跟 Json-iterator 类似,平替成本很低。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/51435.html