douru5373 2015-10-18 23:25
浏览 71
已采纳

在例程上执行gogo的mongodb查询会产生巨大的堆栈跟踪(使用mgo)

I am doing lots of web calls to an api in a go program, and the results are stored in a database (using mgo). The api calls are done on separate go routines. On other routines, I am pulling the information out of the database and processing it, before updating the database. When the data is put back, a flag is set so that it is known that that data has been post processed so when the program asks the database for another entry to post process the database hands back one where the flag complete is set to false. When the flag is set to true, the go routine is shutdown: wg.done().

All is good, I have lots of print outs telling me how the program is getting on, however towards the end of its running I get a huge stack trace containing lots of the same:

goroutine 56731 [sleep]: 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 created by gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 +0x162

goroutine 56698 [sleep]: 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 created by gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 +0x162

goroutine 56699 [sleep]: 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 created by gopkg.in/mgo%2ev2.newCluster /Users/alex/go/src/gopkg.in/mgo.v2/cluster.go:73 +0x1a0

goroutine 56738 [sleep]: 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 created by gopkg.in/mgo%2ev2.newServer /Users/alex/go/src/gopkg.in/mgo.v2/server.go:88 +0x162

There is one thing amongst all of those that is below, which is the only different output on the stack trace to the above (the above is just a sample, my terminal can't scroll back to the beginning there is so many)

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.(*Reader).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 net/http.(*persistConn).readLoop(0xc82751fce0) /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:876 +0xf7 created by net/http.(*Transport).dialConn /usr/local/Cellar/go/1.5/libexec/src/net/http/transport.go:685 +0xc78

I am struggling to work out what it is telling me, whether its locking on writing to the database, whether the routines aren't closing and something is timing out, I don't know. I am using go 1.5 btw.

Any help on how to interpret the above would be great.

The code that talks with the database is below:

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条回答 默认 最新

  • doumao8355 2015-10-19 12:15
    关注

    It looks like the quoted logic is dialing MongoDB every time it needs to do something with it, which isn't the appropriate way to hold sustained database communication within an HTTP server.

    Every time you Dial a MongoDB server (or replica set, or mongos), some background activity is started to keep the cluster topology up-to-date in memory, and to maintain the pool of connections sane (note that all sessions that are created after a single Dial call will share a single pool of connections).

    Calling Dial every time one wants to talk to the database means all of that logic becomes independent for each of the dials, and that background activity may take a moment to shut down after the last session is closed.

    So even though it will work, it's very inefficient as it has to learn again about the topology in use, it fails to use connections from an existing pool, and it also creates unnecessary background churn which is what you are observing in your backtrace.

    For some ideas on how to better maintain a session in this context, please see this topic:

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥170 如图所示配置eNSP
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效
  • ¥15 悬赏!微信开发者工具报错,求帮改
  • ¥20 wireshark抓不到vlan
  • ¥20 关于#stm32#的问题:需要指导自动酸碱滴定仪的原理图程序代码及仿真
  • ¥20 设计一款异域新娘的视频相亲软件需要哪些技术支持
  • ¥15 stata安慰剂检验作图但是真实值不出现在图上