资讯专栏INFORMATION COLUMN

mongo连接分析

yuanxin / 1721人阅读

摘要:本文旨在梳理这些问题,进行一个全面的分析。等到进行数据库操作的时候,再去中获取一个连接,进行操作总结通过以上分析,对于以下的数据库连接池与关系型数据库连接池并无区别。

摘要

在前面的文章中有分析过关系型数据库的连接,以及连接池的原理。在mongo数据库同样存在,经常看到有网友在问mongo 连接了数据库要不要关,怎么关。内置的数据库连接池是单线程还是多线程,mongo服务器为什么会杀游标,杀连接诸如此类的问题,其实这类问题基本上就是连接池的问题,而很多和关系型数据库是类似的,并不是mongo独有的。
本文旨在梳理这些问题,进行一个全面的分析。

Client 连接分析

客户端连接通过driver jar去连接,以java为例,通过mongo-java-driver
连接mongo,这一点和关系型数据库一样,不同的是关系型数据库有一套标准的阻塞型的,写入JDK的数据库操作实现,即JDBC。而mongo则是完全有driver提供。在mongo-java-driver 3.0版本之前只提供了同步的driver操作,3.x之后开始提供异步的driver操作,这边不做扩散,后续会有相关博文介绍异步的数据库操作,本文只介绍同步driver操作。

数据库操作
一个基于mongo-java-driver-2.14.x的mongo操作流程

public static void main(final String[] args) {
        try {
            final String host = "localhost";
            // 连接配置属性
            final MongoClientOptions clientOptions = new MongoClientOptions.Builder()
                    .writeConcern(WriteConcern.ACKNOWLEDGED)
                    .readPreference(ReadPreference.secondaryPreferred())
                    .connectionsPerHost(10).socketTimeout(5000).build();
            final List credentialsList = new ArrayList();
            final String str = "test";
            final char[] psd = str.toCharArray();
            final MongoCredential credential = MongoCredential.createCredential("test",
                    "test",
                    psd);
            credentialsList.add(credential);
            final ServerAddress address = new ServerAddress(host, 27017);
            //包含了一个内置的数据库连接池
            final MongoClient client = new MongoClient(address, credentialsList, clientOptions);
            final DB db = client.getDB("test");
            final DBCollection postCollection = db.getCollection("test");
            postCollection.findOne();
            //连接关闭,释放资源
            client.close();
        } catch (final UnknownHostException e) {
            e.printStackTrace();
        }
    }

这只是一个sample 实际应用中,MongoClient在一个jvm中只应该有一个实例,由他管理连接,进行数据库操作。
client与数据库的交互,mongo 协议也是基于TCP的

几个重要的类

MongoClientOptions: 数据库连接配置项

DB: database连接

DBCollection: collection操作

所以mongo连接的配置核心就在于MongolientOptions类了。比较重要的配置就是
connectionsPerHost,对于线上环境,如果连接数据库的应用比较多,这个连接数不宜过大
socketTimeout: 数据库操作超时时间,一般5s中,对于慢操作,不应该一直占用连接,会损害应用性能,阻塞其他操作

private int minConnectionsPerHost;  //每个节点的最小连接数
    private int connectionsPerHost = 100; // 每个节点的连接数
    private int threadsAllowedToBlockForConnectionMultiplier = 5; //最大等待线程
    private int maxWaitTime = 1000 * 60 * 2; // 获取连接最大等待时间
    private int maxConnectionIdleTime; // 连接池最大空闲时间
    private int maxConnectionLifeTime;
    private int connectTimeout = 1000 * 10; // 连接最大时间
    private int socketTimeout = 0; // 操作最大时间
    private boolean socketKeepAlive = false;
    private boolean autoConnectRetry = false;
    private long maxAutoConnectRetryTime = 0;
    // 心跳检测,保持TCP连接
     private int heartbeatFrequency = Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalMS", "5000"));
    private int minHeartbeatFrequency = Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalNoMasterMS", "500"));
    private int heartbeatConnectTimeout = Integer.parseInt(System.getProperty("com.mongodb.updaterConnectTimeoutMS", "20000"));
    private int heartbeatSocketTimeout = Integer.parseInt(System.getProperty("com.mongodb.updaterSocketTimeoutMS", "20000"));

可以和关系型数据库连接池的实现对比一下

