golang:mgo剖析之Session
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的更多相关文章
- golang mgo的mongo连接池设置:必须手动加上maxPoolSize
本司礼物系统使用了golang的 mongo库 mgo,中间踩了一些坑,总结下避免大家再踩坑 golang的mgo库说明里是说明了开启连接复用的,但观察实验发现,这并没有根本实现连接的控制,连接复用仅 ...
- golang 性能剖析pprof
作为一个golang coder,使用golang编写代码是基本的要求. 能够写出代码,并能够熟悉程序执行过程中各方面的性能指标,则是更上一层楼. 如果在程序出现性能问题的时候,可以快速定位和解决问题 ...
- golang context 剖析 1.7.4 版本
1. 内部结构之 - timerCtx . type timerCtx struct { cancelCtx timer *time.Timer // Under cancelCtx.mu. dead ...
- Golang mgo 模糊查询的使用
在日常使用的Mongodb中,有一项功能叫做模糊查询(使用正则匹配),例如: db.article.find({"title": {$regex: /a/, $options: & ...
- golang学习之mgo操作mongodb
mgo是mongodb的golang驱动,测试代码: // mgotest project main.go package main import ( "fmt" "ti ...
- mgo中DBRef-数据添加测试
2014-1-25 在设计mongo数据库时遇到这样一个问题,日志信息表需要引用人员信息表的数据.如果是结构化数据库,基本上不用想太多的东西.由于刚接触非结构化数据库,按着书上的理解由于日志数量较多, ...
- session机制详解以及session的相关应用
session是web开发里一个重要的概念,在大多数web应用里session都是被当做现成的东西,拿来就直接用,但是一些复杂的web应用里能拿来用的session已经满足不了实际的需求,当碰到这样的 ...
- mgo中DBRef-数据查询测试
下午对数据查询进行了代码测试: package main import ( "crypto/rand" "encoding/hex" "fmt&quo ...
- golang (4) golang 操作mongdb
1. 数据按照时间聚合操作 1.1 正常的数据结构 { "_id" : ObjectId("5cac8d7b1202708adf5d4b64"), " ...
随机推荐
- vim的常用操作
vim的几种编辑模式 正常模式:可以使用快捷键命令,或按:输入命令行. 插入模式:可以输入文本,在正常模式下,按i.a.o等都可以进入插入模式. 可视模式:正常模式下按v可以进入可视模式, 在可视 ...
- Java装箱和拆箱
https://www.cnblogs.com/dolphin0520/p/3780005.html http://mxdxm.iteye.com/blog/2028196 装箱过程是通过调用包装器的 ...
- 66、fastJson 解析json数据时,如果key值不同怎么处理?
在某些场景,你可能需要定制序列化输出,比如说,希望序列化采用之后采用"ID",而不是"id",你可以使用@JSONField这个Annotation. publ ...
- 强命名实用程序(SN.exe)
不要在普通的命令行窗口中编译,请先打开C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Visual Studio 2010 ...
- 使用shell脚本生成数据库markdown文档
学习shell脚本编程的一次实践,通过shell脚本生成数据库的markdown文档,代码如下: HOST=xxxxxx PORT=xxxx USER="xxxxx" PASSWO ...
- SSM框架 springMVC对静态资源访问的处理
https://my.oschina.net/hnqingping1255/blog/415575 错误信息 [org.springframework.web.servlet.PageNotFound ...
- cookie和session机制区别
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...
- CSS查缺补漏篇
前面的话:关于CSS,之前我已经做过一些基础的知识点介绍.CSS主要是用来给页面设置样式的,一般说来,在一个网站中,CSS应该独立封装在一个单独的.css外部文件中.样式的设置总体来说是不难的,但是需 ...
- python基础-集合小结
Python-基础-集合小结 集合 简介 声明 常用操作 成员关系 新增删除 集合间操作 其他 补充 集合 简介 python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和 ...
- 【bzoj3944/bzoj4805】Sum/欧拉函数求和 杜教筛
bzoj3944 题目描述 输入 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 输出 一共T行,每行两个用空格分隔的数ans1,ans2 样例输 ...