在Go语言中同时使用相同的mgo会话(session)

huangapple go评论96阅读模式
英文:

Concurrently using the same mgo session in go

问题

所以我在使用Go语言与MongoDB并发时遇到了一些问题。我最初的获取会话的实现如下:

  1. var globalSession *mgo.Session
  2. func getSession() (*mgo.Session, error) {
  3. // 建立数据库连接
  4. if globalSession == nil {
  5. var err error
  6. globalSession, err = mgo.Dial(":27017")
  7. if err != nil {
  8. return nil, err
  9. }
  10. // 可选。将会话切换为单调行为。
  11. globalSession.SetMode(mgo.Monotonic, true)
  12. }
  13. return globalSession.Copy(), nil
  14. }

这个方法很好用,但我遇到的问题是MongoDB有204个连接的限制,然后它开始拒绝连接,报错信息为connection refused because too many open connections: 204。然而,问题是由于我调用了session.Copy(),它只返回一个会话而不是错误。所以即使连接被拒绝,我的程序也没有抛出错误。

现在我考虑的是只使用一个会话,而不是使用Copy(),这样我就可以获得连接错误,代码如下:

  1. var session *mgo.Session = nil
  2. func NewSession() (*mgo.Session, error) {
  3. if session == nil {
  4. session, err = mgo.Dial(url)
  5. if err != nil {
  6. return nil, err
  7. }
  8. }
  9. return session, nil
  10. }

现在我对此的问题是,如果我尝试并发使用同一个会话,会发生什么。

英文:

So I'm having some trouble figuring out best practices for using concurrency with a MongoDB in go. My first implementation of getting a session looked like this:

  1. var globalSession *mgo.Session
  2. func getSession() (*mgo.Session, error) {
  3. //Establish our database connection
  4. if globalSession == nil {
  5. var err error
  6. globalSession, err = mgo.Dial(":27017")
  7. if err != nil {
  8. return nil, err
  9. }
  10. //Optional. Switch the session to a monotonic behavior.
  11. globalSession.SetMode(mgo.Monotonic, true)
  12. }
  13. return globalSession.Copy(), nil
  14. }

This works great the trouble I'm running into is that mongo has a limit of 204 connections then it starts refusing connections connection refused because too many open connections: 204;however, the issue is since I'm calling session.Copy() it only returns a session and not an error. So event though the connection refused my program never thrown an error.

Now what I though about doing is just having one session and using that instead of copy so I can have access to a connection error like so:

  1. var session *mgo.Session = nil
  2. func NewSession() (*mgo.Session, error) {
  3. if session == nil {
  4. session, err = mgo.Dial(url)
  5. if err != nil {
  6. return nil, err
  7. }
  8. }
  9. return session, nil
  10. }

Now the problem I have with this is that I don't know what would happen if I try to make concurrent usage of that same session.

答案1

得分: 1

关键是复制会话,然后在使用完毕后关闭它。

  1. func GetMyData() []myMongoDoc {
  2. sessionCopy, _ := getSession() // 来自上面的问题
  3. defer sessionCopy.Close() // 这是重要的部分
  4. results := make([]myMongoDoc, 0)
  5. sessionCopy.DB("myDB").C("myCollection").Find(nil).All(&results)
  6. return results
  7. }

话虽如此,看起来 mgo 实际上并没有暴露对底层连接的控制(请参阅维护该库的 Gustavo Niemeyer 的评论)。一个会话基本上等同于一个连接,但即使在会话上调用 Close(),mgo 仍然保持连接处于活动状态。从周围的阅读中,似乎 Clone() 可能是一个可行的方法,因为它重用底层套接字,这将避免创建新套接字的三次握手(有关差异的更多讨论,请参见这里)。

还可以参考这个SO答案,描述了处理会话的标准模式。

英文:

The key is to duplicate the session and then close it when you've finished with it.

  1. func GetMyData() []myMongoDoc {
  2. sessionCopy, _ := getSession() // from the question above
  3. defer sessionCopy.Close() // this is the important bit
  4. results := make([]myMongoDoc, 0)
  5. sessionCopy.DB("myDB").C("myCollection").Find(nil).All(&results)
  6. return results
  7. }

Having said that it looks like mgo doesn't actually expose control over the underlying connections (see the comment from Gustavo Niemeyer who maintains the library). A session pretty much equates to a connection, but even if you call Close() on a session mgo keeps the connection alive. From reading around it seems that Clone() might be the way to go, as it reuses the underlying socket, this will avoid the 3 way handshake of creating a new socket (see here for more discussion on the difference).

Also see this SO answer describing a standard pattern to handle sessions.

huangapple
  • 本文由 发表于 2015年9月26日 01:56:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/32787999.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定