Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB批量写入内存成本_Mongodb_Go_Memory Leaks_Bulkinsert - Fatal编程技术网

MongoDB批量写入内存成本

MongoDB批量写入内存成本,mongodb,go,memory-leaks,bulkinsert,Mongodb,Go,Memory Leaks,Bulkinsert,我使用的是官方的mongodb驱动程序。我获取一个CSV并逐行读取,直到达到1000行,然后解析数据并将其插入数据库。我假设它需要一个恒定的内存,因为大容量写入的数据总是相同的(1000个联系人)。然而,情况并非如此,因为内存显著增加。以下是有关上述查询的一些数据: batchSize = 1000 Contacts - Memory consumed by bulkwrite 10k - 14 MB 20K - 30MB 30K - 59MB 40K - 137 MB 50K -241 MB

我使用的是官方的
mongodb
驱动程序。我获取一个CSV并逐行读取,直到达到1000行,然后解析数据并将其插入数据库。我假设它需要一个恒定的内存,因为大容量写入的数据总是相同的(1000个联系人)。然而,情况并非如此,因为内存显著增加。以下是有关上述查询的一些数据:

batchSize = 1000

Contacts - Memory consumed by bulkwrite
10k - 14 MB
20K - 30MB
30K - 59MB
40K - 137 MB
50K -241 MB
有人能解释为什么吗

代码如下:

func (c *csvProcessor) processCSV(r io.Reader, headerMap map[string]int, emailDB *mongo.Database) error {
    //some code...
    csvReader := csv.NewReader(r)
    for {
        eofReached, err := c.processCSVBatch(csvReader, emailHash, smsHash, headerMap, emailDB)
        if err != nil {
            return errors.Wrap(err, "process CSV batch")
        }
        if eofReached {
            break
        }
    }
    return nil
}

func (c *csvProcessor) processCSVBatch(csvReader *csv.Reader, emailHash map[string]*userData, smsHash map[string]*userData, headerMap map[string]int, emailDB *mongo.Database) (bool, error) {
    var insertUsers, updateUsers, deleteUsers []interface{}
    var isEOFReached bool
    for i := 0; i < processCSVBatchSize; i++ {
        line, err := csvReader.Read()
        if err != nil {
            if err != io.EOF {
                return false, errors.Wrap(err, "read from input")
            }
            isEOFReached = true
            break
        }
        //some code
        insert, update, delete := c.dataMerger.mergeData(
            c.parseUser(line, headerMap),
            emailHash[stringToMD5(line[headerMap["email"]])],
            smsHashVal,
        )
        if insert != nil {
            insertUsers = append(insertUsers, insert)
        }
        if update != nil {
            updateUsers = append(updateUsers, update)
        }
        if delete != nil {
            deleteUsers = append(deleteUsers, delete)
        }
    }
    //update DB
    err := c.mongoDBUserHandler.saveUsers(emailDB, insertUsers, updateUsers, deleteUsers)
    if err != nil {
        return false, errors.Wrap(err, "save users")
    }
    return isEOFReached, nil
}

func (m *mongoDBUserHandler) saveUsers(emailDB *mongo.Database, insert, update, delete []interface{}) error {
    ctx := context.Background()
    // create the slice of write models
    var writes []mongo.WriteModel
    if len(insert) > 0 {
        writes = append(writes, m.getInsertWrites(insert)...)
    }
    if len(update) > 0 {
        writes = append(writes, m.getUpdateWrites(update)...)
    }
    if len(delete) > 0 {
        writes = append(writes, m.getDeleteWrites(delete)...)
    }
    if len(writes) == 0 {
        return nil
    }
    // run bulk write
    _, err := emailDB.
        Collection(userCollection).
        BulkWrite(ctx, writes, options.BulkWrite().SetOrdered(false))
    if err != nil {
        return errors.Wrap(err, "bulk write")
    }
    return nil
}
func(c*csvProcessor)processCSV(r io.Reader,headerMap[string]int,emailDB*mongo.Database)错误{
//一些代码。。。
csvReader:=csv.NewReader(r)
为了{
eofReached,err:=c.processCSVBatch(csvReader、emailHash、smsHash、headerMap、emailDB)
如果错误!=零{
返回错误。换行(错误,“处理CSV批”)
}
如果真的{
打破
}
}
归零
}
func(c*csvProcessor)处理CSVBatch(csvReader*csv.Reader,emailHash映射[string]*用户数据,smsHash映射[string]*用户数据,headerMap[string]int,emailDB*mongo.Database)(布尔,错误){
var insertUsers、updateUsers、deleteUsers[]接口{}
回程布尔值
对于i:=0;i0{
写入=追加(写入,m.getInsertWrites(插入)…)
}
如果len(更新)>0{
写入=追加(写入,m.getUpdateWrites(更新)…)
}
如果len(delete)>0{
writes=append(writes,m.getDeleteWrites(delete)…)
}
如果len(写入)==0{
归零
}
//运行批量写入
_,err:=emailDB。
集合(userCollection)。
BulkWrite(ctx,writes,options.BulkWrite().SetOrdered(false))
如果错误!=零{
返回错误。换行(错误,“大容量写入”)
}
归零
}
以下是伪装的:

    if len(insert) > 0 {
        writes = append(writes, m.getInsertWrites(insert)...)
    }
    if len(update) > 0 {
        writes = append(writes, m.getUpdateWrites(update)...)
    }
    if len(delete) > 0 {
        writes = append(writes, m.getDeleteWrites(delete)...)
    }

非常简单:删除上面的行,将BulkWrite更改为接受
写入
接口{}
,这样您就可以重用相同的备份数组,这应该会节省一些内存。

您可以共享代码吗?可能是go runtime dynamic stack Growth或goroutine heap allocdo您是否配置了片容量?@mh cbon每次尝试将数据保存到数据库时,都会分配一个新片。您可以参考上面的代码。@mh cbon请再次阅读代码-每1000行批次都有新的切片,因此,除非您能指出切片可能无限增长的其他地方,否则我看不出这有什么关系。