MongoDB数据缓存刷新机制

数据库 其他数据库 MongoDB
在MongoDB开发者论坛里描述了这个现象,但是 Eliot Horowitz认为MongoDB内部并没有代码会释放文件系统cache。那么,让我们去源码里面看一下MongoDB缓存和刷新数据的机制。

最近配合好几个项目测试了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. … 
  6. initAndListen(cmdLine.port, appsrvPath); 
  7. … 

显然,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); 
  7. … 

从这一段代码看,MongoDB会在syncdelay设定的周期内,采取同步的形式刷新所有的脏数据。再看一下flushAll是怎么刷新所有数据的:

  1. int MongoFile::flushAll( bool sync ) 
  2.  { 
  3.  … 
  4.  set seen; 
  5.  while ( true ){ 
  6.  auto_ptr f; 
  7.  { 
  8.  rwlock lk( mmmutex , false ); 
  9.  for ( set::iterator i = mmfiles.begin(); i != mmfiles.end(); i++ ){ 
  10.  MongoFile * mmf = *i; 
  11.  if ( ! mmf ) 
  12.  continue
  13.  if ( seen.count( mmf ) ) 
  14.  continue
  15.  f.reset( mmf->prepareFlush() ); 
  16.  seen.insert( mmf ); 
  17.  break; 
  18.  } 
  19.  } 
  20.  if ( ! f.get() ) 
  21.  break; 
  22.  f->flush(); 
  23.  } 
  24.  return seen.size(); 
  25.  } 

上面这一段代码实现的功能很简单,就是把mmfiles中所有MongoFile指针所引用的对象都flush()一次。不过在执行flush()函数之前,需要先执行prepareFlush()确保这个对象是可以执行flush()函数的。下面是***真正执行刷新操作的代码:

  1. void MemoryMappedFile::flush(bool sync) 
  2. if ( view == 0 || fd == 0 ) 
  3. return
  4. if ( msync(view, len, sync ? MS_SYNC : MS_ASYNC) ) 
  5. problem() << “msync ” << errnoWithDescription() << endl; 

终于刷新到磁盘了,呵呵。不过这篇blog只涉及到了数据刷新的代码,至于如何缓存,且听下回分解。

【编辑推荐】

  1. 设计实例对比:MySQL vs MongoDB
  2. MongoDB基于Java、PHP的一般操作和用户安全设置
  3. 在Windows环境下MongoDB搭建和简单操作
  4. 教你如何利用MySQL学习MongoDB
  5. 如何用Java操作MongoDB

 

 

责任编辑:艾婧 来源: 淘宝数据库技术团队
相关推荐

2021-12-08 06:53:28

Choreograph屏幕机制

2021-04-21 07:53:13

Android屏幕刷新

2020-10-13 08:36:30

React 架构机制

2010-09-06 08:43:13

.NET 4

2024-01-03 21:50:32

缓存机制请求

2010-06-02 11:33:26

Linux 内存监控

2020-09-21 14:35:20

VuenextTick前端

2010-03-10 11:55:30

Mocha BSM运维管理摩卡软件

2024-06-17 08:55:52

2016-10-21 09:29:53

嵌入式Linux更新机制

2021-02-25 11:12:31

人工智能生物技术肺纤维化药物

2018-08-10 04:40:56

2009-08-03 18:35:51

ASP.NET数据缓存

2024-04-29 08:05:34

NacosJava数据结构

2011-12-15 09:33:19

Java

2009-06-17 15:43:03

Hibernate缓存

2023-02-24 16:46:25

Glide缓存机制

2021-01-19 10:39:03

Redis缓存数据

2010-10-13 16:44:10

MySQL查询缓存机制

2009-11-09 17:55:13

WCF缓存
点赞
收藏

51CTO技术栈公众号