1.1. 技术概述

1.1.1. 文件保管

CouchDB服务器托管名为databases的数据库,这些数据库存储 文件 . 每个文档在数据库中都是唯一命名的,CouchDB提供了一个 RESTful HTTP API 用于读取和更新(添加、编辑、删除)数据库文档。

文档是CouchDB中数据的主要单位,由任意数量的字段和附件组成。文档还包括由数据库系统维护的元数据。文档字段的名称是唯一的,并且包含 varying types (文本、数字、布尔值、列表等),并且对文本大小或元素计数没有设置限制。

CouchDB文档更新模型是无锁和乐观的。文档编辑是由客户端应用程序加载文档、应用更改并将其保存回数据库进行的。如果编辑同一文档的另一个客户机先保存了他们的更改,则该客户机在保存时会出现编辑冲突错误。若要解决更新冲突,可以打开最新的文档版本,重新应用编辑并重试更新。

单个文档更新(添加、编辑、删除)要么全部成功,要么完全失败。数据库从不包含部分保存或编辑的文档。

1.1.2. 酸性质

CouchDB文件系统的所有功能 Atomic Consistent Isolated Durable (ACID )属性。在磁盘上,CouchDB从不覆盖提交的数据或相关结构,以确保数据库文件始终处于一致状态。这是一个“仅崩溃”的设计,CouchDB服务器不经过关闭过程,它只是被终止。

文档更新(添加、编辑、删除)都是序列化的,除了并发写入的二进制blob。数据库读取器从不被锁定,也不必等待编写器或其他读取器。任何数量的客户机都可以在不被锁定或被并发更新中断的情况下读取文档,即使在同一个文档上也是如此。CouchDB读取操作使用 Multi-Version Concurrency Control (MVCC )在该模型中,每个客户端从读取操作的开始到结束都可以看到数据库的一致快照。这意味着CouchDB可以保证基于每个文档的事务语义。

文档已编入索引 B-trees 通过它们的名称(DocID)和序列ID。对数据库实例的每次更新都会生成一个新的序列号。序列ID稍后用于增量查找数据库中的更改。保存或删除文档时,这些B树索引会同时更新。索引更新总是发生在文件末尾(仅追加更新)。

文档的优势在于,在大多数数据库系统中,数据已经被方便地打包用于存储,而不是分散在多个表和行中。当文档提交到磁盘时,文档字段和元数据按顺序一个接一个地打包到缓冲区中(有助于以后高效地构建视图)。

当CouchDB文档被更新时,所有数据和相关联的索引都被刷新到磁盘上,事务性提交总是使数据库处于完全一致的状态。提交分两步进行:

  1. 所有文档数据和关联的索引更新将同步刷新到磁盘。

  2. 更新后的数据库头被写入两个连续的相同的块,组成文件的前4k,然后同步刷新到磁盘。

如果在步骤1中发生操作系统崩溃或电源故障,部分刷新的更新将在重新启动时被忽略。如果在第2步(提交头)期间发生这样的崩溃,将保留以前相同头的一个幸存副本,以确保先前提交的所有数据的一致性。除了收割台区域,在发生崩溃或电源故障后,不需要进行一致性检查或修复。

1.1.3. 压实

通过偶尔的压实来回收浪费的空间。按计划执行,或者当数据库文件超过一定数量的浪费空间时,压缩过程会将所有活动数据克隆到新文件中,然后丢弃旧文件。数据库始终保持完全在线,所有更新和读取都可以成功完成。只有当所有数据都已复制并且所有用户都转换到新文件时,旧数据库文件才会被删除。

1.1.4. 意见

ACID属性只处理存储和更新,但我们还需要以有趣和有用的方式显示数据的能力。与SQL数据库不同,SQL数据库中的数据必须仔细地分解成表,CouchDB中的数据存储在半结构化文档中。CouchDB文档是灵活的,每个文档都有自己的隐式结构,这缓解了双向复制表模式及其包含的数据的最困难的问题和陷阱。

但是除了充当一个奇特的文件服务器之外,用于数据存储和共享的简单文档模型太简单了,无法在其上构建真正的应用程序——它根本无法完成我们想要和期望的事情。我们希望用多种不同的方式对数据进行切分和切分。我们需要的是一种方法来过滤、组织和报告尚未分解成表的数据。

