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"), " ...
随机推荐
- 03015_JSTL技术
1.JSTL概述 (1)JSP(JSP Standard Tap Library),JSP标准标签库,可以嵌入在jsp页面中使用标签的形式完成业务逻辑等功能.jstl出现的目的同el一样也是要替代js ...
- 6、CSS基础 part-4
1.CSS 定位属性 CSS 定位属性允许你对元素进行定位. 属性 描述 position 把元素放置到一个静态的.相对的.绝对的.或固定的位置中. top 定义了一个定位元素的上外边距边界与其包含块 ...
- 带线表格据gt生成无线表格
json解析练习,python图像处理练习,表格包围框毛刺问题待解决. # -*- coding: utf-8 -*- # coding: utf-8 from PIL import Image, I ...
- Java学习之字符串类
String在Java中是一个类类型(非主类型),是一个不可被继承的final类,而且字符串对象是一个不可变对象.声明的String对象应该被分配到堆中,声明的变量名应该持有的是String对象的引用 ...
- 深入学习之mysql(三)单表操作
1.创建表的结构和数据 CREATE TABLE `t_student`( `id` INT PRIMARY KEY, `stuName` VARCHAR(10) NOT NULL, `age` IN ...
- SQL SERVER存储引擎——04.数据
4. SQL SERVER存储引擎之数据篇 (4.1)文件 (0)主数据文件.mdf初始文件大小至少为3MB,次要数据文件.ndf初始大小,同日志文件一样至少为512KB: (1)SQL SERVER ...
- algorithm 头文件
非修改性序列操作(12个) 循环 对序列中的每个元素执行某操作 for_each() 查找 在序列中找出某个值的第一次出现的位置 find() 在序列中找出符合某谓词的第一个元素 find_if() ...
- quagga源码学习--BGP协议的初始化
quagga支持BGP-4,BGP-4+协议,支持多协议(mpls,isis,ospf等等)以及单播,组播路由的导入和分发. 具体的协议,这里就不附录了,网络上有很多资料,或者RFC. 协议源码的学习 ...
- 无序字母对 character
无序字母对 character 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入 ...
- 简单的实现web聊天界面,一对一
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...