故障背景
在昨天的工作中,遇到一个诡异的小问题,调试了一段时间,在网上也没有找到相关材料(可能谷歌能力有限,搜索不到,要用百度)。先来看一段简单的简化后的代码,简单、清晰、明了、接地气,与我的工作场景一致。
/*
* Copyright (c) 2020.
* panxie@tencent.com
*/
package main
import (
"encoding/json"
"fmt"
)
type L5 struct {
Modid int64 `json:"modid"`
Cmdid int64 `json:"cmdid"`
}
type CommonAttr struct {
Name string `json:"name"`
Desc string `json:"desc"`
}
type OperationQueryCKV struct {
L5
Expression string `json:"expression"`
TimeoutMs int64 `json:"timeout_ms"`
}
type Operation struct {
CommonAttr
*OperationQueryCKV
}
func main() {
op := &Operation{
CommonAttr{
Name: "op_name",
Desc: "op_desc",
},
&OperationQueryCKV{
L5: L5{
Modid: 12345,
Cmdid: 54321,
},
Expression: "expression",
TimeoutMs: 80,
},
}
b, _ := json.MarshalIndent(op,"","\t")
fmt.Printf("%s\n", string(b))
}
关注一下L5结构,这是一种公司内部服务负载均衡和服务发现的公共件,简单的说,一个L5可以换到一个IP和端口列表,然后拿去访问服务。对于CKV查询功能来说,需要一个L5表明CKV在哪。
漫天飞舞的匿名字段,是不是像golang大神特有的标签。运行一下,没问题,符合预期,完美。
[root@VM_15_146_centos ~]# go run main.go
{
"name": "op_name",
"desc": "op_desc",
"modid": 12345,
"cmdid": 54321,
"expression": "expression",
"timeout_ms": 80
}
故障现象
有一天,这样跑了一年的代码突然就不对了,测试发现,OperationQueryCKV结构序列化之后modid和cmdid都消失了,很邪乎。告诉我这个问题后,我也是一脸懵,我最近没有改动相关代码呀。都跑了一年了你跟我说这东西不行了?
故障原因
查看代码提交记录,一处改动进入视野,最近新增了一个查询数据库的功能,与OperationQueryCKV类似的,新增定义了一个OperationQuerySQL,只是新定义了结构,还没有实现和严格测试。
type OperationQuerySQL struct {
L5
User string `json:"user"`
Pwd string `json:"pwd"`
}
type Operation struct {
CommonAttr
*OperationQueryCKV
*OperationQuerySQL
}
查询数据库也需要一个L5,一贯风格,新增一个L5的匿名变量,完活。估计就是两个匿名L5,把值搞没了。试着跑一下样例代码。
func main() {
op := &Operation{
CommonAttr{
Name: "op_name",
Desc: "op_desc",
},
&OperationQueryCKV{
L5: L5{
Modid: 12345,
Cmdid: 54321,
},
Expression: "expression",
TimeoutMs: 80,
},
nil,
}
b, _ := json.MarshalIndent(op, "", "\t")
fmt.Printf("%s\n", string(b))
}
结果,我的L5果然没有了。根本原因应该是匿名变量导致的json字段key重复。
{
"name": "op_name",
"desc": "op_desc",
"expression": "expression",
"timeout_ms": 80
}
解决方法
这样的坑,在分工合作时会不经意引入,有时比较隐晦。
暂时也不知道好的办法,建议是不用或者少用匿名字段,如果需要使用匿名字段,每项都定义不同的`json:”_key_“`。