参见

观景指南

1.1.4.1. 视图模型

为了解决向非结构化和半结构化数据中添加结构的问题,CouchDB集成了一个视图模型。视图是对数据库中的文档进行聚合和报告的方法,是按需构建的,用于聚合、联接和报告数据库文档。因为视图是动态生成的,不会影响基础文档,因此可以根据需要对同一数据使用任意多个不同的视图表示形式。

视图定义是严格虚拟的,只显示当前数据库实例中的文档,使其与显示的数据分离,并与复制兼容。CouchDB视图在special中定义 设计文件 并且可以像普通文档一样跨数据库实例进行复制,这样不仅可以在CouchDB中复制数据,而且可以复制整个应用程序设计。

1.1.4.2. JavaScript视图函数

视图是使用JavaScript函数作为 map-reduce system . 一 view function 以一个CouchDB文档作为参数,然后进行所需的任何计算,以确定要通过视图提供的数据(如果有的话)。它可以基于单个文档向视图中添加多行,也可以根本不添加行。

参见

查看函数

1.1.4.3. 查看索引

视图是数据库实际文档内容的动态表示,CouchDB使创建有用的数据视图变得容易。但是,生成包含数十万或数百万个文档的数据库视图需要耗费大量的时间和资源,而不是系统每次都应该从头开始。

为了保持视图查询的快速性,视图引擎维护其视图的索引,并增量更新它们以反映数据库中的更改。CouchDB的核心设计在很大程度上是围绕高效、增量地创建视图及其索引的需要而优化的。

视图及其函数在特殊的“设计”文档中定义,设计文档可以包含任意数量的唯一命名的视图函数。当用户打开一个视图并自动更新其索引时,同一设计文档中的所有视图都将作为单个组编入索引。

视图生成器使用数据库序列标识来确定视图组是否与数据库完全同步。否则,视图引擎将检查自上次刷新以来更改的所有数据库文档(按压缩顺序排列)。文档的读取顺序与它们在磁盘文件中的顺序一致,从而降低了磁盘磁头查找的频率和成本。

在刷新视图的同时,可以同时读取和查询视图。如果一个客户机正在缓慢地流出一个大视图的内容,那么可以同时为另一个客户机打开和刷新同一个视图,而不会阻塞第一个客户机。对于任何数量的同时进行的客户机读卡器来说都是如此,他们可以在为其他客户机同时刷新索引的同时读取和查询视图,而不会给读取器带来问题。

当视图引擎通过“map”和“reduce”函数处理文档时,它们以前的行值(如果存在)将从视图索引中删除。如果文档是由视图函数选择的,则函数结果将作为新行插入视图中。

当视图索引更改写入磁盘时,更新总是附加在文件末尾,这样既可以减少磁盘提交期间的磁盘头查找时间,又可以确保崩溃和电源故障不会导致索引损坏。如果在更新视图索引时发生崩溃,则不完整的索引更新将丢失,并从以前提交的状态开始增量重建。

1.1.5. 安全和验证

为了保护谁可以读取和更新文档,CouchDB有一个简单的读卡器访问和更新验证模型,可以扩展该模型来实现定制的安全模型。

参见

/db/_security

1.1.5.1. 管理员访问

CouchDB数据库实例具有管理员帐户。管理员帐户可以创建其他管理员帐户并更新设计文档。设计文档是包含视图定义和其他特殊公式以及常规字段和blob的特殊文档。

1.1.5.2. 更新验证

当文档写入磁盘时,可以通过JavaScript函数动态验证文档的安全性和数据验证。当单据通过所有公式验证条件时,允许继续更新。如果验证失败,更新将中止,用户客户端将获得错误响应。

用户的凭据和更新的文档都作为验证公式的输入提供,并且可以通过验证用户更新文档的权限来实现自定义安全模型。

基本的“仅限作者”更新文档模型实现起来很简单,在该模型中,验证文档更新以检查用户是否列在现有文档的“作者”字段中。更多的动态模型也是可能的,比如检查一个单独的用户帐户配置文件的权限设置。

对实时使用和复制的更新都强制执行更新验证,以确保共享、分布式系统中的安全性和数据验证。

1.1.6. 分布式更新和复制

