Http 死机:运行时错误:内存地址无效或对较大数据的零指针取消引用
我正在使用ApachePrediction IO开发一个推荐引擎。在使用事件服务器之前,我有一个GO api,用于侦听来自客户和导入器的事件。在特定情况下,当客户使用importer时,我收集导入的标识,并从importer api向GO api发送json。例如,如果用户导入一个包含45000个数据的csv,我会以类似于json的Http 死机:运行时错误:内存地址无效或对较大数据的零指针取消引用,http,go,nullpointerexception,goroutine,predictionio,Http,Go,Nullpointerexception,Goroutine,Predictionio,我正在使用ApachePrediction IO开发一个推荐引擎。在使用事件服务器之前,我有一个GO api,用于侦听来自客户和导入器的事件。在特定情况下,当客户使用importer时,我收集导入的标识,并从importer api向GO api发送json。例如,如果用户导入一个包含45000个数据的csv,我会以类似于json的{“条形码”:[…]}的格式发送这些45000个identity to GO api。预测IO事件服务器需要特定形状的数据 type ItemEvent struct
{“条形码”:[…]}
的格式发送这些45000个identity to GO api。预测IO事件服务器需要特定形状的数据
type ItemEvent struct {
Event string `json:"event"`
EntityType string `json:"entityType"`
EntityId string `json:"entityId"`
Properties map[string][]string `json:"properties"`
EventTime time.Time `json:"eventTime"`
}
type ItemBulkEvent struct {
Event string `json:"event"`
Barcodes []string `json:"barcodes"`
EventTime time.Time `json:"eventTime"`
}
ItemEvent
是我将从GO Api发送到事件服务器的最终数据ItemBulkEvent
是我从导入器api收到的数据
func HandleItemBulkEvent(w http.ResponseWriter, r *http.Request) {
var itemBulk model.ItemBulkEvent
err := decode(r,&itemBulk)
if err != nil {
log.Fatalln("handleitembulkevent -> ",err)
util.RespondWithError(w,400,err.Error())
}else {
var item model.ItemEvent
item.EventTime = itemBulk.EventTime; item.EntityType = "item"; item.Event = itemBulk.Event
itemList := make([]model.ItemEvent,0,50)
for index, barcode := range itemBulk.Barcodes{
item.EntityId = barcode
if (index > 0 && (index % 49) == 0){
itemList = append(itemList, item)
go sendBulkItemToEventServer(w,r,itemList)
itemList = itemList[:0]
}else if index == len(itemBulk.Barcodes) - 1{
itemList = append(itemList, item)
itemList = itemList[:( (len(itemBulk.Barcodes) - 1) % 49)]
go sendBulkItemToEventServer(w,r,itemList) // line 116
itemList = itemList[:0]
} else{
itemList = append(itemList, item)
}
}
util.RespondWithJSON(w,200,"OK")
}
}
HandleItemBulkEvent
是批量更新的处理函数。在这一步中,我应该提到prediction io的批量上传。通过RESTAPI预测io事件服务器为每个请求接收50个事件。所以我创建了一个有50个上限和一个项目的列表。我使用了相同的物品,只是每一次都改变了身份部分(条形码)并添加到列表中。每50分钟。我使用了一个处理函数将列表发送到事件服务器,然后清理列表,依此类推
func sendBulkItemToEventServer(w http.ResponseWriter, r *http.Request, itemList []model.ItemEvent){
jsonedItem,err := json.Marshal(itemList)
if err != nil{
log.Fatalln("err marshalling -> ",err.Error())
}
// todo: change url to event server url
resp, err2 := http.Post(fmt.Sprintf("http://localhost:7070/batch/events.json?accessKey=%s",
r.Header.Get("Authorization")),
"application/json",
bytes.NewBuffer(jsonedItem))
if err2 != nil{
log.Fatalln("err http -> " , err.Error()) // line 141
}
defer resp.Body.Close()
}
sendBulkItemToEventServer
函数封送传入的itemlist并向prediction io的事件服务器发出post请求。在这一部分中,当我尝试使用5000+项时,它做得很好,但当我尝试使用45000项时,应用程序崩溃,出现以下错误
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xc05938]
goroutine 620 [running]:
api-test/service.sendBulkItemToEventServer(0x1187860, 0xc00028e0e0, 0xc00029c200, 0xc00011c000, 0x31, 0x32)
/home/kadirakinkorkunc/Desktop/playground/recommendation-engine/pio_api/service/CollectorService.go:141 +0x468
created by api-test/service.HandleItemBulkEvent
/home/kadirakinkorkunc/Desktop/playground/recommendation-engine/pio_api/service/CollectorService.go:116 +0x681
Debugger finished with exit code 0
你知道我该怎么解决这个问题吗
编辑:正如Burak Serdar在回答中提到的那样,我通过在发送前使用编组修复了err、err2混淆和数据争用问题。现在我猜它给出了真正的错误(res,err2)
对此有什么想法吗?您的程序中有几个错误。运行时错误是因为您正在检查
err2
是否不是nil,但随后您正在打印err
,而不是err2
<代码>错误为零,因此运行时错误
这意味着err2
不是零,因此您应该看到该错误是什么
您提到您正在以50个批次发送消息,但这种实现是错误的。将元素添加到itemList
,然后使用该itemList
启动goroutine,然后截断它并再次开始填充。这是一场数据竞赛,您的goroutines将看到处理程序正在修改的itemList
实例。当您向goroutine提交一个项目列表时,只需创建一个新的itemList
,而不是截断,这样每个goroutine都可以有自己的副本
如果要继续使用同一个切片,可以封送该切片,然后将JSON消息传递给goroutine,而不是该切片。您收到的错误是您向其发出请求的服务器发送的错误。查看了解有关错误的更多信息 很可能是以下for循环
迭代次数太多,并且由于您使用单独的go例程来创建请求,因此所有请求都会同时发生,这会使服务器过载或故意关闭连接。请提及第141行的代码。我在代码中将这些行声明为注释,我想您错过了。谢谢,我照你说的做了。现在它给了我真正的原因,我猜。如果你想看一下,我编辑了这个问题。看起来这些请求的接收端有问题。检查该服务器的日志。可能您正在使用许多并发请求来重载它。
2020/08/03 15:11:55 err http -> Post "http://localhost:7070/batch/events.json?accessKey=FJbGODbGzxD-CoLTdwTN2vwsuEEBJEZc4efrSUc6ekV1qUYAWPu5anDTyMGDoNq1": read tcp 127.0.0.1:54476->127.0.0.1:7070: read: connection reset by peer
for index, barcode := range itemBulk.Barcodes{