You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby脚本远程执行MongoDB查询耗时波动大的原因排查

为什么我的MongoDB查询时快时慢?

让咱们一步步拆解这个问题,结合你的代码和MongoDB的特性,看看哪些因素可能导致这种忽快忽慢的情况:

首先先贴出你的代码方便参考:

script.rb

require '/home/ubuntu/praneetha/check_mongo/publisher_models.rb'
$stdout.sync = true

begin
  count = 1
  user_id = '53ce011f9937d923a4000001'
  while(true)
    puts "count: #{count}"
    t1 = Time.now.utc
    puts "Time.now is ========= #{t1}"
    p = Puser.find_by(:puid => user_id)
    puts "puser is ====#{p.class}"
    t2 = Time.now.utc
    t3 = t2-t1
    puts "time taken =====> #{t3}"
    if t3>2
      puts "I have an error at time #{t1} and total time is #{t3} "
    end
    count = count + 1
    sleep(300)
  end
end

publisher_models.rb

require 'mongoid'
require 'em-synchrony'

class Puser
  include Mongoid::Document
  field :email, type: String
  #custom user id for the user. This should be indexed at the time of creation
  field :puid, type: String
end

最可能的原因:索引缺失或未生效

你的模型注释里提到puid字段“应该在创建时建立索引”,但实际可能并没有创建索引。这是导致查询时快时慢的头号嫌疑人:

  • 如果没有索引,MongoDB执行find_by(:puid => user_id)时会做全集合扫描(遍历所有文档找匹配项)。如果集合数据量很大,全表扫描的耗时会极不稳定:有时候刚好目标文档在内存缓存里,查询就快;如果文档被换出到磁盘,或者服务器正忙,就会慢到离谱(比如你遇到的15分钟)。
  • 排查方法:登录到MongoDB shell,执行db.pusers.getIndexes(),检查输出里是否有puid: 1的索引。如果没有,立刻创建:
    db.pusers.createIndex({ puid: 1 })
    
    创建索引后,再观察查询耗时应该会稳定在毫秒级。

服务器资源波动或负载过高

你的MongoDB是部署在远程服务器上的,服务器的CPU、内存、磁盘IO资源如果被其他任务占用,会直接拖慢查询速度:

  • 比如服务器正在执行大查询、数据备份、批量写入操作,或者其他应用占用了大量CPU/内存,你的查询就会被抢占资源,导致耗时陡增。
  • 排查方法:
    • 用top、iostat等工具监控服务器的CPU、内存、磁盘读写使用率,看查询变慢时是否对应资源峰值。
    • 查看MongoDB的日志文件(通常是/var/log/mongodb/mongod.log),看有没有慢查询记录、锁等待或者资源不足的警告。

网络链路问题

因为是远程连接,网络波动会直接影响查询耗时:

  • 比如网络拥堵、丢包、延迟突然升高,都会导致你的请求从本地到Mongo服务器的传输时间变长,甚至需要重传数据包,最终表现为查询耗时暴涨。
  • 排查方法:用ping、traceroute工具测试本地到Mongo服务器的网络延迟,观察是否有明显的波动或丢包情况。

数据缓存与内存压力

MongoDB会把常用数据缓存到内存中,如果服务器内存不足,缓存的热数据会被换出到磁盘:

  • 你的脚本是循环查询同一个user_id,如果这个文档刚好在内存缓存里,查询就快;如果缓存被其他数据挤掉,需要从磁盘读取,就会慢很多。
  • 排查方法:查看MongoDB的serverStatus输出(执行db.serverStatus()),关注mem字段里的缓存命中率,如果命中率过低,说明服务器内存不足,需要扩容或者优化数据存储。

集合碎片问题

如果pusers集合有大量的删除、更新操作,会导致集合产生碎片:

  • 碎片会让MongoDB在查询时需要遍历更多的磁盘块,耗时变得不稳定。
  • 排查方法:执行db.pusers.stats()查看storageSize和dataSize的差值,如果差值很大,说明碎片较多。可以用db.runCommand({ compact: 'pusers' })整理碎片(注意:compact操作会锁集合,建议在低峰期执行)。

锁等待问题

不同版本的MongoDB锁粒度不同(比如旧版MMAPv1是库级锁,新版WiredTiger是文档级锁):

  • 如果有大量的写操作(插入、更新、删除)在pusers集合上执行,你的查询可能需要等待锁释放,导致耗时变长。
  • 排查方法:执行db.currentOp()查看当前正在运行的操作,看有没有长时间等待锁的查询。

连接池或连接复用问题

虽然你的脚本是循环查询,但如果Mongoid的连接池配置不合理,可能会导致每次查询都重新建立连接:

  • 重新建立TCP连接的耗时会远高于复用已有连接,偶尔的连接超时或重建就会让查询耗时暴涨。
  • 排查方法:检查Mongoid的连接配置(通常在mongoid.yml里),确保连接池的max_pool_size、timeout等参数设置合理,避免连接频繁断开重连。

先从检查索引开始排查吧,这是最容易解决也最可能的原因。如果索引没问题,再依次排查服务器资源、网络、缓存这些因素。

内容的提问来源于stack exchange,提问作者Praneetha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:44:16