参数调优建议

对于云数据库 MongoDB 版实例,您可以通过控制台修改参数。对于某些重要参数而言,不恰当的参数值会导致实例性能问题或应用报错,所以本文介绍一些重要参数的优化建议以减少您在设置参数时的疑虑。

说明

本文仅包含内核参数,客户端驱动侧的参数(比如socketTimeout等)并不包含在内。

副本集

operationProfiling.mode

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值off

  • 作用:指定查询分析器的级别。

  • 现象

    • 如果设置为all或者slowOp且慢日志比较多时,可能会出现实例性能退化而引起困惑。

    • 部分客户也会因为忘了关闭查询分析器而对自己的某个库里出现system.profile集合而感到困惑。

    • 部分客户也会误解以为需要将此参数设置为slowOp才会产生慢日志。

  • 修改建议

    维持默认值。不仅仅由于开启查询分析器会带来一定的实例性能退化,而且慢日志一般也能提供类似的分析信息。请在必要的时候才考虑开启,并且在开启且分析完毕后及时关闭。更多关于查询分析器(Database Profiler)的信息,请参见官方文档

operationProfiling.slowOpThresholdMs

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值100

  • 作用:定义一个查询是否为慢查询的阈值。

  • 现象

    • 参数设置过小,将导致产生大量慢日志和审计日志,带来慢日志噪音影响慢查询分析。

    • 参数设置过大,将导致很多慢查询并不输出在日志中,影响慢查询分析过程。

  • 修改建议:根据业务的实际情况适当调小或调大阈值,推荐设置为比业务核心查询的平均耗时稍大些的值。示例如下:

    • 假设一个对查询延时比较敏感的业务,日常的查询耗时都仅在30ms左右,为了协助分析一些瞬时抖动的慢查询情况,可以将此参数调小到50。

    • 假设一个分析查询比较重的业务,日常查询耗时都在300~400ms左右,为了减少慢日志噪音,可以将此参数调大到500。

replication.oplogGlobalIdEnabled

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:是

  • 默认值false

  • 作用:是否开启oplogGID来支持DTSmongoShake的双向同步,该参数为自研参数。GID的目的是为了解决双向同步中的环形同步问题。

  • 修改建议:只在需要进行双向同步时开启。该参数需要重启实例生效,应尽量在业务低峰期变更。

replication.oplogSizeMB

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值规格的磁盘空间的10%(比如实例的磁盘大小是500GB,则初始oplogSizeMB就是51200,即50GB)

  • 作用:指定用于保存逻辑同步日志的oplog表的最大值(逻辑大小)。

  • 现象:参数设置过小,可能会导致从节点跟不上而进入异常的RECOVERING状态;也有可能导致日志备份来不及覆盖所有oplog记录而出现空洞,进而无法进行按时间点恢复。

  • 修改建议:维持默认值,不要调小,需要时调大。如遇以下场景可适当调大该值:业务的workload属于数据量不大但更新很多的情况,oplog产生速度比较快。此时适当调大oplogSizeMB可以使得oplog表能够覆盖更长时间的oplog记录,避免出现oplog记录空洞的问题。最佳实践为设置的oplogSize至少应可以保留1小时以上的oplog记录。

说明

该参数的修改并不是通过变更配置文件里的此参数来生效的,阿里云侧管控会通过专门的replsetResizeOplog命令来调整oplog大小。

setParameter.cursorTimeoutMillis

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值600000(10min)

  • 作用:空闲游标的到期阈值,单位为毫秒。如果游标的空闲时间超过该阈值,则MongoDB会自动清理该游标。

  • 现象:如果尝试访问一个已经被清理的过期游标,客户端侧会收到以下格式的报错:

    Message: "cursor id xxxxxxx not found"
    ErrorCode: CursorNotFound(43)
  • 修改建议:不建议调大,为了降低空闲游标的资源开销,可以适当调小(比如300000)。无论何种场景,业务侧都应尽量避免出现长时间空闲游标的情况。

setParameter.flowControlTargetLagSeconds

  • 适用大版本:大于等于4.2

  • 修改完是否需要重启:否

  • 默认值10

  • 作用flowControl机制触发的阈值,flowControl的目的是为了确保大多数提交点不会落后太多。

  • 现象:出现类似下面的慢日志(durationMillis基本等价于flowControl.timeAcquiringMicros,说明请求慢主要是受到flowControl影响),且请求明显受到影响,耗时大幅增加。

    {
      "t": {
        "$date": "2024-04-25T13:28:45.840+08:00"
      },
      "s": "I",
      "c": "WRITE",
      "id": 51803,
      "ctx": "conn199253",
      "msg": "Slow query",
      "attr": {
        "type": "update",
        "ns": "xxx.xxxxx",
        "command": ...,
        "planSummary": "IDHACK",
        "totalOplogSlotDurationMicros": 61,
        "keysExamined": 1,
        "docsExamined": 1,
        "nMatched": 1,
        "nModified": 1,
        "nUpserted": 0,
        "keysInserted": 0,
        "keysDeleted": 0,
        "numYields": 0,
        "locks": ...,
        "flowControl": {
          "acquireCount": 1,
          "acquireWaitCount": 1,
          "timeAcquiringMicros": 959000
        },
        "readConcern": {
          "level": "local",
          "provenance": "implicitDefault"
        },
        "storage": {},
        "cpuNanos": 258845,
        "remote": "172.16.6.38:52368",
        "durationMillis": 959
      }
    }
    
  • 修改建议:可以适当调大该参数,以此来降低flowControl机制介入的敏感度。如果调大后还是会出现请求经常被限流的情况,则说明实例在主从同步方面存在一定的性能瓶颈,需要进一步分析并采取其他方式来解决,比如升级实例配置或者将writeConcern设置为majority。

setParameter.oplogFetcherUsesExhaust

  • 适用大版本:大于等于4.4

  • 修改完是否需要重启:是

  • 默认值true

  • 作用:是否开启流式复制(Stream Replication)。如果关闭此功能的话,主从同步将回退到与之前版本一致的拉取方式。即从节点给同步源发获取一批oplog的请求,然后等待回复,这意味着每批oplog都需要一次网络往返的交互。

  • 现象:部分场景下,流式复制机制可能会带来额外的性能开销和网络带宽开销。

  • 修改建议:不建议调整。流式复制可以在高负载和高延迟的网络环境中减轻复制延迟,还可以降低writeConcern{w:1}primary节点异常宕机时的写入丢失风险,也可以降低其他依赖主从复制的writeConcern(比如{w:majority}{w:>1})下的写入延迟。

setParameter.maxTransactionLockRequestTimeoutMillis

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:否

  • 默认值5

  • 作用:指定事务加锁的超时时间,单位为毫秒。如果事务里的操作无法在给定的时间内获取到需要的锁,则事务会自动abort。

  • 现象:在日志中或者客户端中遇到如下的锁获取超时报错信息。(高版本驱动对于这种TransientTransactionError会自动重试,因此可能只在日志中出现,客户端侧无法感知)

    Message: "Unable to acquire lock '{8442595743001781021: Database, 1525066715360699165}' within a max lock request timeout of '5ms' milliseconds."
    ErrorCode: LockTimeout(24)
  • 修改建议:如果客户端侧经常遇到类似的报错,可以尝试将此参数调大,能适当缓解瞬时并发锁获取不到而导致的事务中止,但相应地也会使得死锁事务操作的中止延后。如果参数调大后问题依然出现,则不建议进一步调大参数,而是需要考虑从业务逻辑上进行优化,比如避免事务内对相同文档的并发修改,以及重新审视事务里的操作,检查事务中是否包含了可能会长时间占用锁的操作(比如DDL、待优化的查询),从源头上避免类似问题发生。

setParameter.replWriterThreadCount

  • 适用大版本:大于等于3.2

  • 修改完是否需要重启:是

  • 默认值16

  • 作用:指定主从同步中并行复制的最大线程数,实际生效的最大线程数为实例规格CPU核数的2倍。

  • 现象:极端场景下可能出现主从同步不及时而从节点产生延迟(lag)不断增大的情况。

  • 修改建议:一般情况不建议调整。特殊情况推荐在阿里云研发工程师的建议下来进行调整。

setParameter.tcmallocAggressiveMemoryDecommit

  • 适用大版本:大于等于4.2

  • 修改完是否需要重启:否

  • 默认值0(代表关闭TCMalloc激进回收)

  • 作用:MongoDB内部使用了TCMalloc作为内存分配器,此参数用于控制是否开启TCMalloc的激进回收策略。开启后,MongoDB会主动尝试合并相邻的空闲内存块并归还一部分内存给操作系统。

  • 现象

    • 因为查询请求消耗过大,内存来不及回收而出现mongod节点OOM的情况。

    • 随着不断使用,堆内存碎片空间越来越多,表现上为内存使用率超过80%且稳定缓慢上升。

  • 修改建议:一般情况不建议调整。有内存相关问题时可以考虑在业务低峰期时调整。

