- 业务会使用 id生成器 产生的 分布式唯一ID,长度比较长。代码反序列化时,出现精度丢失,导致线上故障。
package main
import (
"testing"
"time"
"github.com/bytedance/sonic"
"github.com/stretchr/testify/assert"
)
func TestPrintAttr(t *testing.T) {
amap := map[string]any{
"psm_businessline_ref": map[string]any{
"id": 1691071059696833999,
},
}
amapStr, err := sonic.MarshalString(amap)
assert.Nil(t, err)
t.Log("\n", amapStr)
m1 := make(map[string]any)
err = sonic.UnmarshalString(amapStr, &m1)
assert.Nil(t, err)
}
原因
float640x07FEF FFFF FFFF FFFF
(0x001F FFFF FFFF FFFF)16 = (9007199254740991)10
(0x07EF FFFF FFFF FFFF)16 = (9218868437227405311)10
也就是理论上数值超过9007199254740991(长度=16)就可能会出现精度缺失。
10进制数值的有效数字是16位,一旦超过16位大概率会有缺失精度的问题
一般分布式唯一id是20位长度,所以必然出现精度缺失。
参考:
解决方案- 使用 json.Decoder 来代替 json.Unmarshal 方法
package main
import (
"testing"
"time"
"github.com/bytedance/sonic"
"github.com/stretchr/testify/assert"
)
func TestPrintAttr(t *testing.T) {
amap := map[string]any{
"psm_businessline_ref": map[string]any{
"id": 1691071059696833999,
},
}
amapStr, err := sonic.MarshalString(amap)
assert.Nil(t, err)
t.Log("\n", amapStr)
rightM := make(map[string]any)
if len(amapStr) > 0 {
de := jsoniter.NewDecoder(bytes.NewReader([]byte(amapStr)))
de.UseNumber()
err := de.Decode(&rightM)
if err != nil {
t.Fatal(err)
}
}
}
json.Numberstringjson.Number
package json
// A Number represents a JSON number literal.
type Number string