1.文档存储
一个承载着CouchDB服务器主机的数据库,以文档方式存储。每个文档在数据库中都有唯一的名称,CouchDB提供一个RESTful HTTP API来读取和更新(添加、编辑、删除)数据库文档。
文档是CouchDB中的主要数据单元,由任意数量的字段和附件组成。文档还包括数据库系统维护的元数据。文档字段是唯一命名的,并且包含不同类型的值(文本、数字、布尔值、列表等),并且没有对文本大小或元素数量的设置限制。
CouchDB文档更新模型是无锁且乐观的。文档编辑是通过客户机应用程序加载文档、应用更改并将它们保存回数据库来完成的。如果另一个编辑相同文档的客户端首先保存其更改,则客户端在保存时将获得编辑冲突错误。要解决更新冲突,可以打开最新的文档版本,重新应用编辑并再次尝试更新。
单个文档更新(添加、编辑、删除)要么全部更新,要么什么也不更新, 文档更新要么完全成功,要么完全失败。数据库从不包含部分保存或部编辑的文档。
2. 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
CouchDB文件被设计为能够保证系统具有所有原子性、一致性、隔离性、持久性(ACID)属性。在磁盘上,CouchDB从不覆盖提交的数据或相关结构,确保数据库文件始终处于一致的状态。这是一种“仅崩溃”的设计,CouchDB服务器不会经历关闭过程,而是简单地终止。
文档更新(添加、编辑、删除)是序列化的,但并发写的二进制 除外。数据库读取永远不会被锁住,也永远不必等待写入或其他读取者。任何数量的客户端都可以在不被锁定或被并发更新中断的情况下读取文档,即使是在同一文档上。(个人理解这里可能是脏读的形式)CouchDB读取操作使用多版本并发控制(MVCC)模型,其中每个客户端从读取操作的开始到结束都可以看到数据库的一致快照。这意味着CouchDB可以在每个文档的基础上保证事务语义。
文档通过它们的名称(文档ID)和序列ID在B-tree树中建立索引。对数据库实例的每次更新都会生成一个新的序列号。序列id稍后用于增量地查找数据库中的更改。当保存或删除文档时,这些B-tree索引将同时更新。索引更新总是发生在文件的末尾(仅追加更新)。
文档的优势在于,数据已经被方便地打包用于存储,而不是在大多数数据库系统中分散到多个表和行中。当文档被提交到磁盘时,文档字段和元数据被打包到缓冲区中,一个文档接着一个文档(有助于以后高效地构建视图)。
更新CouchDB文档时,所有数据和相关索引都被刷新到磁盘,事务提交总是使数据库处于完全一致的状态。提交分两步进行:
- 所有文档数据和相关索引更新都同步刷新到磁盘。
- 更新后的数据库头由两个连续的、相同的块组成,组成文件的第一个4k,然后同步地刷新到磁盘。
在第1步操作系统崩溃或电源故障的情况下,重新启动时只会忘记部分刷新的更新。如果在第2步(提交头文件)中发生这样的崩溃,将保留先前相同头文件的存活副本,以确保先前提交的所有数据的一致性。除了头部区域外,没有必要在崩溃或电源故障后进行一致性检查或修复。
3.压缩
偶尔的压缩可以回收被浪费的空间。按照计划,或者当数据库文件超过一定数量的浪费空间时,压缩过程将所有活动数据克隆到一个新文件中,然后丢弃旧文件。数据库始终保持在线状态,所有更新和读取都可以成功完成。只有在复制了所有数据并将所有用户转移到新文件时,才会删除旧数据库文件。
个人感觉,这里应该使用了很多技术来保障一致性,如果是在拷贝过程中文档进行了更新,官方文档没有给出来具体的解决方案。
4. 视图
ACID属性只处理存储和更新,但是我们还需要能够以有趣和有用的方式显示数据。与必须小心地将数据分解为表的SQL数据库不同,CouchDB中的数据存储在半结构化文档中。CouchDB文档是灵活的,每个文档都有自己的隐式结构,这减轻了双向复制表模式及其包含的数据的最困难的问题和陷阱。
但是,除了充当一个奇特的文件服务器之外,用于数据存储和共享的简单文档模型对于构建真正的应用程序来说过于简单——它不能完成我们想要和期望的足够多的事情。我们希望通过许多不同的方式来切分和查看我们的数据。现在需要的是一种方法来过滤、组织和报告尚未分解为表的数据。
4.1 视图模式
为了解决将结构添加回非结构化和半结构化数据的问题,CouchDB集成了一个视图模型。视图是将文档聚合和形成数据库报表的方法,是按需构建的,用于聚合、连接和形成数据库报表文档。因为视图是动态构建的,并且不影响底层文档,所以您可以拥有相同数据的任意多个不同视图表示。
视图定义严格来说是虚拟的,只显示当前数据库实例中的文档,使它们与所显示的数据分离,并与复制兼容。CouchDB视图是在特殊的设计文档中定义的,可以像常规文档一样跨数据库实例进行复制,这样不仅可以在CouchDB中复制数据,还可以复制整个应用程序设计。
4.2 JavaScript视图功能
图是使用JavaScript函数定义的,这些函数在map-reduce系统中充当映射部分。视图函数接受CouchDB文档作为参数,然后执行所需的任何计算,以确定将通过视图提供的数据(如果有的话)。它可以基于单个文档向视图添加多行,也可以完全不添加行。
4.3 View 索引
视图是数据库实际文档内容的动态表示,CouchDB使创建有用的数据视图变得很容易。但是,生成包含数十万或数百万文档的数据库视图需要时间和资源,系统不应该每次都从头开始。
为了保持视图查询的速度,视图引擎维护其视图的索引,并增量地更新它们以反映数据库中的更改。CouchDB的核心设计主要围绕高效、增量地创建视图及其索引进行优化。
视图及其函数定义在特殊的“设计”文档中,文档中可以包含任意数量的惟一命名的视图函数。当用户打开一个视图并自动更新其索引时,同一设计文档中的所有视图都被索引为单个组。
视图生成器使用数据库序列ID来确定视图组是否与数据库完全同步。如果没有,视图引擎将检查自上次刷新以来更改的所有数据库文档(按打包顺序排列)。文档按在磁盘文件中出现的顺序读取,从而降低磁盘磁头查找的频率和成本。
视图可以在刷新的同时,同时读取和查询。如果客户机正在缓慢地将大视图的内容读取出来,则可以同时为另一个客户机打开和刷新相同的视图,而不会阻塞第一个客户机。对于任何数量的并发客户机阅读器都是如此,它们可以在为其他客户机并发刷新索引时读取和查询视图,而不会给阅读器带来问题。
当视图引擎通过您的“map”和“reduce”函数处理文档时,如果存在它们的前一行值,那么它们将从视图索引中删除。如果文档是由视图函数选择的,那么函数结果将作为新行插入视图。
当将视图索引更改写入磁盘时,更新总是附加在文件末尾,这既可以减少磁盘提交期间的磁头查找时间,又可以确保崩溃和电源故障不会导致索引损坏。如果在更新视图索引时发生崩溃,则不完整的索引更新只会丢失,并从其先前提交的状态增量地重新构建。
5.安全和校验
为了保护那些可以阅读和更新的文档,CouchDB有一个简单的阅读器访问和更新验证模型,可以扩展该模型来实现定制的安全模型。
5.1管理员访问
CouchDB数据库实例具有管理员帐户。管理员帐户可以创建其他管理员帐户并更新设计文档。设计文档是包含视图定义和其他特殊公式的特殊文档,以及常规字段和blob。
5.2 更新校验
由于文档是写到磁盘上的,因此可以通过JavaScript函数动态地验证它们,以实现安全性和数据验证。当文档通过所有公式验证条件时,允许继续更新。如果验证失败,更新将中止,用户客户机将获得错误响应。用户凭证和更新后的文档都作为验证公式的输入,可以通过验证用户更新文档的权限来实现自定义安全模型。基本的author only update文档模型实现起来很简单,其中验证文档更新以检查用户是否列在现有文档的author字段中。更动态的模型也是可能的,比如检查一个单独的用户帐户配置文件的权限设置。更新验证对实时使用和复制的更新都是强制的,以确保共享、分布式系统中的安全性和数据验证。
6. 分布式更新和复制
CouchDB是一个基于对等的分布式数据库系统。它允许用户和服务器在断开连接时访问和更新相同的共享数据。然后可以在以后双向复制这些更改。CouchDB文档存储、视图和安全模型被设计为协同工作,以使真正的双向复制高效可靠。文档和设计都可以复制,从而允许将完整的数据库应用程序(包括应用程序设计、逻辑和数据)复制到笔记本电脑上脱机使用,或者复制到远程办公室的服务器上,在远程办公室中,连接速度慢或不可靠会使共享数据变得困难。复制过程是增量的。在数据库级别,复制只检查自上次复制以来更新的文档。如果复制在任何步骤失败,例如由于网络问题或崩溃,下一个复制将在最后一个检查点重新启动。可以创建和维护部分副本。复制可以通过JavaScript函数进行过滤,以便只复制特定的文档或满足特定条件的文档。这允许用户离线使用大型共享数据库应用程序的子集,同时保持与应用程序和该数据子集的正常交互。
6.1 冲突
冲突检测和管理是对任何分布式文本编辑系统都是关键问题。CouchDB存储系统将编辑冲突视为一种常见状态,而不是异常状态。冲突处理模型简单、无损,同时保留了单一的文档语义,允许分散的冲突解决。
CouchDB允许数据库中同时存在任意数量的冲突文档,每个数据库实例决定哪个文档是赢家,哪个文档是冲突。只有获胜的文档才能出现在视图中,而失败的冲突仍然可以访问,并保留在数据库中,直到在数据库压缩过程中删除或清除。因为冲突文档仍然是常规文档,所以它们像常规文档一样复制,并且遵循相同的安全性和验证规则。
当分布式编辑冲突发生时,每个数据库副本都看到相同的获胜修订,并且每个副本都有机会解决冲突。解决冲突可以手工完成,或者根据数据的性质和冲突由自动化代理完成。该系统在维护单个文档数据库语义的同时,使分散的冲突解决成为可能。
即使多个断开连接的用户或代理试图解决相同的冲突,冲突管理仍将继续工作。如果解决的冲突导致更多的冲突,系统将以相同的方式容纳它们,在每台机器上确定相同的赢家,并维护单个文档语义。
6.2 应用程序
仅使用基本复制模型,许多传统的单服务器数据库应用程序几乎不需要额外的工作就可以实现分布式。CouchDB复制被设计为可以立即用于基本的数据库应用程序,同时还可以扩展用于更复杂和功能更全面的用途。只需很少的数据库工作,就可以构建具有细粒度安全性和完整修订历史的分布式文档管理应用程序。可以实现对文档的更新来利用增量字段和blob复制,在增量字段和blob复制中,复制的更新几乎与实际的编辑差异(diffs)一样高效和增量。
7. 实施
CouchDB构建在Erlang OTP平台上,这是一种功能强大的并发编程语言和开发平台。Erlang是为实时电信应用程序开发的,特别强调可靠性和可用性。
无论是在语法还是语义上,Erlang都与C或Java等传统编程语言非常不同。Erlang使用轻量级进程和消息传递实现并发,它没有共享的状态线程,所有数据都是不可变的。Erlang的健壮性和并发性非常适合数据库服务器。
CouchDB在概念模型和实际的Erlang实现中是为无锁并发性设计的。减少瓶颈和避免锁定可以使整个系统在重负载下正常工作。CouchDB可以容纳许多客户机,它们可以复制更改、打开和更新文档,以及查询同时为其他客户机刷新索引的视图,而不需要锁。
对于更高的可用性和更多的并发用户,CouchDB是为无共享集群而设计的。在一个无共享的集群中,每台机器都是独立的,并与集群伙伴复制数据,从而允许各个服务器在零停机时间内发生故障。由于在重新启动时不需要一致性扫描和修复,如果由于数据中心断电导致整个集群失败,例如,重新启动后整个CouchDB分布式系统立即可用。
CouchDB从一开始就使用分布式文档数据库系统的一致视图构建。与将分布式特性固定在相同的遗留模型和数据库之上的繁琐尝试不同,它是经过仔细推敲的设计、工程和集成的结果。文档、视图、安全性和复制模型、特殊用途的查询语言、高效而健壮的磁盘布局以及Erlang平台的并发性和可靠性,都被小心地集成为一个可靠而高效的系统。