重要

开启此参数可能会带来一定的性能退化,具体情况取决于您的工作负载。建议您只在业务低峰期时尝试开启此参数,且调整完持续观察业务一段时间,如果有受影响的情况应及时回滚参数调整。

setParameter.transactionLifetimeLimitSeconds

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:否

  • 默认值60

  • 作用:指定事务的生命周期,单位为秒。如果事务的整体执行时间超过了此限制,会被标记为过期并被后台的周期性清理线程主动处理并abort掉。

  • 现象:客户端侧遇到格式如下的报错:

    Message: "Aborting transaction with txnNumber xxx on session with lsid xxxxxxxxxx because it has been running for longer than 'transactionLifetimeLimitSeconds'"
  • 修改建议:可以适当调小(比如到30),不建议调大。未提交的长事务可能会给WiredTiger存储引擎的缓存带来很大压力,一旦缓存压力超载通常会带来更多问题,包括数据库卡顿、请求延迟大幅增加、CPU使用率满等,导致业务受损。无论如何,业务侧都应该尽量避免长事务的出现。为了解决超时问题,您应该将事务分解为更小的部分,以便在配置的时间限制内可以执行完成。您还需要确保已经优化过查询语句,查询语句具有适当的索引覆盖率,以便在事务中快速地访问数据。

关于事务使用的最佳实践,请参见事务与Read/Write Concern

storage.oplogMinRetentionHours

  • 适用大版本:大于等于4.4

  • 修改完是否需要重启:否

  • 默认值0(代表此参数不生效,oplog大小完全由前面提到的replication.oplogSizeMB参数控制)

  • 作用:指定用于保存逻辑同步日志的oplog表的最小保留时间。

  • 现象

    • 参数设置过大,导致oplog表占据过多磁盘空间。

    • 部分用户忘记曾经设置过此参数,疑惑实例的磁盘空间大小波动原因。

  • 修改建议:对于相对稳定的workload,维持默认值。对于可能会发生大幅度写入操作变化的workload,建议将此参数配置为>1.0的浮点数。设置此参数时也需要评估可能的空间占用,避免触发磁盘满锁引发其他问题。

storage.wiredTiger.collectionConfig.blockCompressor

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:是

  • 默认值snappy

  • 作用:设置集合数据的存储压缩算法(修改后仅对所有的新建的表生效,已存在的表不受影响)。目前支持设置为不压缩或者snappyzlibzstd压缩算法(4.2及以上的版本才支持zstd)。

  • 修改建议:按需修改。不同的压缩算法有着不同的表现,有的压缩率更高但压缩和解压时的CPU开销更大。实际压缩算法之间的对比,应以您实际测试的结果为准。如果实例主要用来存储冷数据,那么为了获得更高的压缩比,可以考虑将此参数修改为zstd

    说明

    如果您想针对不同的表使用不同的压缩算法,需要使用带相关选项的显式createCollection命令,更多介绍,请参见MongoDB官方文档

分片集群(Shard)

setParameter.migrateCloneInsertionBatchSize

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:否

  • 默认值0(代表受16MB文档大小限制)

  • 作用:指定chunk迁移时克隆步骤中单个批次的最大文档数量。

  • 现象:部分场景下,chunk迁移时可能会导致分片出现性能毛刺问题。

  • 修改建议:一般情况无需调整。如果分片集群实例在均衡期间因为chunk迁移而导致性能毛刺问题,可以考虑将此参数调整为一个固定的批次大小。

setParameter.rangeDeleterBatchDelayMS

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:否

  • 默认值20

  • 作用:chunk迁移时清理步骤中批量删除的间隔时间(也会影响清理孤立文档的cleanupOrphaned命令),单位为毫秒。

  • 现象

    • 部分场景下,进行chunk迁移后的文档异步删除时可能会导致CPU突增。

    • 参数设置过大,文档可能未及时删除导致变成孤立文档;或者需要删除的文档太多而超时,出现下面的错误日志:

      Message: "OperationFailed: Data transfer error: ExceededTimeLimit: Failed to delete orphaned <db>.<collection> range [xxxxxx,xxxxx] :: caused by :: operation exceeded time limit"
  • 修改建议:一般情况无需调整。如果分片集群实例在均衡期间因为文档异步删除而导致CPU使用率突增,可以考虑将此参数调大,比如调整为200

