聊聊Protocol Buffers

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 Protocal Buffers是google推出的一种序列化协议。由于它的编码和解码的速度,已经编码后的大小控制的较好,因此它常常被用在RPC调用中,传递参数和结果。比如gRPC。 Protocal Buffers的实现非常简单,本文将对比JSON协议,来聊聊Protocol Buffers的实现以及它高性能的秘密 2. 正篇 2.1 减少传输量(字段名和定界符) 汽车类在Golang中的定义 type Car struct { Age int32 `json:"age"` Color string `json:"color"` Price float32 `json:"price"` } JSON字符串表示 { "age": 10, "color": "red", "price": 15.2568983 } 1)"{" 、"}"、"[", “]"、 双引号、”," 、":" 是为了把字段与字段之间,以及字段的名称和值分隔开。它们不是必须的。 2)字段的名称"age"、“color”、“price"也不是必须的。 如果发送方和接收方都对对象的定义是明晰的,那么字段的名称也不要传递 Protocol Buffers对象定义 message Car { int32 age = 1; string color = 2; double price = 3; } 每个字段都有一个编号,比如在例子中,age是1,color是2,price是3 接收方只要拿到编号,就可以知道需要解析的是哪个字段,它对应的名字甚至是字段值的长度 下图是对Protocol buffers编码的说明 图1 ...

April 3, 2019 · 2 min

如何在Golang中制造stack overflow 故障

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 大家都知道golang的栈的动态增长的,并且是放在堆上的,理论上可以相当的大,那么怎么才能制造一个stack overflow 故障呢? 其实只要人为的加入循环引用就能做到 package main import ( //"github.com/json-iterator/go" "encoding/json" ) type A struct { ElementB *B } type B struct { ElementA *A } func main(){ a := A{} b := B{} a.ElementB = &b b.ElementA = &a //var json = jsoniter.ConfigCompatibleWithStandardLibrary json.Marshal(a) } 栈溢出,程序奔溃,并输出 ╰─$ go run test_stackoverflow2.go runtime: goroutine stack exceeds 1000000000-byte limit fatal error: stack overflow runtime stack: runtime.throw(0x10e2e65, 0xe) /usr/local/Cellar/go/1.11.2/libexec/src/runtime/panic.go:608 +0x72 runtime.newstack() /usr/local/Cellar/go/1.11.2/libexec/src/runtime/stack.go:1008 +0x729 runtime.morestack() /usr/local/Cellar/go/1.11.2/libexec/src/runtime/asm_amd64.s:429 +0x8f goroutine 1 [running]: encoding/json.(*structEncoder).encode(0xc0000642d0, 0xc00007e000, 0x10c8d40, 0xc00000c030, 0x199, 0x100) 看来默认栈的最大大小也就1GB。 这个例子其实源于真实的线上故障,经过测试无论是标准的Json库,或是jsoniter都无法避免此问题。 另外如果Golang编译器,或者Marshal函数能够对递归的深度做出判断,超过一定深度就报错,在栈溢出前,抛出err,避免栈溢出,程序崩溃 后记 已经给json-iterator/go 提了issue,并且提了pull request。 有需要也可以直接使用我个改进库vearne/json-iterator-go 默认递归的最大层级限制是1000 ...

November 30, 2018 · 1 min

制作了jsonlint的镜像站

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 引言 jsonlint.com是我最喜欢的json 验证和编辑网站 但国内的访问这个网站非常不稳定,根据它提供的源码,部署了一个它的镜像站,为了表示对原作者的尊重,保留了原有的广告和推广链接 访问地址 http://jsonlint.vearne.cc 访问地址 Thanks to Douglas Crockford of JSON and JS Lint, and Zach Carter, who built a pure JavaScript implementation. You can download the JSONLint source code on GitHub. 参考资料 zaach/jsonlint circlecell/jsonlint.com 请我喝瓶饮料

August 21, 2018 · 1 min

json-iterator 使用要注意的大坑

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 众所周知, Golang标准库"encoding/json"的性能并不好,现在比较热的替代库是"json-iterator/go" 传送门: json-iterator/go 我们的日志打成json格式,然后做集中收集,为了提高性能用json-iterator替换encoding/json。打火焰图,却发现(JSON序列化日志)耗时占总时间的比重没有下降 2. 重新测试 难道json-iterator出的性能压测数据都是吹牛逼,只要自己又重新测试了一下,以下是测试代码 json_test.go package tjson import ( "testing" "encoding/json" jsoniter "github.com/json-iterator/go" ) type Car struct { Name string Name1 string Name2 string Name3 string } func BenchmarkStructJsoniter(b *testing.B) { c := Car{Name1:"xxxxxxxxxxxxx", Name2:"xxxxxxxxxxxxxxxxxxxx", Name3:"xxxxxxxxxxxxxxxxxx", Name: "buickxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} for i := 0; i < b.N; i++ { //use b.N for looping jsoniter.Marshal(&c) } } func BenchmarkStructStd(b *testing.B) { c := Car{Name1:"xxxxxxxxxxxxx", Name2:"xxxxxxxxxxxxxxxxxxxx", Name3:"xxxxxxxxxxxxxxxxxx", Name: "buickxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} for i := 0; i < b.N; i++ { //use b.N for looping json.Marshal(&c) } } func BenchmarkMapJsoniter(b *testing.B) { mymap := make(map[string]string, 10000) mymap["Name1"] = "xxxxxxxxxxxxx" mymap["Name2"] = "xxxxxxxxxxxxxxxxxxxx" mymap["Name3"] = "xxxxxxxxxxxxxxxxxx" mymap["Name"] = "buickxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" for i := 0; i < b.N; i++ { //use b.N for looping jsoniter.Marshal(&mymap) } } func BenchmarkMapStd(b *testing.B) { mymap := make(map[string]string, 10000) mymap["Name1"] = "xxxxxxxxxxxxx" mymap["Name2"] = "xxxxxxxxxxxxxxxxxxxx" mymap["Name3"] = "xxxxxxxxxxxxxxxxxx" mymap["Name"] = "buickxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" for i := 0; i < b.N; i++ { //use b.N for looping json.Marshal(&mymap) } } BenchMark脚本 ...

March 28, 2018 · 2 min