可复现的代码:
https://gitee.com/tianshuapp/web-deploy-task-manage
使用的是gofiber框架,在包内设置了一个全局变量来保存数据,如下:
var list = make(map[int64]*Task, 10)
// var list2 sync.Map // 时隔两个月,用sync.Map试了一次,依然出现这个问题
type Task struct {
ID int64
Name string
}
gofiber设置了两个接口,一个是创建:
func Create(c *fiber.Ctx) error {
task := &Task{
ID: time.Now().Unix(),
Name: "agent-web",
}
list[task.ID] = task
return c.JSON(task)
}
一个是查询:
func Detail(c *fiber.Ctx) error {
_id, err := strconv.Atoi(c.Query("id"))
if err != nil {
return c.SendString("id为空")
}
id := int64(_id)
task, ok := list[id]
if !ok {
return c.SendString("task不存在")
}
return c.JSON(task)
}
我在node端(实测postman也如此)依次请求创建与查询,就会有几率触发Name异常,比如创建了:
{
ID: 1670430590397846,
Name: "agent-web"
}
请求Detail时,却变成了:
{
ID: 1670430590397846,
Name: "167043059"
}
Name异常的表现是9个字符被ID的前9个数字替代。
在Create方法里,创建完立即查询,值是正常的,测了很多次;
我建了个协程,在里面每隔1秒打印一次全局变量list,仅是创建的话,不会异常,如果请求Detail,就会有几率瞬间改变Name。
后来我把创建方法的ID值改成计数器,,测了10000次也不会出现这种异常的情况了 依然存在这个问题:
var counter int64 = 0
func Create(c *fiber.Ctx) error {
counter ++
task := &Task{
ID: counter,
Name: "agent-web",
}
list[task.ID] = task
return c.JSON(task)
}
建议以后少用int,多用string
希望有识之士帮忙分析一下其中原因。
我错了,我判断是否出现异常的方法是判断查询到的name是否是数字,这是错的。
因为出现了这种情况:
name的第一个字符被id的第一个字符替换了!
暂时无解了,id换字符串试试 。
ID改完字符串类型也会冲掉Name字段
也不一定是Name字段,结构体里还有User string;Arch string
改动一番代码后,有时是User字段被改,有时是Arch字段被改,可能Name字段就一直是正常的
总之这三个字符串字段不一定哪个有问题,有问题的偶尔有问题,有的字段一直没问题
还使用了一个ristretto库,支持并发的高性能内存缓存,依然存在此问题。
暂时无解
2个月后,使用了sync.Map测试,依然如此问题。
可复现的代码:
https://gitee.com/tianshuapp/web-deploy-task-manage
破案了,是gofiber的问题,Immutable 参数改一下就可以正常了。