【问题标题】:MongoDB on Windows slow *sometimes* using tailable cursors as message queueWindows 上的 MongoDB *有时* 使用可尾游标作为消息队列缓慢
【发布时间】:2014-01-29 04:46:04
【问题描述】:

我们正在用 C#、Delphi、PL/SQL 和 PHP 的客户端完成 C 上的通用服务总线实现。 该库运行良好,我们的总线性能出色除非 MongoDB 数据库在 Windows 上运行(在 2008 R2、2003 和 7 上测试)并且没有其他“特殊" 程序正在运行。

Out 测试执行以下操作:

  1. 程序 A 发送关于上限集合的消息
  2. 程序 B 在消息队列集合上结束,并在消息出现时使用 awaitData 参数设置为 true 的游标“唤醒”
  3. 当程序 B 唤醒时,准备一条消息并向程序 A 发送响应,在程序 A 的特定集合中插入一个文档
  4. 程序 A 已经在等待第二个“响应”集合,并在程序 B(生产者)发回响应时唤醒
  5. 循环到此结束

我们的测试程序计算循环并报告使用 Visual Studio 2010 编译的控制台应用程序的性能。

我们在一台机器上运行这一切,或者为 MongoDB 使用不同的机器并在同一台机器上运行消费者和生产者。 我们在 Windows 2008R2、Windows 2003 和 Windows 7 上运行它。 对于 2008R2,我们为该操作系统使用了特殊的 mongo 构建,而对于 2003 和 7,我们使用了“旧版”64 位构建。

在干净的操作系统中,没有程序运行,我们的测试每秒执行大约 32-50 次往返,与我们在全速运行时获得的“好”结果相比,这是一个糟糕的表现。

现在,奇怪的事情来了:

当在运行 mongo 数据库的同一台机器上启动某个应用程序时,我们的测试速度提高到大约 450/秒(当在同一台机器上运行环回所有内容时)到大约 300/秒(当消费者和生产者在一台机器上运行时) , 和另一台机器上的 mongodb 通过网络。

我们以前从未一直注意到这个问题的原因是因为我们在开发中几乎一直打开 vms Visual Studio,而 Visual Studio 是一个充当“mongodb 加速器”的程序(我知道这听起来很荒谬,请不要在这个声明上抨击我)。

起初,我们基本上是在没有打开 VS 的情况下运行我们的测试时“随机”注意到这个问题的。因此,我们倾向于将其归咎于 vmware 运行的底层 SAN、vm 主机、宇宙射线或 NSA 窥探我们的程序。 直到我们最终弄清楚了在我们运行测试时同时打开 VS 之间的相关性,并缩小到以下几点:

MongoDB 在 Windows 系统(作为控制台或作为服务)上运行,虚拟或物理版本 2008R2、2003 或 7 运行缓慢以相同方式访问另一个上限集合的消费者除非您只需启动一个程序,例如 Visual Studio、Delphi XE4、Google Chrome 浏览器、CrystalDiskMark 磁盘 I/O 测试程序(其他程序也可以加速 Mongo )。然后 mongodb 的速度比前面提到的模式提高了一个数量级。

我们无法准确找到这些程序可能导致问题的共同点。

此时我们对这个问题感到震惊,我什至查看了用于可尾游标的 MongoDB 代码,但没有发现任何闻起来可能会导致问题的东西。代码几乎旋转了最多 4 秒以等待数据出现,除了每个循环上的可疑“睡眠”调用之外,没有其他引人注目的地方。

是否有可能某些程序最终导致 Sleep() Windows API 调用行为不同?这使得 mongo 在可尾光标上执行此操作更慢??

我们认为某些东西确实在“变慢”,因为 CPU 利用率配置文件也下降了,就像 mongodb 在运行缓慢时实际上是在“等待”某些东西。

我知道这种模式在基于 unix/linux 的系统上运行良好,我在 Mac 上尝试了相同的代码库,没有任何问题,所以这闻起来像 Windows 问题。

还有其他人遇到过类似的问题吗?

【问题讨论】:

  • 我认为问题的答案可能在这里:stackoverflow.com/questions/9518106/…。 MongoDB 在循环中使用 sleep(2),其中可尾游标在到达上限集合的末尾时会等待更多数据

标签: performance mongodb cursor tail


【解决方案1】:

找到问题的根源。 MongoDB 直接调用 Sleep() Windows API 函数,即使睡眠时间少于 15 毫秒。

由于默认的 Windows 最小分辨率,任何小于该分辨率的设备(至少在 Windows 2008 R2、Windows 2003 和 Windows 7 上)无论如何都会休眠至少 15 毫秒。

MongoDb 中的简单解决方案是从这里更新 time_support.cpp:

void sleepmillis(long long s) {
    fassert(16228, s <= 0xffffffff );        
    Sleep((DWORD) s);
}

到:

extern "C" unsigned int __stdcall timeBeginPeriod( unsigned int ms );
extern "C" unsigned int __stdcall timeEndPeriod( unsigned int ms );
// Notice bellow the arbitrary nature of 50ms set as the "minimum" timer resolution
// There seems to be no complete agreement on that *is* the default timer resolution in Windows.
// To be on the "safe side" let's use 50ms
#define BELLOW_WINDOWS_MIN_RESOLUTION(s)(s > 0 && s < 50)

void sleepmillis(long long s) {
    fassert(16228, s <= 0xffffffff );
    // When our waiting period falls bellow Windows min resolution, let's set resolution
    // to 1 ms. Note that this change may effect all kernel scheduler thread operations.
    // Apparently this changes the Windows kernel "quantum" length
    // see http://msdn.microsoft.com/en-us/library/windows/desktop/dd757624(v=vs.85).aspx
    // Applications such as Google Chrome seem to do this during the life of Chrome, that's why
    // running apps which do this "accelerate" certain mongo operations that depending on proper
    // Sleep() resolution on Windows
    if(BELLOW_WINDOWS_MIN_RESOLUTION(s)) timeBeginPeriod(1);
    Sleep((DWORD) s);
    if(BELLOW_WINDOWS_MIN_RESOLUTION(s)) timeEndPeriod(1);
}

【讨论】:

  • 仅供参考,这已在 mongodb 中修复(感谢 jsbattig)。
猜你喜欢
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多