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行批次都有新的切片,因此,除非您能指出切片可能无限增长的其他地方,否则我看不出这有什么关系。