go(golang)对例程的mongodb查询会产生巨大的堆栈跟踪(使用mgo)

时间:2015-10-18 23:25:33

标签: mongodb go goroutine mgo

我在go程序中对api进行了大量的Web调用,结果存储在数据库中(使用mgo)。 api调用是在单独的go例程上完成的。在其他例程中,我在更新数据库之前将信息从数据库中提取出来并进行处理。当放回数据时,设置一个标志,以便知道该数据已经过后处理,因此当程序要求数据库提供另一个条目以进行后处理时,数据库会将数据库交回标志complete为设为false。当该标志设置为true时,go例程将关闭:wg.done()

一切都很好,我有很多打印输出告诉我程序是如何进行的,但是在运行结束时我会得到一个包含大量相同内容的巨大堆栈跟踪:

  

goroutine 56731 [睡觉]:time.Sleep(0x12a05f200)     /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9   gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82601b420,0x1)     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者   gopkg.in/mgo%2ev2.newServer     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162

     

goroutine 56698 [睡眠]:time.Sleep(0x12a05f200)     /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9   gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82601bce0,0x1)     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者   gopkg.in/mgo%2ev2.newServer     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162

     

goroutine 56699 [睡眠]:time.Sleep(0x1dcd6500)     /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9   gopkg.in/mgo%2ev2.(*mongoCluster).syncServersLoop(0xc8256425a0)     /Users/alex/go/src/gopkg.in/mgo.v2/cluster.go:353 + 0x2b1由   gopkg.in/mgo%2ev2.newCluster     /Users/alex/go/src/gopkg.in/mgo.v2/cluster.go:73 + 0x1a0

     

goroutine 56738 [睡眠]:time.Sleep(0x12a05f200)     /usr/local/Cellar/go/1.5/libexec/src/runtime/time.go:59 + 0xf9   gopkg.in/mgo%2ev2.(*mongoServer).pinger(0xc82606fa40,0x1)     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:295 + 0x1b4由创建者   gopkg.in/mgo%2ev2.newServer     /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 + 0x162

下面的所有内容中都有一件事,这是上面的堆栈跟踪中唯一不同的输出(上面只是一个示例,我的终端可以滚动回到开头有这么多)

  

goroutine 57201 [IO wait]:net.runtime_pollWait(0xedb6f0,0x72,   0xc82000a2c0)     /usr/local/Cellar/go/1.5/libexec/src/runtime/netpoll.go:157 + 0x60   net。(* pollDesc).Wait(0xc827b0e5a0,0x72,0x0,0x0)     /usr/local/Cellar/go/1.5/libexec/src/net/fd_poll_runtime.go:73+0x3a   net。(* pollDesc).WaitRead(0xc827b0e5a0,0x0,0x0)     /usr/local/Cellar/go/1.5/libexec/src/net/fd_poll_runtime.go:78 + 0x36   net。(* netFD).Read(0xc827b0e540,0xc828d61000,0x1000,0x1000,0x0,   0x754050,0xc82000a2c0)     /usr/local/Cellar/go/1.5/libexec/src/net/fd_unix.go:232+0x23a   net。(* conn).Read(0xc8260eac38,0xc828d61000,0x1000,0x1000,0x0,0x0,   0x0)/usr/local/Cellar/go/1.5/libexec/src/net/net.go:172 + 0xe4   net / http.noteEOFReader.Read(0x7960c0,0xc8260eac38,0xc82751fd38,   0xc828d61000,0x1000,0x1000,0xc82644dc20,0x0,0x0)     /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:1370+0x67   net / http。(* noteEOFReader).Read(0xc826116e60,0xc828d61000,0x1000,   0x1000,0xc827d1a770,0x0,0x0):126 + 0xd0   BUFIO。(*阅读器).fill伪(0xc82644d4a0)     /usr/local/Cellar/go/1.5/libexec/src/bufio/bufio.go:97 + 0x1e9   bufio。(* Reader).Peek(0xc82644d4a0,0x1,0x0,0x0,0x0,0x0,0x0)     /usr/local/Cellar/go/1.5/libexec/src/bufio/bufio.go:132 + 0xcc   净/ HTTP(* persistConn).readLoop(0xc82751fce0)     /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:876 + 0xf7   由net / http。(* Transport).dialConn创建     /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:685 + 0xc78

我正在努力弄清楚它告诉我的是什么,它是否锁定写入数据库,例程是否关闭以及某些事情已经超时,我不知道。 我正在使用1.5 btw。

任何有关如何解释上述内容的帮助都会很棒。

与数据库对话的代码如下:

func (l *Ledger) addRaceToDatabase(race Race) { //true if added, 

false if existed
  session, err := mgo.Dial("127.0.0.1")
  if err != nil {
    panic(err)
  }

  defer session.Close()

  session.SetMode(mgo.Monotonic, true)

  c := session.DB("collection").C("races")

    // Index
  index := mgo.Index{
    Key:        []string{"id"},
    Unique:     true,
    DropDups:   true,
    Background: true,
    Sparse:     true,
  }

  err = c.EnsureIndex(index)
  if err != nil {
    panic(err)
  }

  result := Race{}
  //if the race exists, don't add it to the database
  err = c.Find(bson.M{"id": race.ID}).One(&result)
  if err != nil {
    //if there is an error there wasn't an entry so add this to the database
    err = c.Insert(race)
    if err != nil {
        panic(err)
    }   
  } else {
    //if it does find an entry, it will print it
    fmt.Println("FOUND: ", result.ID)
  }
}

1 个答案:

答案 0 :(得分:0)

看起来引用的逻辑是每次需要对它执行某些操作时拨打MongoDB,这不是在HTTP服务器中保持持续数据库通信的适当方式。

每次Dial MongoDB服务器(或副本集或mongos)时,都会启动一些后台活动,以使集群拓扑在内存中保持最新状态,并保持连接池的清晰(请注意,在单个Dial调用之后创建的所有会话将共享一个连接池。)

每次想要与数据库通信时调用Dial意味着所有逻辑对于每个拨号都是独立的,并且在最后一个会话关闭后,后台活动可能需要一些时间才能关闭。

所以尽管它会起作用,但由于它必须再次学习使用的拓扑结构,它无法使用现有池中的连接,它也会产生不必要的背景流失,这就是你的工作效率非常低在你的回溯中观察。

有关如何在此上下文中更好地维护会话的一些想法,请参阅此主题: