Skip to content

MongoDB 连接管理

连接基础

1. MongoDB 连接机制

连接流程

  1. 客户端发起 TCP 连接到 MongoDB 服务器
  2. 服务器验证客户端身份(如果启用认证)
  3. 建立逻辑连接,分配连接 ID
  4. 客户端发送命令,服务器处理并返回结果
  5. 连接保持活动状态,等待后续命令
  6. 客户端或服务器关闭连接

连接类型

  • 短连接:每次操作建立新连接,操作完成后关闭
  • 长连接:建立一次连接,多次操作复用
  • 连接池:管理连接集合,按需分配和回收

2. 连接字符串格式

基本连接字符串

mongodb://username:password@host:port/database?options

副本集连接字符串

mongodb://username:password@host1:port1,host2:port2,host3:port3/database?replicaSet=rs0&readPreference=primary

分片集群连接字符串

mongodb://username:password@mongos1:port1,mongos2:port2,mongos3:port3/database

连接选项

选项描述示例值
replicaSet副本集名称rs0
readPreference读取偏好primary, secondary, nearest
writeConcern写入关注点{ w: 1, j: true }
readConcern读取关注点local, majority
connectTimeoutMS连接超时30000
socketTimeoutMS套接字超时30000
maxPoolSize最大连接池大小100
minPoolSize最小连接池大小10
maxIdleTimeMS连接最大空闲时间3600000
tls启用 TLStrue

连接池配置

1. 连接池原理

连接池工作流程

  1. 客户端初始化连接池,创建最小数量的连接
  2. 当需要连接时,从池中获取可用连接
  3. 使用连接执行操作
  4. 操作完成后,将连接返回池中
  5. 定期清理空闲连接
  6. 当池中连接不足时,创建新连接(不超过最大限制)

连接池优势

  • 减少连接建立和关闭的开销
  • 控制并发连接数量
  • 提高连接利用率
  • 提供连接复用机制

2. MongoDB 驱动连接池配置

Python (PyMongo)

python
from pymongo import MongoClient

client = MongoClient(
    "mongodb://localhost:27017/",
    maxPoolSize=100,
    minPoolSize=10,
    maxIdleTimeMS=3600000,
    connectTimeoutMS=30000,
    socketTimeoutMS=30000,
    serverSelectionTimeoutMS=5000
)

Node.js (MongoDB Driver)

javascript
const { MongoClient } = require('mongodb');

const uri = "mongodb://localhost:27017/";

const client = new MongoClient(uri, {
  maxPoolSize: 100,
  minPoolSize: 10,
  maxIdleTimeMS: 3600000,
  connectTimeoutMS: 30000,
  socketTimeoutMS: 30000,
  serverSelectionTimeoutMS: 5000
});

Java (MongoDB Java Driver)

java
import com.mongodb.MongoClientSettings;
import com.mongodb.client.MongoClients;

MongoClientSettings settings = MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString("mongodb://localhost:27017/"))
    .applyToConnectionPoolSettings(builder -> {
        builder.maxSize(100);
        builder.minSize(10);
        builder.maxConnectionIdleTime(3600, TimeUnit.SECONDS);
        builder.maxConnectionLifeTime(86400, TimeUnit.SECONDS);
        builder.connectTimeout(30, TimeUnit.SECONDS);
    })
    .build();

MongoClient client = MongoClients.create(settings);

3. 连接池参数调优

maxPoolSize

  • 推荐值:根据应用并发数和服务器资源调整
  • 计算公式:maxPoolSize = (CPU核心数 * 2) + 磁盘数
  • 注意:不要设置过大,避免服务器资源耗尽

minPoolSize

  • 推荐值:10-20
  • 确保有足够的连接应对突发流量
  • 避免频繁创建和销毁连接

maxIdleTimeMS

  • 推荐值:3600000(1小时)
  • 清理长时间空闲的连接
  • 避免连接资源浪费

connectTimeoutMS

  • 推荐值:30000(30秒)
  • 平衡连接速度和可靠性
  • 避免过短导致连接频繁失败

socketTimeoutMS

  • 推荐值:30000(30秒)
  • 防止长时间阻塞
  • 适合大多数操作场景

连接参数优化

1. MongoDB 服务器连接参数

maxIncomingConnections

yaml
# mongod.conf
net:
  maxIncomingConnections: 65536  # 默认65536

推荐值

  • 根据服务器资源调整
  • 考虑操作系统文件描述符限制
  • 监控连接使用情况,避免资源耗尽

2. 操作系统参数调整

文件描述符限制

bash
# 查看当前限制
ulimit -n

# 临时调整
ulimit -n 65536

# 永久调整(/etc/security/limits.conf)
mongodb soft nofile 65536
mongodb hard nofile 65536

# 系统级调整(/etc/sysctl.conf)
fs.file-max = 2097152
net.core.somaxconn = 1024

TCP 连接参数

bash
# /etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.ip_local_port_range = 1024 65000
net.core.netdev_max_backlog = 1000

3. 客户端连接参数

readPreference

  • 控制从哪个节点读取数据
  • 推荐在副本集环境中使用 secondaryPreferred
  • 减少主节点压力,提高读取性能

writeConcern

  • 控制写入确认级别
  • 根据数据一致性要求调整
  • 推荐使用 { w: 1 }{ w: "majority" }

readConcern

  • 控制读取数据的一致性级别
  • 推荐使用 localmajority
  • 平衡一致性和性能

连接监控

1. 连接状态查看

查看当前连接数

javascript
// 查看服务器连接统计
db.serverStatus().connections

// 输出示例:
// { current: 123, available: 65413, totalCreated: 45678 }

查看活动连接

javascript
// 查看当前操作
show currentOp()

// 过滤连接操作
db.currentOp({ op: "command", active: true })

// 查看连接详情
db.adminCommand({ currentOp: true, $query: { connectionId: { $ne: -1 } } })

查看连接历史

javascript
// 查看连接创建总数
db.serverStatus().connections.totalCreated

// 查看连接池统计(如果使用驱动连接池)
// 取决于驱动实现

2. 连接监控工具

MongoDB Atlas/Ops Manager

  • 提供连接数监控仪表盘
  • 支持设置连接数告警
  • 显示连接来源和分布

Prometheus + Grafana

yaml
# MongoDB 导出器配置
mongodb_global_connections_current 123
mongodb_global_connections_available 65413
mongodb_global_connections_totalCreated 45678

自定义监控脚本

bash
#!/bin/bash

# 连接监控脚本

HOST="localhost"
PORT=27017
USER="admin"
PASSWORD="password"

CONNECTIONS=$(mongo --host $HOST --port $PORT -u $USER -p $PASSWORD --authenticationDatabase admin --eval "db.serverStatus().connections" --quiet)

CURRENT=$(echo $CONNECTIONS | grep -oP 'current: \K[0-9]+')
AVAILABLE=$(echo $CONNECTIONS | grep -oP 'available: \K[0-9]+')
TOTAL=$(echo $CONNECTIONS | grep -oP 'totalCreated: \K[0-9]+')

# 输出到监控系统
echo "mongodb_connections_current $CURRENT"
echo "mongodb_connections_available $AVAILABLE"
echo "mongodb_connections_total $TOTAL"

3. 连接告警配置

MongoDB Atlas 告警

  • 设置连接数阈值告警
  • 支持邮件、短信、Webhook 通知
  • 自定义告警条件

Prometheus 告警规则

yaml
# 连接数告警
groups:
- name: mongodb-connection-alerts
  rules:
  - alert: MongoDBConnectionsHigh
    expr: mongodb_global_connections_current / mongodb_global_connections_available > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High MongoDB connections ({{ $value | humanizePercentage }})"
      description: "MongoDB has {{ $value | humanizePercentage }} of connections used"

  - alert: MongoDBConnectionsCritical
    expr: mongodb_global_connections_current / mongodb_global_connections_available > 0.95
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Critical MongoDB connections ({{ $value | humanizePercentage }})"
      description: "MongoDB has {{ $value | humanizePercentage }} of connections used. Immediate action required!"

连接问题排查

1. 连接失败问题

常见原因

  • 网络连接问题
  • 认证失败
  • 连接数达到上限
  • 服务器不可用
  • 防火墙或安全组限制

排查步骤

bash
# 测试网络连接
telnet mongodb.example.com 27017
nc -zv mongodb.example.com 27017

# 检查服务器状态
systemctl status mongod

# 查看 MongoDB 日志
tail -f /var/log/mongodb/mongod.log | grep -i "error"

# 检查连接数
db.serverStatus().connections

# 检查认证配置
mongo -u admin -p password --authenticationDatabase admin --eval "db.runCommand({ ping: 1 })"

2. 连接泄漏问题

症状

  • 连接数持续增长
  • 连接池耗尽
  • 应用响应缓慢
  • 服务器资源耗尽

排查方法

javascript
// 查看长时间运行的连接
db.currentOp({
  active: true,
  secs_running: { $gt: 60 },
  $query: { connectionId: { $ne: -1 } }
})

// 查看连接来源分布
db.adminCommand({
  currentOp: true,
  $query: { connectionId: { $ne: -1 } }
}).inprog.forEach(op => {
  print(op.client, op.appName, op.secs_running)
})

解决方案

  • 检查应用代码,确保连接正确关闭
  • 调整连接池参数,设置合理的最大连接数
  • 实现连接池监控,及时发现泄漏
  • 使用连接超时,自动回收长时间空闲的连接

3. 连接超时问题

常见原因

  • 网络延迟高
  • 服务器负载过高
  • 查询执行时间过长
  • 连接池配置不合理

解决方案

yaml
# 调整连接超时参数
connectTimeoutMS: 30000
socketTimeoutMS: 30000
serverSelectionTimeoutMS: 5000

# 优化查询性能
# 为查询添加合适的索引
# 优化查询语句
# 限制返回结果数量

# 调整服务器资源
# 增加 CPU、内存
# 优化存储配置

连接安全管理

1. 认证与授权

启用认证

