免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5027 | 回复: 1

[MongoDB] MongoDB数据缓存刷新机制 [复制链接]

论坛徽章:
0
发表于 2012-02-22 14:51 |显示全部楼层
MongoDB数据缓存刷新机制




本文原文出自淘宝DBA团队博客,文章对MongoDB源码进行了分析,跟踪了其缓存Flush机制,对缓存刷新机制进行了清晰的讲解。

最近配合好几个项目测试了MongoDB的写入性能。在内存没有用尽的情况下,虽然MongoDB只有一个更新线程,写入还是非常快的,基本上能达到25000/s以上(索引数据用uuid_generate_randome和uuid_unparse随机产生)。当内存用尽开始往磁盘上刷脏页的时候,性能有非常大的波动,即使调整了syncdelay也没有太大改善。在测试中还出现了一个莫名其妙的情况:MongoDB会间歇性地释放文件系统的cache。除了直接删除表空间之外,很难想到有什么动作可以诱发这个现象。在MongoDB开发者论坛里描述了这个现象,但是Eliot Horowitz认为MongoDB内部并没有代码会释放文件系统cache。那么,让我们去源码里面看一下MongoDB缓存和刷新数据的机制。

首先找到mongod的入口(db/db.cpp),发现MongoDB的初始化步骤非常简单,概括起来就以下三步:
  1. int main(int argc, char* argv[], char *envp[] )
  2. {

  3. Module::configAll( params );
  4. dataFileSync.go();

  5. initAndListen(cmdLine.port, appsrvPath);
复制代码
}显然,dataFileSync就是我们感兴趣的那个类。dataFileSync类派生自BackgroundJob类,而BackgroundJob主要的功能就是生成一个后台线程并指派任务。数据的刷新是一个不断执行的后台任务,在dataFileSync.run()里面可以找到刷数据的相关代码:
  1. void run()
  2. {

  3. Date_t start = jsTime();
  4. int numFiles = MemoryMappedFile::flushAll( true );
  5. time_flushing = (int) (jsTime() – start);

  6. globalFlushCounters.flushed(time_flushing);
复制代码

}从这一段代码看,MongoDB会在syncdelay设定的周期内,采取同步的形式刷新所有的脏数据。再看一下flushAll是怎么刷新所有数据的:
  1. int MongoFile::flushAll( bool sync )
  2. {

  3. set seen;
  4. while ( true ){
  5. auto_ptr f;
  6. {
  7. rwlock lk( mmmutex , false );
  8. for ( set::iterator i = mmfiles.begin(); i != mmfiles.end(); i++ ){
  9. MongoFile * mmf = *i;
  10. if ( ! mmf )
  11. continue;
  12. if ( seen.count( mmf ) )
  13. continue;
  14. f.reset( mmf->prepareFlush() );
  15. seen.insert( mmf );
  16. break;
  17. }
  18. }
  19. if ( ! f.get() )
  20. break;

  21. f->flush();
  22. }
  23. return seen.size();
复制代码
}上面这一段代码实现的功能很简单,就是把mmfiles中所有MongoFile指针所引用的对象都flush()一次。不过在执行flush()函数之前,需要先执行prepareFlush()确保这个对象是可以执行flush()函数的。下面是最后真正执行刷新操作的代码:

void MemoryMappedFile::flush(bool sync)
{
if ( view == 0 || fd == 0 )
return;
if ( msync(view, len, sync ? MS_SYNC : MS_ASYNC) )
problem() << “msync ” << errnoWithDescription() << endl;
}终于刷新到磁盘了,呵呵。不过这篇blog只涉及到了数据刷新的代码,至于如何缓存,且听下回分解。

来源:www.taobaodba.com


论坛徽章:
0
发表于 2012-02-24 17:38 |显示全部楼层
谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP