gopkg.in/mgo.v2(Mongo, Go)中的并发性

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

Concurrency in gopkg.in/mgo.v2 (Mongo, Go)

问题

我希望在使用Go编写的Web应用程序中使用MongoDB。

我可以拥有一个mgo.Session并在Web应用程序中并发使用它吗?例如在http.Handler中。

还是我应该调用Session.CopySession.Close来创建会话池?

听起来有些矛盾,我在某些地方读到mgo.Session内部已经实现了连接池,可以并发使用会话,而在其他地方我读到需要使用CopyClose

英文:

I wish to use MongoDB in webapp written in Go.

Can I have one mgo.Session and use it concurrently in web app. e.g. in http.Handler

or should I call Session.Copy and Session.Close -> make pool of sessions.

It sounds contradictory somewhere I read that pool is already implemented inside of mgo.Session and I can use session concurrently and in other places I read that I need Copy and Close.

答案1

得分: 9

mgo.Session 是线程安全的。引用它的文档:

> 所有的 Session 方法都是线程安全的,可以从多个 goroutine 中调用。

但这并不意味着你不应该在并行中创建和使用更多的 Session,通过调用 Session.Copy()Session.Clone(),在初始的 dial 时间获取的 Session 上。

线程安全和使用更多 Session 的好处并不互斥。虽然你可以从任意数量的 goroutine 中使用单个 mgo.Session,但这样做不会很好地扩展,甚至根本不会扩展。Session 自动管理一个连接池,甚至可能连接到多个服务器节点,但如果你使用单个 Session,你就无法利用这一点。通过在每个请求开始时创建一个新的 Session(如果需要),并在结束时正确关闭它(使用 Session.Close(),最好使用 defer 调用),你可以利用同时使用多个连接的潜力,可能连接到多个服务器节点(如果可用),从而更好地利用服务器资源,并获得更快的响应时间(无论是从数据库还是最终传递给 HTTP 终端用户)。调用 Session.Close() 不会关闭与服务器的底层连接,它只会将连接放回连接池,准备好供另一个 Session 使用。

还可以参考关于使用 Session 的相关问题:https://stackoverflow.com/questions/40999637/mgo-query-performance-seems-consistently-slow-500-650ms/41000876#41000876

英文:

The mgo.Session is safe for concurrent use. Quoting from its doc:

> All Session methods are concurrency-safe and may be called from multiple goroutines.

But this doesn't mean you should not create and use more of them in parallel, by calling Session.Copy() or Session.Clone(), on the initial session obtained at dial time.

Being concurrency-safe and having benefit from using more of them do not exclude each other (they are not mutually exclusive). While you may use a single mgo.Session from arbitrary number of goroutines, that will not scale well, that will not scale at all. Sessions automatically manage a pool of connections, maybe even to multiple server nodes, but if you're using a single Session, you're not taking advantage of that. By creating a new Session at the start of each of your request (if needed), and properly closing it at the end (with Session.Close(); preferably called using defer), you are taking advantage of potentially using multiple connections at the same time, possibly to multiple server nodes (if available), and thus better utilizing server resources; and getting faster response times (both from the database, and ultimately to your HTTP end users). Calling Session.Close() does not close the underlying connection to the server, it will just put the connection back to the pool, ready to be picked up by another session.

Also see related question about the use of Sessions: https://stackoverflow.com/questions/40999637/mgo-query-performance-seems-consistently-slow-500-650ms/41000876#41000876

答案2

得分: 4

调用DialDialWithTimeoutDialWithInfo将建立连接池。如果您需要多个会话,则需要调用session.Copy()session.New(),推荐使用session.Copy(),因为它将保留授权信息。以下是一个示例:

假设您有一个UserService结构体来处理所有用户数据库需求。请注意,这是我凭记忆写的,所以可能有一些语法错误,但思路是正确的。

type UserService struct {
    DB *mgo.Session
}

func (s *UserService) Create(u *User) error {
    sessionCopy := s.DB.Copy()
    defer sessionCopy.Close()
    
    db := sessionCopy.DB("test_db")
    col := db.C("users")

    if err := col.Insert(u); err != nil {
        return err
    }
}

以上是一个示例代码。

英文:

Calling Dial or DialWithTimeout or DialWithInfo will establish the connection pool. If you need more than one session then you need to call session.Copy() or session.New(), session.Copy() is preferred since it will retain the auth. Here is an example:

Lets say you have a UserService struct to handle all your user db needs. Note this is from the top of my head so there might be a few syntax errors but the idea is there.

type Userservice struct {
    DB *mgo.Session
}

func (s *Userservice) Create(u *User) error {
    sessionCopy := s.DB.Copy()
    defer sessionCopy.Close()
    
    db := sessionCopy.DB("test_db")
	col := db.C("users")

    if err := col.Insert(u); err != nil {
        return err
    }
}

huangapple
  • 本文由 发表于 2017年2月28日 01:25:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/42492020.html
匿名

发表评论

匿名网友

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

确定