yaml
# mongod.conf
security:
  authorization: enabled
  keyFile: /etc/mongodb/keyfile

创建用户

javascript
use admin
db.createUser({
  user: "appUser",
  pwd: "password",
  roles: [
    { role: "readWrite", db: "myDatabase" }
  ]
})

使用 X.509 认证

yaml
# 客户端连接字符串
mongodb:///?authMechanism=MONGODB-X509&tls=true&tlsCertificateKeyFile=client.pem&tlsCAFile=ca.pem

2. TLS/SSL 加密

启用 TLS

yaml
# mongod.conf
net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt
    allowInvalidHostnames: false
    allowInvalidCertificates: false

客户端 TLS 连接

python
client = MongoClient(
    "mongodb://localhost:27017/",
    tls=True,
    tlsCAFile="/etc/mongodb/ca.crt",
    tlsCertificateKeyFile="/etc/mongodb/client.pem"
)

3. 防火墙配置

防火墙规则

bash
# 允许特定 IP 访问 MongoDB
iptables -A INPUT -p tcp --dport 27017 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP

# 使用 firewalld
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="27017" accept'
firewall-cmd --reload

连接管理最佳实践

1. 应用层最佳实践

使用连接池

  • 所有应用必须使用连接池
  • 合理配置连接池大小
  • 复用连接,避免频繁创建和关闭

正确关闭连接

python
# 应用退出时关闭连接
client.close()

实现重试机制

python
from pymongo.errors import ConnectionFailure

max_retries = 3
retry_delay = 1

for attempt in range(max_retries):
    try:
        client = MongoClient(connectTimeoutMS=5000)
        client.admin.command('ping')
        break
    except ConnectionFailure:
        if attempt == max_retries - 1:
            raise
        time.sleep(retry_delay)
        retry_delay *= 2  # 指数退避

2. 服务器层最佳实践

合理配置连接数

  • 根据服务器资源调整 maxIncomingConnections
  • 考虑操作系统文件描述符限制
  • 监控连接使用情况,避免资源耗尽

优化网络配置

  • 启用 TCP 连接复用
  • 调整 TCP 超时参数
  • 优化网络带宽和延迟

定期维护

  • 定期重启 MongoDB 服务器(计划内维护)
  • 清理无效连接
  • 更新 MongoDB 版本,修复连接相关 bug

3. 监控与告警

实时监控

  • 监控连接数变化趋势
  • 设置连接数告警阈值
  • 分析连接来源和分布

定期审计

  • 定期检查连接日志
  • 审计连接来源 IP
  • 检查异常连接模式

容量规划

  • 根据连接增长趋势进行容量规划
  • 预测未来连接需求
  • 提前扩容服务器资源

常见问题(FAQ)

Q1: MongoDB 最大支持多少连接数?

A1: MongoDB 默认最大连接数为 65536,但实际支持的连接数受以下因素限制:

  • 操作系统文件描述符限制
  • 服务器内存大小
  • CPU 核心数
  • 磁盘 I/O 能力

Q2: 如何确定合适的连接池大小?

A2: 连接池大小应根据以下因素确定:

  • 应用并发数
  • 服务器资源(CPU、内存)
  • 操作类型(读多写少或写多读少)
  • 网络延迟

推荐公式:连接池大小 = (CPU核心数 * 2) + 磁盘数

Q3: 为什么连接数持续增长?

A3: 连接数持续增长可能是以下原因:

  • 连接泄漏:应用未正确关闭连接
  • 流量增长:业务规模扩大
  • 连接池配置不合理:最大连接数设置过大
  • 长时间运行的查询:连接被长时间占用

Q4: 如何处理连接超时?

A4: 处理连接超时的方法:

  • 优化网络连接,降低延迟
  • 调整连接超时参数
  • 实现连接重试机制
  • 优化查询性能,减少执行时间
  • 增加服务器资源,提高处理能力

Q5: 如何监控连接池使用情况?

A5: 监控连接池的方法:

  • 使用驱动内置的连接池统计功能
  • 实现自定义监控脚本
  • 使用 APM 工具(如 New Relic、Datadog)
  • 监控应用性能指标,间接反映连接池状况

Q6: 连接池耗尽会导致什么问题?

A6: 连接池耗尽会导致:

  • 应用响应缓慢或超时
  • 新请求无法获取连接
  • 服务器资源耗尽
  • 应用崩溃

Q7: 如何优化大量短连接场景?

A7: 优化短连接场景的方法:

  • 使用连接池,复用连接
  • 增加连接池最小连接数
  • 延长连接空闲超时时间
  • 考虑使用长连接替代短连接
  • 优化应用架构,减少连接创建频率

Q8: 不同驱动的连接池实现有什么区别?

A8: 不同驱动的连接池实现存在差异:

  • PyMongo:基于线程的连接池,支持自动扩展
  • Node.js Driver:基于事件循环的连接池,适合高并发场景
  • Java Driver:高度可配置的连接池,支持多种参数调整
  • .NET Driver:功能丰富的连接池,支持连接租赁和回收

建议参考各驱动文档,根据应用需求选择合适的连接池配置。