`
yangzb
  • 浏览: 3503636 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

CouchDB 实现原理

阅读更多

特性

  1. RESTFul API
  2. 基于文档存储,无表固定结构,数据之间没有关系范式要求
  3. 多版本并发控制模型
  4. 用户自定义查询结构(map/reduce)
  5. 增量索引更新机制
  6. 多master复制模式
  7. 用Erlang编写

CouchDB 能够适应非常广泛的应用场景,在某些偶尔连接网络的应用中,我们可以用CouchDB暂存数据,随后进行同步。也可以在Cloud环境中,作为大型的分布 式的数据存储。CouchDB提供了基于 HTTP的API的访问方式,这样,保证了所有的常见的语言都可以使用CouchDB。

底层存储结构

CouchDB是一个"面向文档"的数据库,文档的格式是一个JSON字符串(也可包含二进制附件)。 底层结构是由一个"存储"(storeage) ,以及多个"视图索引"(view indexs)。 "储存"用来储存文件, "视图索引"用于查询处理。

CouchDB落实到最底层的数据结构就是两类B+Tree 。

第一类B+Tree,by_id_index (使用document的id为key)。常用来通过document的id来查找document的位置,实际上,他是指向的一个reversion列表集合。

第 二类B+Tree, by_seqnum_index (使用序列号来作为key,说得具体点就是记录最新的reversion来作为key) 。当document进行更新的时候,就会产生一个新的序列号。 (值得注意的是,所有更新操作都是一个串行的方式,因此序列号反映了序列的非同步更新)。 同步复制的追踪,数据的显示以及更新与它都密不可分。

 


 

一切皆追加

所 有的更新操作(包括document的创建,修改和删除)都是以在couch文件尾部追加的方式(即Append方式)进行。而不是修改现有的文件。在此 之后, B+树节点也修改为指向新的文件的位置。修改操作实际上就是在现有的B+树的末尾附加一个新的文件。这反过来又引发修改父节点的B+树节点,造成一个新的 副本父节点...直到所有的方式回到根B+树节点。最后修改文件头以指向新的跟节点。

这意味着所有更新将触发1次写入文件(除删除)和logN写入每个B +树节点的页面。 因此,复杂度为O ( logN )。

一 切皆最佳的操作提供了一个有趣的MVCC (多版本并发控制)模型,因为该文件保存了所有以前的历史文件版本信息。 只要客户端持有先前根节点的B +树索引,它就可以得到的快照视图。即便是更新不断发生,客户将不会看到任何的最新变化。这种一致性快照在在线备份以及在线"瘦身"方面是非常有用的。

值得注意的是,读操作是并行的,写操作是串行的。 换句话说,在任何时候只有一个文件可以进行更新操作(但是,如果是写入附件的话,可以在一个文件中进行并行操作。)

GET document

当客户端向CouchDB的发出的HTTP的REST的GET请求,DBServer将做如下操作...

  1. 查找文件头,找到by_id B +树索引的根节点
  2. 在B +树中找出该文件的位置
  3. 阅读了该文件,并返回到客户端

PUT document(修改操作)

当客户端向CouchDB的发出的HTTP的REST的PUT请求,DBServer将做如下操作...

  1. 查找文件头,找到by_id B +树索引的根节点
  2. 在B +树中找出该文件的位置
  3. 读取该文件。对比reversion,如果他们不匹配就抛出一个错误。
  4. 如果它们匹配,生成一个新的reversion。
  5. 寻找末尾的一个区域(region),看看该文件的容量是否可以容纳,如果不能就另外开辟一个region。
  6. 写文件(新reversion)到新的区域(region)
  7. 修改by_id B +树以指向新的文件位置
  8. 修改by_seqnum B +树添加新实体(新seqnum ) ,并删除旧的条目(旧seqnum ) 。

请注意, by_seqnum B +树索引总是指向最新版本,以前的修改会自动被覆盖。

PUT/POST document(创建)

当客户端向CouchDB的发出的HTTP的REST的PUT请求,DBServer将做如下操作...

  1. 生成一个新的seqnum及一个新的文件编号和修订
  2. 寻找末尾的一个区域(region),看看该文件的容量是否可以容纳,如果不能就另外开辟一个region。
  3. 写文件(新reversion)到新的区域(region)
  4. 修改by_id B +树以指向新的文件位置
  5. 修改by_seqnum B +树添加新项目(新seqnum )

删除文件(修改)

当客户端向CouchDB的发出的HTTP的REST的DELETE请求,DBServer将做如下操作...

  1. 查找文件头找到根节点的by_id B +树索引
  2. 在B +树找出叶节点以及该文件的位置
  3. 读取该文件。 对比修订,如果他们不匹配就抛出一个错误。
  4. 如果它们匹配,找出找到这个reversion。
  5. 生成一个新的reqnum
  6. 修改by_id B +树的reversion 历史,将这个路径的reversion标记为被删除
  7. 修改by_seqnum B +树添加新实体(新seqnum ) ,并删除旧的条目(旧seqnum )。

Online Compation(删除旧的Document)

作为一个一切皆追加的存储方式,存储文件会随着时间的推移与日俱增。 因此,我们需要对其进行"瘦身",删除那些旧的Document数据。这个过程称为 Compaction。

打开一个新的存储文件
从by_seqnum B +树索引中找到最新reversion的document
复制document到新的存储文件中(在新的存储文件中自动更新相应的B +树索引)。

在 Compation的过程,数据库仍然可用,只是请注意,在Compation的时候,是通过遍历DBName.couch文件, 将最新的数据拷贝到一个DBName.compat文件中, 因此这个过程可能会耗费很大的存储空间,如果您在系统繁忙(主要是write)的情况下进 行Compation,可能会导致你的硬盘空间耗尽。推荐系统在一个写操作不是很繁忙的情况下进行Compation。

View Indexs

CouchDB 支持类似数据库的View的概念。所不同的是CouchDB是采用Map/Reduce的方式来表现的。(请注意,reduce语义与谷歌的Map /Reduce模型有着很大的不同)。Map()是一个用户定义的函数,它用来将每个文件处理成中间结果。Reduce()是另外的一种用户定义的函数, 它用户将Map()函数所产生的中间结果进行收集汇总而生成最终结果。

Map()的中间对象和Reduce()后的结果存储在View Indexs中。随着存储得到更新, 以前的结果也会随着更新。

每一个View的定义就是一个Map函数和一个可选的Reduce函数。View存储在design Document中。

(map函数,必须)
function(doc) {
emit(null
, doc);
}
(reduce函数,可选)
function (key, values, rereduce) {
   return
 sum(values);
}

请注意这里design Document和View Index是不同的。design Document保存的是view的定义,View Index保存的是针对某个Database进行View操作,产生的结果。


 

起初,View文件是空的(View尚未创建) , 当查询执行的时候会触发下面一系列的处理。

1.CouchDB将遍历存储文件的by_seqnum B +树索引。
2.在此基础上, CouchDB获得所有现有文件的最新reversion
3.CouchDB通过seqnum获取document,然后将每份document反馈到View Server 上用于进行Map操作。
4.View Server 调用map(doc)函数,遍历调用emit(key,value),一个中间实体就是被这么创建出来的。
5.最后,将map(doc)函数所产生和结果集返回给CouchDB 。
6.CouchDb将这些实体加入到B +树索引,Key = emit_key + doc_id 。 遍历每一个B +树的叶节点。
7.CouchDB将View Servier所获得的Map()结果集进行"Reduce" 操作。
8.View Server 调用Reduce(key,value)函数。
9.将reduce计算的结果返回给CouchDB
10.CouchDb将更新叶子上的B +树节点,将其指向reduce的值。
11.在此之后, CouchDb移动到父节点的叶子上的B +树节点。 遍历每个B +树父节点, CouchDB将相应reduce子节点的数据发送到View Server,再次进行reduce的操作(rereduce)。
12.View Server再次调用 reduce(key, value)函数。
13.最后, 再将rereduce计算出的结果返回给CouchDB 。
14.CouchDB将更新父B +树节点,将其指向rereduce的值。

CouchDB继续上升一个等级,并重复计算rereduce结果。 最后,直到更新完根节点的rereduce的结果为止。


 

当处理完成后,View Index 看上去就是下面这种样子


 

增量视图更新

CouchDB更新view indexes采用懒加载和增量的方式。 也即是说,当文件被更新了,CouchDB不会立即刷新view index,直到下一次查询到来的时候才进行更新。

CouchDB刷新index采用如下的方式:

  1. CouchDB将遍历存储文件的by_seqnum B +树索引。
  2. CouchDB从最后一次视图查询的结果中抽取出的所有改变的文档,然后从新进行map操作,并取得一个Map结果集合。
  3. CouchDb更新Map结果到B +树索引,一些叶子B +树节点将被更新。
  4. 对于那些已经更新了的叶子B +树节点, CouchDB重新发送Map生成的所有中间结果到View Server 进行Reduce的操作。 然后reduce的结果保存到B +树节点。
  5. 所有涉及到这个叶子B +树节点都需要更新, CouchDB需要再次执行Reduce计算,并且更新相应的父节点。 直到更新完根节点为止。

由于一致的快照的特性,在进行数据更新操作的过程中,view 查询需要花费较长时间。 查询需要等待索引更新完成后才能看到一致的结果。 还有一个选择(开发中) ,立即返回一个陈旧的副本,这对客户来说是可以容忍的。

分享到:
评论

相关推荐

    couchdb源码

    在深入探讨CouchDB源码之前,我们首先理解CouchDB的基本概念和工作原理。 CouchDB的核心是基于JSON(JavaScript Object Notation)的数据存储方式,这种格式易于读写且兼容性好,使得CouchDB非常适合Web应用。每个...

    CouchDB权威指南

    通过阅读《CouchDB权威指南》这本书,读者将能够深入了解CouchDB的原理、功能、优势以及如何在实际项目中有效利用这些特性。无论是初学者还是经验丰富的开发者,都能从中获得宝贵的知识和指导。

    Go-go-couchdb-另一个CouchDBHTTPAPI的Go封装

    通过阅读`go-couchdb-master`压缩包中的源代码,你可以更详细地了解库的内部实现,包括各个函数的工作原理和它们如何包装HTTP请求。此外,查看库的文档和示例代码也是学习如何使用`Go-couchdb`的好方法。 总的来说...

    Python-CouchApp是一个开发使用CouchDB的Web应用的小型框架

    Python-CouchApp的工作原理是将文件系统的目录结构映射到CouchDB的设计文档(Design Document)。设计文档包含了定义CouchDB视图、更新函数、验证函数等逻辑的JSON文件。通过这种方式,开发者可以在本地进行开发,...

    数据库CouchDB入门到精通视频课程下载整理.zip

    3. 源代码分析:通过分析相关的源代码,可以更直观地了解CouchDB的工作原理,提升解决问题的能力。 4. 数据集:练习使用CouchDB处理不同类型的数据显示其灵活性和效率,例如模拟日志记录、社交网络数据存储等。 ...

    面向文档存储数据库系统Apache CouchDB入门到精通视频教程

    视频详细讲解,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 1、课程简介 CouchDB 是一个开源的面向文档的数据库管理系统,...第18节 - 18.LightCouch实现增删改操作 第19节 - 19.筛选出多个满足条件的doc

    CouchDB Introduction

    4. **分布式的特性**: CouchDB支持多节点部署,并且可以通过复制机制实现数据冗余,增强系统的可用性和容错性。 5. **事件最终一致性**: 在分布式环境中,CouchDB通过事件最终一致性模型来解决数据同步问题。 6. **...

    flycouchdb:CouchDB的迁移工具

    开发者可以通过阅读源码来理解其工作原理,或者直接参与到项目中,贡献自己的力量,共同推动这个工具的完善和发展。 总结来说,`flycouchdb`是一款强大的CouchDB迁移工具,借助Clojure的高效性,为数据库的迁移提供...

    couchdb-orm:一个简单的CouchDB ORM

    7. **连接池管理**:为了优化性能,ORM可能实现了连接池,可以高效地管理和复用数据库连接。 8. **同步与异步操作**:考虑到性能需求,couchdb-orm可能提供了同步和异步两种操作方式,以适应不同的应用场景。 9. *...

    Rug:PHP CouchDB 客户端

    如果你打算使用或贡献到`Rug`项目,可以通过查看源码来理解其实现原理,通过运行测试用例来检查其功能是否正常。同时,阅读文档可以帮助你更好地理解和使用这个客户端库。 总的来说,`Rug` 为 PHP 开发者提供了一个...

    mocody:实现单表设计,以及对MongoDB,CouchDB和dynamoDB的统一查询访问

    开发者可以通过阅读源码了解其实现原理,通过测试用例验证其功能,通过文档学习如何集成到自己的项目中。由于项目目前处于试验阶段,使用时需谨慎,不建议在生产环境中直接使用。随着项目的成熟,mocody有望成为一个...

    rcouch:使用钢筋静态分发Apache CouchDB

    总的来说,rcouch是针对Apache CouchDB的一个优化项目,它利用钢筋(Rebar)工具实现静态分发,简化了部署流程,提高了效率。如果你是一个CouchDB的使用者,学习rcouch可以帮助你更好地管理和扩展你的数据库服务。...

    beanbag:通用CouchDB驱动程序

    通过简单的API调用,开发者可以轻松地实现与CouchDB服务器的通信,例如: ```javascript var BeanBag = require('beanbag'); var db = new BeanBag('http://localhost:5984/mydatabase'); // 创建一个新文档 db....

    brooklyn-example-hello-world-webapp-0.6.0-rc.2.zip

    总的来说,这个布鲁克林示例结合了Brooklyn的分布式系统管理能力与Lift框架的Web开发优势,通过CouchDB实现了数据的持久化。这不仅展示了如何在Brooklyn中集成和管理Web服务,还演示了如何利用现代NoSQL数据库如...

    chttpd:用于CouchDB的可感知群集的httpd层

    CouchDB是一款用Erlang编程语言实现的开源分布式文档数据库,强调数据的可复制性和高可用性。`chttpd`的作用在于提供一个接口,使得用户可以通过HTTP协议与CouchDB进行交互,进行数据的读写、查询、备份等操作。 ##...

    数据库系统原理课件,ppt版的

    同时,也会讲解不同类型的数据库,如关系型数据库(如MySQL、Oracle)、非关系型数据库(如MongoDB、CouchDB)以及分布式数据库等。 2. **数据模型**:数据模型是数据库设计的基础,包括概念数据模型(如实体-关系...

    pouch-auth:PouchDB 和 CouchDB 的用户认证插件

    在JavaScript开发中,pouch-auth的使用需要一定的熟悉度,包括理解PouchDB和CouchDB的基本工作原理,以及如何集成和调用插件提供的API。在实际项目中,开发者通常会结合其他前端框架(如React或Angular)来构建完整...

Global site tag (gtag.js) - Google Analytics