http - panic : runtime error: invalid memory address or nil pointer dereference with bigger data

标签 http go nullpointerexception goroutine predictionio

我正在使用 Apache Prediction IO 开发推荐引擎。在事件服务器之前,我有一个 GO api,用于监听来自客户和进口商的事件。在客户使用导入器的特定情况下,我收集导入的身份,并将 json 从导入器 api 发送到 GO api。例如,如果用户导入一个包含 45000 个数据的 csv,我会将这 45000 个身份以 json 格式发送到 GO api,例如 {"barcodes":[...]}。 .预测 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是批量更新的处理函数。在这一步中,我应该提到预测 io 的批量上传。通过 rest api 预测 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函数编码传入的项目列表并向预测 io 的事件服务器发出发布请求。在这部分中,当我尝试使用 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)我猜。
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
对此有任何想法吗?

最佳答案

您的程序中有几个错误。运行时错误是因为您正在检查 err2不是零,但是你正在打印 err ,而不是 err2 . err为零,因此运行时错误。
这意味着 err2不是零,所以你应该看到那个错误是什么。
您提到您正在分批发送 50 条消息,但该实现是错误的。您将元素添加到 itemList , 然后用 itemList 启动一个 goroutine ,然后截断它并重新开始填充。这是一场数据竞赛,你的 goroutine 将看到 itemList处理程序正在修改的实例。而不是截断,只需创建一个新的 itemList当您向 goroutine 提交一个时,每个 goroutine 都可以拥有自己的副本。
如果您想继续使用相同的 slice ,您可以编码 slice ,然后将 JSON 消息传递给 goroutine 而不是 slice 。

关于http - panic : runtime error: invalid memory address or nil pointer dereference with bigger data,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63222424/

相关文章:

Python 获取 http 预告片

http - 媒体类型的后缀和子类型可以互换使用吗?

json - 如何使用 Go 部分解析 JSON?

jakarta-ee - "Exception while loading the app"没有堆栈跟踪

java - 什么是NullPointerException,我该如何解决?

asp.net - 如何在 AngularJS 2 中传递查询参数?

python - Python 中的网站压力测试 - Django

python-2.7 - 如何在 Golang 中重命名不同目录中的一组文件

go - 如何将标准输出从 os.Exec 传输到文件和终端?

java - 什么是 NullPointerException,我该如何解决?