golang操作mongo使用的包是"gopkg.in/mgo.v2",coding过程中需要并发读写mongo数据库,简单观摩了下源码,记录下自己的一些理解,如有错误,敬请斧正。 

  一般来说,我们直接这样创建一个session:

Session, err = mgo.Dial(URL)

 if err != nil {

  log.Println(err)

}

  来看看Dial这个函数做了什么:

func Dial(url string) (*Session, error) {

session, err := DialWithTimeout(url, 10*time.Second)

if err == nil {

session.SetSyncTimeout(1 * time.Minute)

session.SetSocketTimeout(1 * time.Minute)

}

return session, err

}

  调用DialWithTimeout函数设置默认的超时时间是10秒。该函数中调用了DialWithInfo这个函数,而DialWithInfo函数中比较重要是是调用了newSession,看看这个函数做了什么操作:

func newSession(consistency Mode, cluster *mongoCluster, timeout time.Duration) (session *Session) {

cluster.Acquire()

session = &Session{

cluster_:    cluster,

syncTimeout: timeout,

sockTimeout: timeout,

poolLimit:   4096,

}

debugf("New session %p on cluster %p", session, cluster)

session.SetMode(consistency, true)

session.SetSafe(&Safe{})

session.queryConfig.prefetch = defaultPrefetch

return session

}

  返回的session设置了一些默认的参数,暂时先忽略,直接看看Session的数据结构:

type Session struct {

m                sync.RWMutex

cluster_         *mongoCluster

slaveSocket      *mongoSocket

masterSocket     *mongoSocket

slaveOk          bool

consistency      Mode

queryConfig      query

safeOp           *queryOp

syncTimeout      time.Duration

sockTimeout      time.Duration

defaultdb        string

sourcedb         string

dialCred         *Credential

creds            []Credential

poolLimit        int

bypassValidation bool

}

  m是mgo.Session的并发锁,因此所有的Session实例都是线程安全的。slaveSocket,masterSocket代表了该Session到mongodb主节点和从节点的一个物理连接的缓存。而Session的策略总是优先使用缓存的连接。是否缓存连接,由consistency也就是该Session的模式决定。假设在并发程序中,使用同一个Session实例,不使用Copy,而该Session实例的模式又恰好会缓存连接,那么,所有的通过该Session实例的操作,都会通过同一条连接到达mongodb。虽然mongodb本身的网络模型是非阻塞通信,请求可以通过一条链路,非阻塞地处理,但是会影响效率。

  其次mgo.Session缓存的一主一从连接,实例本身不负责维护。也就是说,当slaveSocket,masterSocket任意其一,连接断开,Session自己不会重置缓存,该Session的使用者如果不主动重置缓存,调用者得到的将永远是EOF。这种情况在主从切换时就会发生,在网络抖动时也会发生。

  mgo的DB句柄需要你做一个copy操作:

// Copy works just like New, but preserves the exact authentication

// information from the original session.

func (s *Session) Copy() *Session {

s.m.Lock()

scopy := copySession(s, true)

s.m.Unlock()

scopy.Refresh()

return scopy

}

  copySession将源Session浅拷贝到临时Session中,这样源Session的配置就拷贝到了临时Session中。关键的Refresh,将源Session浅拷贝到临时Session的连接缓存指针,也就是slaveSocket,masterSocket置为空,这样临时Session就不存在缓存连接,而转为去尝试获取一个空闲的连接。

mgo自身维护了一套到mongodb集群的连接池。这套连接池机制以mongodb数据库服务器为最小单位,每个mongodb都会在mgo内部,对应一个mongoServer结构体的实例,一个实例代表着mgo持有的到该数据库的连接。看看这个连接池的定义:

type mongoServer struct {

sync.RWMutex

Addr          string

ResolvedAddr  string

tcpaddr       *net.TCPAddr

unusedSockets []*mongoSocket

liveSockets   []*mongoSocket

closed        bool

abended       bool

sync          chan bool

dial          dialer

pingValue     time.Duration

pingIndex     int

pingCount     uint32

pingWindow    [6]time.Duration

info          *mongoServerInfo

}

  info代表了该实例对应的数据库服务器在集群中的信息——是否master,ReplicaSetName等。而两个Slice,就是传说中的连接池。unusedSockets存储当前空闲的连接,liveSockets存储当前活跃中的连接,Session缓存的连接就同时存放在liveSockets切片中,而临时Session获取到的连接就位于unusedSockets切片中。

  每个mongoServer都会隶属于一个mongoCluster结构,相当于mgo在内部,模拟出了mongo数据库集群的模型。

