Mongos连接模型探究

经常有同学会问, client/mongos/mongod之间的连接模型是怎样的关系,一个客户端连接对应多少个对后端mongod的连接。这个问题是有意义的,因为我们知道,client到mongod之间的连接,是 one-thread-per-connection的模式的,而且每个连接线程默认分配1MB内存,一千个连接就是1GB的内存; 而且活跃连接多了,内核态的线程切换引起的性能开销又是一个让人头痛的问题。one-thread-per-connection的模型相当传统(落后),该模型将线程切换/调度交给操作系统管理,带来的结果就是:延迟不可控。不过mongos接入层的引入,较好的缓解了该问题,本文主要介绍mongos和mongod之间的连接池模型,以及调优参数项。


◆◆

连接模型

◆◆

mongos作为client和mongod之间的中间层,需要管理两方面的连接

  1. client对mongos的连接

  2. mongos对mongod分片以及每个副本集的连接

mongos对client的连接模型


client对mongos的连接采用one-thread-per-connection的模式,listener线程负责accept到新的连接,每个连接新分配一个线程来处理,线程栈大小默认为1MB。


d7964aedc75e48de0c3851852c2a1d61339ba4a0

总结,mongos对客户端的连接模型是采用one-thread-per-connection的经典方式。 另外,该方式有一个较为严重的问题:在活跃连接较多的场景下,会引起较多的线程切换,导致处理延时难以量化。


mongos对后端分片的连接模型


mongos对后端分片mongod的连接模型如下图。 mongos采用ASIO网络框架,每个用户请求通过网络实践回调/异步状态机的Reactor模型驱动。ReactorPool被划分为N个ReactWorker,每个Worker对等的处理用户请求。每个Worker中有M个连接池(M=后端所有mongod的个数)。如果后端有3分片,每个分片3副本,则每个Worker中管理9个连接池。

76a7a6ce0563885c0f3c78fc3f061bf751e950bb

用户请求被RoundRobin到ReactWorker中,如下代码所示:

70751b3932fee3a08f9036f73c1c7c1185c770ac
◆◆

mongos连接池可调优参数

◆◆

mongos连接池可调优参数主要在 src/mongo/executor/connectionpool.h 和 src/mongo/executor/connectionpool.cpp 中。默认值为


21d2b629dcbfec4c20355c8a08e2f930df42fd65

连接池的细分


上面我们说过,mongos有一个ASIO的ReactorPool,每个Pool有有若干个连接池,每个连接池负责管理某个特定的mongod的连接。 每个连接池又分为 1. readyPool (管理空闲连接) 2. processingPool (管理在创建中/定期检查健康状态的连接) 3. checkoutPool (管理正在使用中的连接)

对于一个特定的连接,它在三个池中的状态转移关系如下图。


e8b8f5fc2691c44b5ae89f19b8b124bb7fc25467
  1. minConnections 为默认为1,表示每个worker默认对每个mongod初始连接是1,且如果readyPool中连接过多,最终会将readyPool连接个数收敛到1

  2. maxConnections 默认没做限制,表示每个worker不限制对后端mongod的连接个数

  3. refreshTimeout 和 refreshRequirement, 每个连接有最长IdleTime,大小为refreshRequirement,默认为5分钟,超过这个值,如果当前连接个数大于minConnections,就会丢弃该连接,否则对该连接进行heartBeat后重新放回readyPool。refreshTimeout参数不重要,表示与mongod进行heartBeat的超时时间。


相关代码如下所示:


6f99883a7d409b4ad788ecb39a90fa7e9cd8166f

hostTimeout 如果该连接池长时间没有处理任何请求,就将该连接池全部释放掉。


2e215244b8607600a10cd3380ab2b36d2a239d7b

ASIO ReactorWorkerPool大小


mongodb 提供taskExecutorPoolSize参数挑中mongos的ReactorPool的大小。用户可以通过setParameter参数,在mongos的配置文件中指定。该参数默认没有指定,因此mongos默认的workerPool大小为cpu核心个数(cat /proc/cpuinfo)。


1e2db8af3c4fb6d376fb6cfe33297b894852f23a

有价值的调优项


1. minConnection和 refreshRequirement


minConnection值默认为1, 举个例子,如果在一个8核机器上默认配置部署mongos,则mongos对后端每个mongod有1X8=8个连接,如果是3副本,2分片,则总用有1X8X3X2=48个连接。如果有流量峰值,或后端mongod处理不过来,则会创建新的连接,峰值过去后,多余的连接会在refreshRequrement指定的时间后释放。 如果对业务平均响应和平均峰值间隔有个合理的预估,就可以有把握的调整这两个值的大小。 举个例子,如果两分片,平均写入响应时间在10ms,写入TPS要求为1000。峰值间隔为5分钟。则minConnection最好设置大于 1000/2(两副本)/100(10ms)=5,从而防止冷启动带来的延迟开销。refreshRequirement = 5X2 = 10分钟,idle回收时间大于业务峰值间隔。从而避免峰值时创建新的连接。


2. maxConnection


这个值默认没有做限制,这样非常容易使mongos对mongod造成connection-flood。如果mongod请求处理超过客户端超时。客户端对mongos发起重试,mongos对mongod的请求还在checkoutPool中没有回收,readyPool中不够分配,只能创建新连接处理客户端的重试,重试依然超时,如此往复导致对mongod的连接数暴增。 这个值建议通过最大QPS/TPS来估算。以写为例: maxConnection = maxTPS / nShards / nMongos / taskExecutorPoolSize


3. taskExecutorPoolSize 与mongos部署模式

mongos默认不适合单机多部署,因为asioWorker的个数等于CPU核心个数。如果单机多部署,则需要考虑线程切换带来的影响。比较合理的mongos单机部署多方式是使用cgroups或taskset将mongos binding到对应的核上。并且binding的核心个数 = taskExecutorPooSize


原文发布时间为: 2018-11-22
本文作者:Mongoing中文社区
本文来自云栖社区合作伙伴“Mongoing中文社区”,了解相关信息可以关注“Mongoing中文社区”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值