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. imageX

    imageX 编辑 ImageX 是一个命令行工具,原始设备制造商 (OEM) 和公司可以使用它来捕获.修改和应用基于文件的磁盘映像以进行快速部署.ImageX 可以使用 Windows 映像 (.w ...

  2. LeetCode with Python -> Dynamic Programming

    198. House Robber You are a professional robber planning to rob houses along a street. Each house ha ...

  3. [python][django学习篇][11]后台admin用户登录博客,添加文章---这一章和博客首页设计没有关系

    1 如果没有创建超级管理员账号,先要创建python manage.py createsuperuser 2 在admin后台注册模型(如果没有这一步,登录http://127.0.0.1:8000/ ...

  4. Spring整合hibernate -hibernateTemplate

    目录 1 在Spring中初始化hibernateTemplate并注入Sessionfactory 2 DAO里注入hibernateTemplate 3 getHibernateTemplate. ...

  5. Mysql,phpmyadmin密码忘了怎么办

    1.关闭mysql服务 # service mysql stop 如果提示mysql: unrecognized service这样的错误提示. 先查看查找mysql.server,使用:find / ...

  6. Linux常用命令与基本概念

    复制 文件的复制 cp 源文件 目标文件 文件夹的复制 cp -r 源文件夹 目标文件夹 删除 删除文件 rm 文件名 删除文件夹 rm -rf 文件夹 查看文件类型 file 文件名 压缩与解压 z ...

  7. BZOJ 2243:染色(树链剖分+区间合并线段树)

    [SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认 ...

  8. 【bzoj3771】Triple FFT+容斥原理

    题目描述 樵夫的每一把斧头都有一个价值,不同斧头的价值不同.总损失就是丢掉的斧头价值和. 他想对于每个可能的总损失,计算有几种可能的方案. 注意:如果水神拿走了两把斧头a和b,(a,b)和(b,a)视 ...

  9. 【Luogu】P4172水管局长(LCT)

    题目链接 有个结论是x到y的路径上最长边权值等于最小生成树上最长边权值,于是问题转化为最小生成树. 再考虑把问题反过来,删边变成加边. 于是变成动态维护最小生成树,LCT可以做到. #include& ...

  10. Java接口对Hadoop集群的操作

    Java接口对Hadoop集群的操作 首先要有一个配置好的Hadoop集群 这里是我在SSM框架搭建的项目的测试类中实现的 一.windows下配置环境变量 下载文件并解压到C盘或者其他目录. 链接: ...