`
russelltao
  • 浏览: 157186 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

深入mongoDB(1)--mongod的线程模型与网络框架

 
阅读更多

最近工作需要开始研究mongoDB,我准备从其源代码角度,对于mongod和mongos服务的架构、sharding策略、replicaset策略、数据同步容灾、索引等机制做一个本质性的了解。其代码约20万行(我研究的是2.0.6版本源码),本篇先从mongod的启动流程说起,它本是一个多线程程序,所以本文在于说明mongod有多少个线程,每个线程的意义所在。希望大家阅读本文时关注在mongod的外围框架,暂不涉及数据文件的组织、索引B树的组织等,仅focus in在网络框架、线程模型上。


弄清楚这点的好处很明显:之后就可以有的放矢的研究mongod某个模块究竟是如何实现的,可以快速的跳到相应的类中阅读源码,解决我们在产品中的实际问题。我认为这是研究其庞大源码一个好的开始。


在说明mongod前,须了解mongoDB大量代码是基于boost库构建的,因此这里先行对boost库建立线程做个简单的了解。


1、boost库如何建立线程

boost::thread是boost中跨平台的多线程库,mongoDB创建线程时大多数情况下是使用thread库的(少量情况直接调用pthread_create方法),主要使用了以下两种方式:

(1)直接运行让线程运行func

例如durThread线程:

void durThread() {

while( !inShutdown() ) { ... }

}

boost::thread t(durThread);

(2)在类中定义静态的run方法,调用thread创建线程

class FileAllocator : boost::noncopyable {
static void run( FileAllocator * fa );


void FileAllocator::start() {
boost::thread t( boost::bind( &FileAllocator::run , this ) );
}
};


2、mongod的入口

mongod的入口main函数在src/mongo/db/db.cpp文件中,我画了个简单的活动图简要介绍其启动流程:


如上图所示,这里出现了12个固定线程,还没有包括mongod运行以后处理请求时派生出来的线程,如下所示:

– interruptThread

– DataFileSync::run

– FileAllocator::run

– durThread

– SnapshotThread::run

– ClientCursorMonitor::run

– PeriodicTask::Runner::run

– TTLMonitor::run

– replSlaveThread

– replMasterThread

– webServerThread

– 处理数据库请求的主线程

如果不属于任何replica set,那么至少有10个固定线程(去除replSlaveThread和replMasterThread)。

下面我们先讨论这10个固定的线程,再讨论性能非常弱的监听web事件的线程是怎样处理请求的,最后讨论性能稍好一点的主服务线程是怎样处理请求的。


3、5个基于BackgroundJob类实现的工作线程

这5个线程分别是DataFileSync,SnapshotThread, ClientCursorMonitor, TTLMonitor, PeriodicTask,类图如下所示:


上面这5个类也是用boost::threadfunction方法创建线程运行的,它们继承了BackgroundJob类,使用go方法启动线程执行jobBody就是在启动线程执行run方法,如下所示:

    BackgroundJob& BackgroundJob::go() {
        boost::thread t( boost::bind( &BackgroundJob::jobBody , this, _status ) );
        return *this;
    }
	
    void BackgroundJob::jobBody( boost::shared_ptr<JobStatus> status ) {
        ...
        run();
        ...
    }	

这些线程的意义如下:

DataFileSync主要在调用MemoryMappedFile::flush方法将内存中的数据刷到磁盘上。 我们知道,mongodb是调用mmap把磁盘中的数据映射到内存中的,所以必须有一个机制时刻的刷数据到硬盘才能保证可靠性,多久刷一次是与syncdelay参数相关的。

SnapshotThread将生成快照文件帮助快速恢复。

ClientCursorMonitor将管理用户的游标,每4秒调用一次idleTimeReport()方法,每一分钟调用sayMemoryStatus()方法。

TTLMonitor管理TTL,通过调用doTTLForDB()方法检查所有db。

PeriodicTask将从动态数组std::vector<PeriodicTask* > _tasks中获取周期性任务执行。


4、5个直接提供全局方法执行的线程


FileAllocator用于分配新文件,它决定分配文件的大小,例如用翻倍的方式。

interruptThread只处理信号量。

durThread做批量提交和回滚工作。

replSlaveThread是当前结点作为secondary时的同步线程。

replMasterThread是当前结点作为master时的同步线程。


5、web监听线程

mongod是如何处理web请求的呢?它是通过网络框架中的核心类Listerner实现的,类图如下所示:


怎么理解这幅类图呢?

首先看Listener类,它负责监听、创建新连接,其工作步骤如下:

a、创建socket句柄,绑定端口,监听

b、调用select检测新连接事件

c、对检测到的事件调用accept建立新连接

d、调用void Listener::acceptedMP(MessagingPort*mp)方法处理新连接,谁重新实现acceptedMP方法谁决定处理方式


这个Listener类既用于处理web请求,也用于处理普通的数据库请求。

OK,现在我们看web请求是如何处理的。MiniWebServer类继承了Listener类,它重新实现了acceptedMP方法,开始接收TCP流,解析HTTP协议,同时还会负责组装HTTP响应包并发送TCP流到客户端。那么实际完成http请求的类是谁呢?它是继承了MiniWebServer类的DbWebServer类。这个类重新实现了doRequest方法,它会在完整接收到HTTP请求后被调用,HTTP请求的处理过程不在本篇的讨论范围内,这里略过。但我们清楚了,这个线程采用同步的阻塞的方式处理请求,它意味着它同一时刻只能处理一个web请求,并发能力超级弱,还好web请求只是mongod的副业,仅用于查询状态。


6、主监听线程和数据请求的处理线程

处理数据库请求的是上图中的PortMessageServer 类,它运行在主线程中。

我们先看看PortMessageServer 类是如何实现acceptedMP方法的:

virtual voidacceptedMP(MessagingPort * p) {
	if ( !connTicketHolder.tryAcquire() ) {
		sleepmillis(2); // otherwisewe'll hard loop
		return;
	}
	 …
		int failed =pthread_create(&thread, &attrs, (void*(*)(void*)) &pms::threadRun,p);
		…
}

很清晰,它开启了一个线程独立的执行这个请求。虽然这种方式依然性能极差:大量的进程间上下文切换在等着我们,但总比web请求处理要好多了,而且mongod的并发能力本来就不是它的长项。

对于每个新连接,都会有类封装成对象,如下:


接下来pms::threadRun方法是在处理MessagingPort对象。

下面看看pms::threadRun方法中做了些什么:

void threadRun( MessagingPort *inPort) {
	TicketHolderReleaserconnTicketReleaser( &connTicketHolder );
	Message m;
	try {
		LastError * le = newLastError();
		lastError.reset( le ); //lastError now has ownership
		handler->connected( p.get());
		while ( ! inShutdown() ) {
			if ( ! p->recv(m) ) {
				p->shutdown();
				break;
			}
			handler->process( m ,p.get() , le );
		}
	}
	handler->disconnected( p.get());
}

可以看到,它会在这个连接上接收完整的请求,之后会调用handler的process方法。这个handler又是什么呢?如下图所示:


所以,普通的数据库请求是由MyMessageHandler的process方法处理的。这个方法里也只是个封装,真正处理业务的是全局方法assembleResponse。

assembleResponse方法中会按照8种操作方式分别的调用DataFileMgr中的方法处理实际文件,例如:

enum Operations {
	opReply = 1,     /* reply. responseTo is set. */
	dbMsg = 1000,    /* generic msg command followed by a string */
	dbUpdate = 2001, /* update object */
	dbInsert = 2002,
	//dbGetByOID = 2003,
	dbQuery = 2004,
	dbGetMore = 2005,
	dbDelete = 2006,
	dbKillCursors = 2007
};

在方法中有类似这样的代码在调用实际的业务类处理操作:

                else if ( op == dbInsert ) {
                    receivedInsert(m, currentOp);
                }
                else if ( op == dbUpdate ) {
                    receivedUpdate(m, currentOp);
                }
                else if ( op == dbDelete ) {
                    receivedDelete(m, currentOp);
                }

当然本篇志不在此,下篇我们再讨论索引和数据文件的操作。





分享到:
评论

相关推荐

    mongodb-async-driver-2.0.1 jar包

    5. **认证和安全性**:支持MongoDB的各种安全特性,包括SSL/TLS加密连接、身份验证(如SCRAM-SHA-1或MONGODB-CR)、角色权限管理和访问控制。 6. **CRUD操作**:提供对MongoDB基本的Create(创建)、Read(读取)、...

    MongoDB-C++-Driver3.2.rar

    同时,它还支持认证机制,如SCRAM-SHA-1和MONGODB-X509,确保只有授权用户才能访问数据库。 最后,驱动还提供了日志记录和错误处理功能,帮助开发者调试和诊断问题。通过设置日志级别,可以获取不同级别的信息,而...

    mongodb-win32-x86_64-2008plus-3.4.12-signed.msi

    总的来说,MongoDB 3.4.12是适用于Windows 64位系统的强大数据库解决方案,它提供了一套全面的功能,包括高性能、高可用性和灵活的数据模型,对于开发者和管理员来说都是一个可靠的选择。通过下载和安装"mongodb-win...

    MongoDB 开发文档

    MongoDB 是一款非常流行的开源文档型数据库系统,以其灵活的数据模型、高扩展性和强大的性能而闻名于世。它支持多种编程语言,并且有着丰富的生态系统,使得开发者可以轻松地在不同的环境中部署和管理MongoDB。 ###...

    nodejs + mongodb 合集 (1)

    .pdf"(可能由于字符编码问题,部分字符显示不正常,但大致可以推测是关于Node.js实战的中文版教程)则可能涵盖了Node.js的基础知识,包括模块系统、文件I/O、网络编程、Express框架的使用,以及如何与MongoDB进行...

    SpringMVC+mongodb应用实例

    在本实践教程中,我们将深入探讨如何将SpringMVC框架与MongoDB数据库结合,构建一个高效的应用实例。MongoDB是一个流行的NoSQL数据库,以其灵活性、高性能和易扩展性而受到开发者的青睐。SpringMVC是Spring框架的一...

    定向爬虫:MongoDB与Scrapy-v11.zip

    本项目结合了MongoDB数据库和Scrapy框架,为数据存储和爬虫构建提供了完整的解决方案。 首先,我们要理解MongoDB,这是一个基于分布式文件存储的开源文档数据库系统。MongoDB的优势在于其灵活性和可扩展性,它支持...

    基于hyperf的mongodb连接池组件暂不支持协程

    Swoole的主要特性之一就是协程(Coroutine),这是一种轻量级的并发模型,能够在用户态进行上下文切换,相比传统的线程模型,协程具有更低的开销和更高的执行效率。在Hyperf中,协程被广泛用于实现微服务间的无阻塞...

    NoSQL数据库-MongoDB和Redis

    - **高性能**:使用单线程模型处理请求,具有非常高的吞吐量。 - **持久化**:支持两种持久化方式:RDB(快照)和AOF(Append Only File)。 - **发布/订阅模式**:支持消息队列功能。 - **数据结构丰富**:支持多种...

    mongoDB说明文档

    结合流行的Python Web框架Django与MongoDB,可以构建高性能的Web应用。这部分内容详细介绍了如何在Django项目中配置和使用MongoDB。 ### **6. 入门指南(Getting Started)** 入门指南为初学者提供了快速上手...

    前端 Vue+Node+MongoDB高级全栈开发

    在本篇内容中,我们将深入探讨“前端 Vue+Node+MongoDB 高级全栈开发”的核心知识点。通过本文的学习,您将能够更好地理解如何利用这些技术构建高效、灵活且可扩展的应用程序。 ### 一、Vue.js简介 **Vue.js** 是...

    Pure JS (4.1): 使用 MongoDB 进行数据存储和管理

    **标题解析:** "Pure JS (4.1): 使用 MongoDB 进行数据存储和管理" 暗示本文将探讨如何使用纯JavaScript与MongoDB数据库进行交互,以实现数据的存储和管理,而不依赖任何特定的前端或后端框架。 **描述分析:** ...

    MongoDB介绍

    6. **聚合框架**:MongoDB提供了一种强大的聚合框架,类似于SQL的GROUP BY操作,允许用户在服务器端进行复杂的分析和数据处理。 7. **地理空间索引**:MongoDB支持对地理位置数据进行索引,便于进行地理位置相关的...

    面试题库(Python+Vue+MongoDB).zip

    1. **Python** 部分:可能包括Python的基础语法、面向对象编程、常用库(如Numpy、Pandas、Django、Flask等)、错误和异常处理、多线程与并发、网络编程以及Python在实际项目中的应用等。 2. **Vue.js** 部分:涵盖...

    Go-Go的MongoDB驱动

    mgo支持SSL/TLS加密连接,保证了数据传输的安全性,还可以配置认证机制,如SCRAM-SHA-1或x509证书。 9. **示例代码**: ```go import "gopkg.in/mgo.v2" session, err := mgo.Dial("mongodb://localhost") if...

    面试真题包含spring-java-集合-框架-并发-spring-运维-数据库等多领域45卷合集.rar

    这份名为"面试真题包含spring-java-集合-框架-并发-spring-运维-数据库等多领域45卷合集.rar"的压缩包是为准备Java相关面试的求职者精心整理的资源库。它包含了45套涵盖多个领域的面试题,旨在帮助求职者全面复习和...

    koa mongodb 后台系统.zip

    在本项目中,Node.js将作为服务器端运行环境,通过Koa框架接收并处理来自前端的请求,同时与MongoDB数据库进行数据交换。 四、Web系统架构 本后台系统的架构遵循MVC(Model-View-Controller)设计模式,模型层负责...

    ET开源游戏服务器框架C#

    首先,ET游戏服务器框架采用了Actor模型,这是一种并发处理模型,通过消息传递实现线程间的通信。这种模型可以避免竞态条件,提高系统的可扩展性和并行性,非常适合处理大量的并发请求,如游戏中的玩家交互、战斗...

    Backend system based on node.js + Mongodb. 基于 node.js + Mongodb

    它的异步模型使得系统能同时处理多个请求,避免了线程切换带来的开销。模块系统(如`require`)使得代码可复用性增强,方便构建大型项目。此外,Node.js还有丰富的生态系统,包含各种中间件、框架和库,如Express...

    mongodb驱动PHP版

    此外,MongoDB支持多种查询语法,包括简单的键值匹配、正则表达式、范围查询以及复杂的聚合框架。PHP驱动提供了方便的方法来构建这些查询,如`find()`用于查找文档,`insertOne()`和`insertMany()`用于插入数据,`...

Global site tag (gtag.js) - Google Analytics