type mongoCluster struct {

sync.RWMutex

serverSynced sync.Cond

userSeeds    []string

dynaSeeds    []string

servers      mongoServers

masters      mongoServers

references   int

syncing      bool

direct       bool

failFast     bool

syncCount    uint

setName      string

cachedIndex  map[string]bool

sync         chan bool

dial         dialer

}

  mongoCluster持有一系列mongoServer的实例,以主从结构分散到两个数组中。  每个Session都会存储自己对应的,要操作的mongoCluster的引用。

  前面的描述可以总结成下面这张图:

  那么我们在使用的时候就可以创建一个Session,然后clone操作,用clone得到的copysession完成操作,结束后关闭这个copysession就可以了。

golang:mgo剖析之Session的更多相关文章

  1. golang mgo的mongo连接池设置:必须手动加上maxPoolSize

    本司礼物系统使用了golang的 mongo库 mgo,中间踩了一些坑,总结下避免大家再踩坑 golang的mgo库说明里是说明了开启连接复用的,但观察实验发现,这并没有根本实现连接的控制,连接复用仅 ...

  2. golang 性能剖析pprof

    作为一个golang coder,使用golang编写代码是基本的要求. 能够写出代码,并能够熟悉程序执行过程中各方面的性能指标,则是更上一层楼. 如果在程序出现性能问题的时候,可以快速定位和解决问题 ...

  3. golang context 剖析 1.7.4 版本

    1. 内部结构之 - timerCtx . type timerCtx struct { cancelCtx timer *time.Timer // Under cancelCtx.mu. dead ...

  4. Golang mgo 模糊查询的使用

    在日常使用的Mongodb中,有一项功能叫做模糊查询(使用正则匹配),例如: db.article.find({"title": {$regex: /a/, $options: & ...

  5. golang学习之mgo操作mongodb

    mgo是mongodb的golang驱动,测试代码: // mgotest project main.go package main import ( "fmt" "ti ...

  6. mgo中DBRef-数据添加测试

    2014-1-25 在设计mongo数据库时遇到这样一个问题,日志信息表需要引用人员信息表的数据.如果是结构化数据库,基本上不用想太多的东西.由于刚接触非结构化数据库,按着书上的理解由于日志数量较多, ...

  7. session机制详解以及session的相关应用

    session是web开发里一个重要的概念,在大多数web应用里session都是被当做现成的东西,拿来就直接用,但是一些复杂的web应用里能拿来用的session已经满足不了实际的需求,当碰到这样的 ...

  8. mgo中DBRef-数据查询测试

    下午对数据查询进行了代码测试: package main import ( "crypto/rand" "encoding/hex" "fmt&quo ...

  9. golang (4) golang 操作mongdb

    1. 数据按照时间聚合操作 1.1 正常的数据结构 { "_id" : ObjectId("5cac8d7b1202708adf5d4b64"), " ...

随机推荐

  1. Python虚拟机类机制之填充tp_dict(二)

    填充tp_dict 在Python虚拟机类机制之对象模型(一)这一章中,我们介绍了Python的内置类型type如果要完成到class对象的转变,有一个重要的步骤就是填充tp_dict对象,这是一个极 ...

  2. Azure继续降价云 价格战就此终结?

    [TechTarget中国原创] 刚刚跨入2016年,就听到了云降价这样一个消息,但是我们却不要期望降价之风如去年一样呼呼不绝. 微软公司在本周宣称,他们将在下个月对其D系列虚拟机实施高达17%的降价 ...

  3. Careercup - Microsoft面试题 - 24313662

    2014-05-12 07:27 题目链接 原题: Convert a number to a number 题目:把二进制数转化成四进制数. 解法:四是二的倍数,所以两位变一位就可以了. 代码: / ...

  4. 37、iamgeview 图层叠加

    1 Drawable d1 = new BitmapDrawable(circleBitmap); Drawable d2 = login.this.getResources().getDrawabl ...

  5. vmware克隆centos修改linux mac地址

    故障背景:  在vmware workstation中了完全克隆了一个已经存在的centos的虚拟机,启动之后发现网卡没有启动.于是重启一下network服务,发现提示错误信息“Device eth0 ...

  6. python-day3-之函数

    不使用函数的情况下只能遵循面向过程的编程,即,根据业务逻辑从上到下实现功能,往往重复的功能,使得代码出现重复. #最简单的函数调用 #由于python遵循从上到下读入内存的规律,所以函数要放到调用的前 ...

  7. Python学习-day14-HTML

    以下博客为转载 http://www.cnblogs.com/evilliu/p/5750539.html 一:HTML(HyperText Markup Language)介绍 超文本标记语言,标准 ...

  8. 使用jQuery ui创建模态表单

    jQuery UI 是一个建立在 jQuery JavaScript 库上的小部件和交互库,可以使用它创建高度交互的 Web 应用程序. 在web页面的开发过程中,在添加元素的时候需要用到弹出窗口添加 ...

  9. [转]Pycharm 断点调试方法

    转自: https://blog.csdn.net/u013088062/article/details/50216015

  10. MFC之HTTP文件上传

    BOOL UploadFile(LPCTSTR strURL, LPCTSTR strLocalFileName) { // 如果URL为空或者文件不存在,直接返回 if (strURL == NUL ...