1.mongo push ,set
在实践中写入mongo的时候使用了push,发现流量非常非常的大,简直到了无语的程度。
查找资料后发现,使用push的时候默认会返回整个document的数据,也就是说每一次写入都要读取整个document并返回,导致流量巨大,网上资料比较多,例如这个
后来采用set来实现,用updateMany,但是这个有个问题就是当新建的时候,返回数据里没办法判断是否写入成功。
c.UpdateMany(ctx, filter, bson.M{"$set": mKeyVal})
op := options.FindOneAndUpdateOptions{Projection: bson.M{"_id": 1}}
err = c.FindOneAndUpdate(ctx, filter, bson.M{"$push": bson.M{"msg": bson.M{"$each": msgListToMongo}}}, &op).Err()
UpdateMany 会存在的问题就是filter的document不存在的时候不会返回错误,只能通过返回结果里说未找到。
所以没办法判断是否要进行新增。
FindOneAndUpdate 假如不设置options的话,在返回结果里会返回整个document的数据,这样就会导致流量暴增,插入一条数据,返回几千条数据,导致服务器流量是天量,能达到几百M
这里设置op为只返回 _id 这样是最小量的了,是最小的结果,流量几KB即可
但是写入的流量就没办法了,这个就是真实的写入数据库的量。
$push 设置了option之后,速度也是比较快的,和set差不多,设置略快。
$set 在当前场景里不好判断是否新增一个document
2.如何判断某个端口的流量
iftop -f "src port 27017" -P
iftop -f "dst port 27017" -P
查看指定端口流量,src 表示源头流出,dst表示流入。
这样就能够看出流量变化了。
3.for range append陷阱
s := []int{1, 2, 3}
q := make([]*int, 0, 10)
for i, v := range s {
q = append(q, &v)
fmt.Println(&s[i])
}
for _, v := range q {
fmt.Println(v)
}
上面的代码里,for,range里打印出的 &v地址都是同一个,也就是说假如append里加入for range里的v值的地址,其实都是同一个,这样就出问题。
可以查看for range的源码发现,返回的index,value都是申请的临时变量。自己看源码麻烦的话,直接看这个文章