MongoS连接池问题学习笔记
01
客户端到MongoS的连接
在默认情况下,mongos对客户端的连接都是每个连接对应一个线程,每个线程1M的内存,所以连接数增多,对于MongoS的内存消耗还是很大的。
连接的创建和销毁是比较耗费资源的,为了较少这种消耗,在MongoDB3.6版本引入了adaptive线程池。默认情况下不开启,它有如下特点:
0、adaptive线程池中的线程会同时处理多个连接的IO请求。开启它之后,每个连接将不在对应一个线程。
1、默认情况下,MongoDB的adaptive线程池会为我们创建CPU个数/2个线程;
2、在线程池内部,有一个"线程池使用阈值",当我们对于线程池内部的线程使用值小于这个阈值时,线程池会自动销毁部分线程。
3、MongoDB3.6的线程池默认是不开启的,需要我们指定参数serviceExecuter来开启,如下:
net: serviceExecutor: adaptive
4、可以通过 mongo shell 执行db.serverStatus().network.serviceExecutorTaskStats查看线程池的使用情况
02
MongoS的连接池
MongoS内部两种类型的连接池,传统的连接池和ASIO连接池。
传统连接池:DBConnectionPool
大部分的command都是使用传统的连接池的,它的应用范围比较广泛。另外,mongos对于集群所有的shard和config,都会周期性的执行一个isMaster指令,并以此更新分片的主从信息,这个指令指定的过程,也是通过传统连接池实现的。
传统连接池内的连接执行命令不会创建新的线程,是在 mongos 接收的连接创建的线程上执行的,所以不会消耗额外的内存空间。
ASIO连接池:ConnectionPool
ASIO连接池设置了连接池的最大连接,最小连接,刷新时间,超时时间等限制。建立新的连接时,当前的连接数既要满足最小连接数和最大连接数的限制,同时也要满足最大连接数等硬性要求。
我们可以通过connPoolStats 与 shardConnPoolStats 命令查看mongos/mongod内部连接池的状态:
mongos> db.runCommand({shardConnPoolStats:1}) { "totalInUse" : 0, "totalAvailable" : 0, "totalCreated" : 0, "totalRefreshing" : 0, "pools" : { }, "hosts" : { }, "threads" : [ { "hosts" : [ ], "seenNS" : [ ] } ], "ok" : 1, "operationTime" : Timestamp(1615822847, 1), "$clusterTime" : { "clusterTime" : Timestamp(1615822847, 1), "signature" : { "hash" : BinData(0,"4niRErK1XnD93zgXSyG5XD5P+is="), "keyId" : NumberLong("6894922308364795935") } } }
4个重要的参数需要关注,如下:
"inUse" : 0 //正在使用的连接数 "available" : 0 //可用的连接数 "created" : 0 //历史创建过的连接数,包含已经回收的 "refreshing" : 0 // refresh 状态的连接数
通过 ASIO 连接池的连接执行的命令,每次会创建一个线程执行的,默认的栈空间大小是 8 M 。所以ASIO 连接池内 mongos 到 mongod 的连接消耗的最小内存是8M 。
MongoS一般情况下混用这俩,对于CRUD等基本操作,3.2版本和3.4版本通过ASIO连接池执行,3.6版本及以上,全部读写操作都使用ASIO连接池执行。
03
版本间的差异
3.2 / 3.4 版本传统连接池的连接回收策略不是很完善,大量的空闲连接不能及时回收,所以偶尔重启 mongos来回收连接还是很有必要的。
3.2 / 3.4 版本传统连接池不能限制同时到每个 host 的连接;3.6 及以上版本可以通过 connPoolMaxShardedInUseConnsPerHost 和connPoolMaxInUseConnsPerHost 控制到每个 host 的连接数。
客户端到mongos和mongos到mongod的连接数是什么关系?
在3.2和3.4版本,如果客户端到mongos的连接数很多,而且每个连接都执行常见的CRUD操作,那么客户端到mongos的连接数比较少,而mongos到mongod的连接数比较多,二者比值小于1:1;如果客户端只是持有连接而不做任何操作,那么结果相反;
3.6 及以上的版本,连接池的使用与回收策略都比较完善,并且查询、更新、删除、插入等操作都是通过ASIO 连接池执行的。所以如果 mongos 进来的连接都很繁忙,进来的连接和出去的连接基本保持 1:1 的关系,而且从mongos到mongod的连接消耗的内存比较多;当然如果进来连接不执行任何操作,那么 mongos 不会创建到 mongod 的连接,此时 mongos 进来的连接和出去的连接是大于 1:1 的。