setParameter.rangeDeleterBatchSize

  • 适用大版本:大于等于4.0

  • 修改完是否需要重启:否

  • 默认值0(代表自动选择合理的批次大小,一般为128)

  • 作用:指定chunk迁移时清理步骤中批量异步删除单个批次的最大文档数量。

  • 现象:部分场景下,进行chunk迁移后的文档异步删除时可能会导致CPU使用率突增。

  • 修改建议:一般情况无需调整。如果分片集群实例在均衡期间因为文档异步删除而导致CPU突增,可以考虑将此参数调整为一个固定的批次大小。

说明

此参数与setParameter.rangeDeleterBatchDelayMS参数共同作用来影响chunk迁移后的文档异步删除流程,调整时可以分别调整、组合调整或者渐进式调整。

分片集群(Mongos)

operationProfiling.slowOpThresholdMs

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值100

  • 作用:定义一个查询是否为慢查询的阈值。

  • 现象

    • 参数设置过小,将导致产生大量慢日志和审计日志,带来慢日志噪音影响慢查询分析。

    • 参数设置过大,将导致很多慢查询并不输出在日志中,影响慢查询分析过程。

  • 修改建议:根据业务的实际情况适当调小或调大阈值,推荐设置为比业务核心查询的平均耗时稍大些的值。示例如下:

    • 假设一个对查询延时比较敏感的业务,日常的查询耗时都仅在30ms左右,为了协助分析一些瞬时抖动的慢查询情况,可以将此参数调小到50。

    • 假设一个分析查询比较重的业务,日常查询耗时都在300~400ms左右,为了减少慢日志噪音,可以将此参数调大到500。

setParameter.ShardingTaskExecutorPoolMaxConnecting

  • 适用大版本:大于等于3.6

  • 修改完是否需要重启

    • 3.64.0版本:是

    • 大于等于4.2版本:否

  • 默认值2

  • 作用:指定分片集群实例MongosTaskExecutor连接池初始化连接时的最大并发度。用来控制mongosmongod的连接建立速度。

  • 现象:如果该值设置较大,在触发较多连接创建时,可能会引起MongosCPU使用率突增。

  • 修改建议:不建议调整。

setParameter.ShardingTaskExecutorPoolMaxSize

  • 适用大版本:大于等于3.6

  • 修改完是否需要重启

    • 3.64.0版本:是

    • 大于等于4.2版本:否

  • 默认值2^64-1(int64类型的最大值)

  • 作用:指定分片实例Mongos上每个TaskExecutor连接池的最大连接数。

  • 修改建议:无需调整。如果期望限制MongosShard之间的连接池上限,可以设置,但不建议设置得太小,否则会导致连接池耗尽时Mongos上请求阻塞等待的问题。

setParameter.ShardingTaskExecutorPoolMinSize

  • 适用大版本:大于等于3.6

  • 修改完是否需要重启

    • 3.64.0版本:是

    • 大于等于4.2版本:否

  • 默认值1

  • 作用:指定分片集群实例Mongos上每个TaskExecutor连接池的最小连接数。

  • 现象:部分场景下,Mongos上突发的请求可能会导致TaskExecutor连接池需要额外新建很多连接,然后引起Mongos上的CPU突增以及其他问题。

  • 修改建议:建议设置为[10,50]间的合理值,具体多少应该取决于分片实例的拓扑结构(分片数以及分片内的节点数)。请注意,Mongos维护这些到Shard上的空闲连接会有少量资源开销。

setParameter.cursorTimeoutMillis

  • 适用大版本:大于等于3.0

  • 修改完是否需要重启:否

  • 默认值600000(10min)

  • 作用:空闲游标的到期阈值,单位为毫秒。如果游标的空闲时间超过该阈值,则MongoDB会自动清理该游标。

  • 现象:如果尝试访问一个已经被清理的过期游标,客户端侧会收到以下格式的报错:

    Message: "cursor id xxxxxxx not found"
    ErrorCode: CursorNotFound(43)
  • 修改建议:不建议调大,为了降低空闲游标的资源开销,可以适当调小(比如到300000)。无论如何,业务侧都应尽量避免出现长时间空闲游标的情况。