initialSize:初始连接数
maxActive: 最大连接数量
minIdle: 最小连接数量
maxWait: 获取连接最大等待时间ms
minEvictableIdleTimeMillis:连接保持空闲而不被驱逐的最小时间
timeBetweenEvictionRunsMillis:销毁线程的时间检测
testOnBorrow:申请连接时执行,比较影响性能
validationQuery:testOnBorrow为true检测是否是有效连接sql
testWhileIdle:申请连接的时候检测

mongo 内置的连接池管理比较简单,没有进行连接池的连接有效管理,通过heartbeat间隔一段时间发送数据包给mongo 服务器,确保连接有效,这一点和之前介绍的有点区别,之前的销毁掉无用的连接。这样会增加额外的网络和CPU负担。

看下mongo 创建MongoClient的时候会去初始化连接池。等到进行数据库操作的时候,再去PooledConnectionProvider中获取一个连接,进行操作

总结

通过以上分析,对于mongo driver 3.x 以下的mongo数据库连接池与关系型数据库连接池并无区别。只是连接池的实现方式不一样,比如一个用锁,一个用信号量。容器的选型也不太一样,但是这些并不会影响到大部分的应用开发者对于连接的配置和理解。回到开头提出的几个问题,看到这里自然就有答案了。而对于服务器kill掉游标这个问题,游标本身也不是mongo独有的,客户端通过游标控制结果数量的读取,游标本身也是占用不少资源的,所以不能一直占有,服务器kill掉游标,所以游标占用时间太长。可以通过db.serverStatus().metrics.cursor去查看timeout的游标,找出耗时操作,进行优化。

"cursor": {
"timedOut": "NumberLong(99)"
"open": {
"noTimeout": "NumberLong(0)"
"pinned": "NumberLong(3)"
"total": "NumberLong(3)"
}
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19259.html

相关文章

  • MongoDB 资源、库、工具、应用程序精选列表中文版

    摘要:推荐阅读资源库工具应用程序精选列表中文版有哪些鲜为人知,但是很有意思的网站一份攻城狮笔记每天搜集上优秀的项目一些有趣的民间故事超好用的谷歌浏览器油猴插件合集目录资源文档文章图书会谈教程更多库工具管理数据部署桌面发展监控应用资源文档介绍文档教 推荐阅读 MongoDB 资源、库、工具、应用程序精选列表中文版 有哪些鲜为人知,但是很有意思的网站? 一份攻城狮笔记 每天搜集 Github ...

    e10101 评论0 收藏0
  • 记录一次并发读取MongoDB的踩坑过程

    摘要:出现的问题笔者前段时间开发一个新项目的某个功能模块要读取老游戏中某个数据库计作库连续读库中的个集合相当于的张表取数据在测试环境单次操作时是内但是并发测试情况下比如内个并发时读取库个集合的耗时能达到以上甚至且个并发请求几乎同时完成但是在我本地 出现的问题 笔者前段时间开发一个新项目的某个功能模块,要读取老游戏中某个Mongo数据库(计作A库),连续读A库中的6个集合(相当于MySQL的6...

    luffyZh 评论0 收藏0
  • Express使用mongodb管理会话储存 connect-mongo模块简介

    摘要:简介在我的前一篇小文中小书提到了可以更换会话储存那么这篇文章我们就来讲讲在进行会话管理的时候如何将会话数据保存在外部数据库中本文中我们使用用作会话储存数据库本文中使用的模块以及版本号一览模块名称版本号特性支持支持所有版本的支持支持 简介 在我的前一篇小文中express-session小书提到了express-session可以更换会话储存. 那么这篇文章我们就来讲讲express在进...

    jackzou 评论0 收藏0
  • Express使用mongodb管理会话储存 connect-mongo模块简介

    摘要:简介在我的前一篇小文中小书提到了可以更换会话储存那么这篇文章我们就来讲讲在进行会话管理的时候如何将会话数据保存在外部数据库中本文中我们使用用作会话储存数据库本文中使用的模块以及版本号一览模块名称版本号特性支持支持所有版本的支持支持 简介 在我的前一篇小文中express-session小书提到了express-session可以更换会话储存. 那么这篇文章我们就来讲讲express在进...

    zhangxiangliang 评论0 收藏0

发表评论

0条评论

yuanxin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<