我的数据层使用大量的Mongo聚合,平均而言,查询需要500-650毫秒才能返回。我正在使用mgo。
mgo
下面显示了一个示例查询函数,该函数代表了我大部分查询的外观。
func (r userRepo) GetUserByID(id string) (User, error) { info, err := db.Info() if err != nil { log.Fatal(err) } session, err := mgo.Dial(info.ConnectionString()) if err != nil { log.Fatal(err) } defer session.Close() var user User c := session.DB(info.Db()).C("users") o1 := bson.M{"$match": bson.M{"_id": id}} o2 := bson.M{"$project": bson.M{ "first": "$first", "last": "$last", "email": "$email", "fb_id": "$fb_id", "groups": "$groups", "fulfillments": "$fulfillments", "denied_requests": "$denied_requests", "invites": "$invites", "requests": bson.M{ "$filter": bson.M{ "input": "$requests", "as": "item", "cond": bson.M{ "$eq": []interface{}{"$$item.active", true}, }, }, }, }} pipeline := []bson.M{o1, o2} err = c.Pipe(pipeline).One(&user) if err != nil { return user, err } return user, nil }
user我拥有的结构如下所示。
user
type User struct { ID string `json:"id" bson:"_id,omitempty"` First string `json:"first" bson:"first"` Last string `json:"last" bson:"last"` Email string `json:"email" bson:"email"` FacebookID string `json:"facebook_id" bson:"fb_id,omitempty"` Groups []UserGroup `json:"groups" bson:"groups"` Requests []Request `json:"requests" bson:"requests"` Fulfillments []Fulfillment `json:"fulfillments" bson:"fulfillments"` Invites []GroupInvite `json:"invites" bson:"invites"` DeniedRequests []string `json:"denied_requests" bson:"denied_requests"` }
根据我提供的信息,有什么明显的东西可以暗示为什么我的查询平均需要500-650ms?
我知道使用聚合管道可能会降低性能,但我不希望它这么糟糕。
..有什么明显的证据可以表明为什么我的查询器平均需要500-650ms?
就在这里。您mgo.Dial()在执行每个查询之前先进行调用。mgo.Dial()必须每次都连接到MongoDB服务器,在查询后立即关闭它。建立连接很可能需要数百毫秒,包括身份验证,分配资源(在服务器和客户端),等等。这非常浪费。
mgo.Dial()
对于给定的群集,通常只调用一次此方法。 然后,在获取的会话上使用“新建”或“复制”方法建立到同一群集的其他会话。这将使它们共享基础群集,并适当地管理连接池。
创建一个全局会话变量,在启动时连接 一次 (使用例如包init()函数),然后使用该会话(或由Session.Copy()或获得的该会话的副本/克隆Session.Clone())。例如:
init()
Session.Copy()
Session.Clone()
var session *mgo.Session var info *db.Inf // Use your type here func init() { var err error if info, err = db.Info(); err != nil { log.Fatal(err) } if session, err = mgo.Dial(info.ConnectionString()); err != nil { log.Fatal(err) } } func (r userRepo) GetUserByID(id string) (User, error) { sess := session.Clone() defer sess.Close() // Now we use sess to execute the query: var user User c := sess.DB(info.Db()).C("users") // Rest of the method is unchanged... }