CouchDB是一个基于对等机的分布式数据库系统。它允许用户和服务器在断开连接时访问和更新相同的共享数据。这些更改可以在以后双向复制。

CouchDB文档存储、视图和安全模型旨在协同工作,使真正的双向复制高效可靠。文档和设计都可以复制,允许将完整的数据库应用程序(包括应用程序设计、逻辑和数据)复制到笔记本电脑以供脱机使用,或者复制到远程办公室的服务器上,这些服务器的连接速度慢或不可靠使数据共享变得困难。

复制过程是增量的。只在上次更新的复制级别检查复制。如果复制在任何步骤失败,例如由于网络问题或崩溃,下一个复制将在最后一个检查点重新启动。

可以创建和维护部分副本。可以通过JavaScript函数过滤复制,以便只复制特定文档或满足特定条件的文档。这允许用户将大型共享数据库应用程序的子集脱机供自己使用,同时保持与应用程序和该数据子集的正常交互。

1.1.6.1. 冲突

冲突检测和管理是任何分布式编辑系统的关键问题。CouchDB存储系统将编辑冲突视为常见状态,而不是异常状态。冲突处理模型简单且“无损”,同时保留了单个文档语义并允许分散冲突解决。

CouchDB允许在数据库中同时存在任意数量的冲突文档,每个数据库实例都决定哪个文档是“赢家”,哪些是冲突。只有获胜的文档才能出现在视图中,而“丢失”冲突仍然可以访问,并保留在数据库中,直到在数据库压缩过程中删除或清除为止。因为冲突文档仍然是常规文档,所以它们与常规文档一样进行复制,并受相同的安全和验证规则的约束。

当发生分布式编辑冲突时,每个数据库副本都看到相同的成功修订,并且每个副本都有机会解决冲突。可以手动解决冲突,也可以通过自动代理来解决,具体取决于数据和冲突的性质。该系统在维护单文档数据库语义的同时,使分散的冲突解决成为可能。

即使多个断开连接的用户或代理试图解决相同的冲突,冲突管理仍将继续工作。如果已解决的冲突导致更多冲突,系统将以相同的方式容纳它们,在每台计算机上确定相同的赢家,并维护单个文档语义。

1.1.6.2. 应用

只需使用基本的复制模型,许多传统的单服务器数据库应用程序就可以实现分布式,而几乎不需要额外的工作。CouchDB复制被设计成对基本数据库应用程序立即有用,同时还可以扩展以用于更精细和功能更全面的用途。

只需很少的数据库工作,就可以构建具有细粒度安全性和完整修订历史记录的分布式文档管理应用程序。可以实现对文档的更新来利用增量字段和blob复制,其中复制的更新几乎与实际的编辑差异(“diff”)一样高效和增量。

1.1.7. 实施

CouchDB建立在 Erlang OTP platform ,一个功能性、并发编程语言和开发平台。Erlang是为实时电信应用开发的,它非常强调可靠性和可用性。

无论是在语法还是语义上,Erlang都与C或Java等传统编程语言有很大的不同。Erlang使用轻量级的“进程”和消息传递来实现并发,它没有共享状态线程,所有数据都是不可变的。Erlang健壮、并发的特性非常适合于数据库服务器。

在概念模型和实际的Erlang实现中,CouchDB是为无锁并发而设计的。减少瓶颈和避免锁可以使整个系统在高负载下正常工作。CouchDB可以容纳许多客户机复制更改、打开和更新文档、查询索引同时为其他客户机刷新的视图,而不需要锁。

为了获得更高的可用性和更多的并发用户,CouchDB是为“无共享”集群而设计的。在一个“无共享”的集群中,每台机器都是独立的,并与它的集群伙伴一起复制数据,允许单个服务器出现故障而无需停机。而且,由于重新启动时不需要进行一致性扫描和修复,因此,如果整个集群发生故障(例如,由于数据中心断电),整个CouchDB分布式系统在重新启动后立即可用。

CouchDB从一开始就构建了一个一致的分布式文档数据库系统。与将分布式功能附加到相同的遗留模型和数据库之上的繁琐尝试不同,它是精心设计、工程设计和集成的结果。文档、视图、安全和复制模型、专用查询语言、高效可靠的磁盘布局以及Erlang平台的并发性和可靠性都经过了精心的集成,以构建一个可靠高效的系统。