分享到

简介

数据库从不孤立。用户、应用程序、脚本,甚至其他数据库都会向其输入和提取信息,就像生物消耗和分配环境能量(以及彼此的能量)一样。没有哪个数据库能在规模或复杂性上与地球的全球生态系统相匹配,但设计和支持信息系统仍与维护一个小生态系统(如花园、温室或动物饲养箱)有诸多相似之处。

经典的生态划分也可以应用于数据库在信息系统中的角色:动物、植物还是矿物?确定哪种模式适用于给定的数据模型需要尽可能地了解其所处的环境。

Animal, vegetable, and mineral modes

“动物”似乎描述了一种活跃的组织原则,它嵌入(或者说,更不客气地说,纠缠)在操作流程和工作流中,经过调整、编程——简而言之,就是专业化的。“动物”方法在围绕单个数据库作为信息流的收集者和单一真相来源而明确构建的、高度集中的系统或子系统中表现出色。失去这种专注,“动物”数据库就有可能变成一只大熊猫:行动迟缓、维护成本高昂,而且是物流和官僚噩梦。

更像“植物”的数据库只组织它所获得的数据,不多不少,它约束和提炼信息,但不对其采取积极行动。这些数据库以适应性换取了对工作流的集中和主动控制,收集和组织信息,而不将行为和使用假设编码在更僵化的数据库结构中。在数据库不是信息处理唯一场所,或者有更大的团队和沟通结构交互的系统中,处理一个被视为“一个”而不是“唯一”组织原则的、编程较少的数据库可能会更容易。

还有一些“矿物”数据库设计甚至放弃了对信息的最小权限,只提供具有最基本结构的存储,就像五千年前苏美尔人刻写从账本到抱怨的所有内容的泥板一样。有时确实只需要一个ACID 兼容的电子表格,但更仔细地审视系统是非常有必要的。也可能现有的“矿物”数据库实现未能考虑到或笨拙地近似了更复杂的数据模型,或者数据模型本身的一部分或全部不适合关系表示。

多个数据库

每个与数据库交互的程序或系统——不排除设计者、用户或开发者——也都有一个生态角色,它们消费和生成信息,组合、分离信息,增减细微之处,无论是好是坏。许多这些交互系统都有自己的数据模型,目标系统数据模型的一部分或全部现在构成了其中的一个组件(有时是透过传说中的暗玻璃,就像任何曾经诅咒过意外的VARCHAR(20)的人都能证明的那样)。

这些连接意味着数据库设计必须经常适应至少一些假设,如果不是其外部其他数据模型的结构元素的话。信息被分割:用户和预订在一个数据库中,酒店空房信息来自另一个数据库,航班预订在航空公司端复制,并在用户和预订端也进行复制。模式变得纠缠不清,一个数据库的更改会对其他数据库产生影响。

管理更多的事物以及它们之间更多的交互总是更加困难,尤其是在多个存储中分割数据模型会产生深远的影响。用模式更安全地封装和处理完全关系模型的分区,所有主要的 RDBMS 都除了 MySQL 支持。但情况还是会发生。有些信息更适合非关系结构。有些信息已经分散在属于其他系统的数据库中,或者采用面向服务的架构(宏观或微观)使得分裂不可避免。更严格的弹性要求需要网络化、冗余存储。数据模型现在比以往任何时候都更需要考虑分布在多个交互式数据存储中。

分割数据模型最主要的牺牲是参照完整性。在单个数据库中,服务器可以阻止违反外键约束的操作,例如插入或更新具有不存在的父 ID 的记录,或删除其他记录所依赖的记录。将数据模型的一部分移到另一个存储中,那么维护正确性就成为你(和你的团队)的问题。

专业解决方案

和其他任何东西一样,参照完整性是一个可协商的约束,如果能获得足够的回报,牺牲它也是一个选择。有时甚至不是一个需要提出的问题,如果数据模型在图论意义上足够简单,实体很少,实体之间的连接很少或主要是层级关系,或者两者兼有。性能和可扩展性要求也可以支持引入关系模型的替代方案,即数据模型的某些部分以比 RDBMS 能够轻松容纳的更高容量和更快变化的速度表示真实信息。

2000 年代后期,这些替代方案出现了寒武纪大爆发。突然出现了存储文档、图、键值对的“NoSQL”数据库。列式存储通过将表侧向放置并建模扁平的、非规范化数据实现了惊人的性能。新来者拥抱了跨网络服务器的横向扩展,抛弃了 ACID 手册,转而支持 BASE(“基本可用、软状态、最终一致性”),并为 SQL 之外的概念开发了 API 和领域特定语言。不仅如此,围绕数据存储的对话重塑模糊了数据库作为概念的边界。Kafka 这样的流处理器是数据库吗?ElasticSearch 这样的搜索引擎呢?它们都从根本上促进了信息的存储和检索;讨论它们都需要引用大量的数据库技术语言。更根本的是,它们都是解决特定数据建模问题的方案。

如果您需要存储和处理...请考虑...
具有少量相互连接的层次结构、原始结构化文档或至少有一些共同字段的对象文档数据库(Couchbase、MongoDB)
大量“扁平”数据,例如仪器读数或结构化分析列式数据库(Cassandra、HBase)、时间序列数据库(TimescaleDB、InfluxDB、Druid)
通过键标识且仅通过该键查询的记录键值存储(Redis、LevelDB)、缓存(memcached)
记录之间具有点对点导航的复杂关系图数据库(OrientDB、Neo4j、TerminusDB)
按接收顺序的瞬时数据流流处理器和队列(Kafka、RabbitMQ、ZeroMQ)
文件。大量大量的文件云文件存储(Google Cloud Storage、Amazon S3 和 Athena)
非结构化文档,或具有高度可变模式的结构化文档搜索引擎(ElasticSearch、Solr)、内容存储库(Jackrabbit)
关系型数据,在行星规模下NewSQL 高度分布式关系数据库(VoltDB、Spanner)
以上至少有几个多模型数据库(FaunaDB、ArangoDB)

请注意,以上仅为示例,并非推荐!Kristof Kovacs 还维护了一份更详细的许多 NoSQL 选项总结,从流行的到鲜为人知的都有。

默认选项

如果你不需要存储至少千兆字节的例外,而这些例外又符合关系数据模型,你甚至可能不需要放弃 ACID 和参照完整性!关系数据库在全文搜索和存储结构化或非结构化文档方面通常非常强大;特别是 PostgreSQL 对 JSON 的处理非常广泛,具有可索引的二进制存储和丰富的查询工具集,使得混合关系-文档策略变得实用。Postgres 和其他 RDBMS 都通过服务器组件、扩展或存储引擎支持其他模型,其中一些专用存储(如 TimescaleDB)是建立在关系数据库之上的。

因此,尽管数十个营销部门竭尽全力,那个古老而拥有半个世纪历史的 RDBMS 仍然是首选的通用数据存储,非关系型解决方案则找到了适合其优势的专业利基。NoSQL 数据库可以做许多关系型数据库无法轻松或根本无法做到的事情,但在可预见的未来,关系数据库仍将存在。通过服务器调优、索引和表分区,单个关系数据库可以应对除最繁重工作负载之外的所有情况。当这仍不足以应对时,还有复制。

复制与架构

深入介绍复制技术超出了数据建模指南的范围,但它们的使用会带来无法忽视的后果。复制的数据库不仅仅是变得更大:一旦数据存储联网,它就不再是整个系统架构的单一元素。复制引入了一整套新的关于延迟、网络分区、维护等方面的考虑。

最常见的复制形式涉及仅向单个服务器写入数据。主服务器将更改转发给一个或多个副本服务器,这些副本服务器要么待命以在主服务器宕机时替换它(故障转移),要么承担响应读取查询的工作。在后一种情况下,网络延迟可能意味着更改可能不会立即可见,但由于它们只单向流动,因此一致性仍然得到保证。这种读写分离自然而然地适用于在适当的情况下通过视图表示合并的实体,尤其是在软件系统中适用于命令查询职责分离,这是一种设计模式,可以帮助控制仅与检索或存储相关的复杂性。

在另一种“多主”复制模式中,数据可以写入和读取多个服务器,这些服务器联网后,在繁重的工作负载下比单个服务器更具弹性。然而,达成共识是复杂的,并且实现更高水平的写入验证以保证持久性可能会很慢。这往往需要更简单的数据模型和对冲突和回滚更精细的处理。

大多数 NoSQL 数据存储都是为集群设计的,有些甚至到了在单台计算机上运行几乎是事后才考虑的地步。特别是,NoSQL 带来了分片的概念,即将表的各个分区从集群中的不同节点提供服务。分片是这些数据库实现规模的主要因素,但如果没有复制,失去一个节点仍然意味着数据丢失。大多数 NoSQL 数据库提供基本复制,通常具有自动故障转移功能。少数数据库,如 Cassandra 和 Couchbase,使用多个主节点。

CAP 定理

他的“CAP 定理”(一致性、可用性、分区容错性:三选二)至今仍有共鸣,但就像动物/植物/矿物三分法一样,它是一个优雅的过度简化——不多不少。

Martin Kleppmann 在 2015 年详细描述了 CAP 的缺点,这建立在 Coda Hale 早期澄清“三选二”方面的努力之上。Brewer 本人也曾宣称 Google 的 Spanner 数据库“实际上是 CA”,凭借 Google 网络的巨大规模克服了 AP/CP 的二分法。

集成外部信息

信息很少只在系统数据库与其用户之间流通。大多数信息系统都是开放系统,数据从其他信息系统流入并流出。这些流程通常适合自动化,达到一定的量级后几乎是强制性的;手动数据输入是最后的手段。有时,外部信息源是常开的,有队列、流处理器或专用守护进程在记录到达时添加记录,但一次不会做太多。然而,有时实时数据可能不可用或根本不必要——月度销售额或昨天的网站分析不需要精确到秒。

批量数据摄取过程通常被称为 ETL,即 Extract-Transform-Load(提取-转换-加载),即使在没有发生提取或转换的情况下也是如此。典型的 ETL 过程是一个 cron 作业或计划任务,它从外部系统下载存档数据导出,通常是像 CSV 或 TSV 这样的扁平分隔格式。记录可以由 ETL 任务在将其写入数据库时进行转换,或者,与首字母缩写词相反,在之后进行批量转换。批量转换在涉及与现有数据连接时特别有用,因为数据库可以更有效地一次优化数千行的连接,而不是数千次单行连接。

Integrating external information

数据导入的第一方工具各不相同。专有 RDBMS 通常包含专门的 ETL 管理程序,例如 SQL Server Integration Services 或 Oracle Data Integrator,而主要的开源和 NoSQL 选项通常只提供基本的批量文件加载工具,如 mysqlimportmongoimport,或者 PostgreSQL 和 Cassandra 中的服务器端 COPY 命令(Postgres 还在 psql 客户端中提供了客户端 \copy 指令)。

然而,第三方 ETL 自动化正在成为一个可行的商业利基,尤其是在越来越多的数据库托管在云端的情况下。如果您有大量不同的传入流或严格的法规遵从性限制,那么调查这些服务可能值得。它们所做的一切您都可以用现有工具完成——问题是您是否有时间自行实施和维护足够健壮的 ETL 流程。

联邦:统一信息源

ETL 并不是唯一的选择。2003 年,SQL 标准引入了一个名为 SQL/MED 的扩展,用于外部数据管理。文件、其他数据库、其他关系型或非关系型 DBMS、REST 端点、目录服务——所有这些以及更多都涉及看起来很像列和行的数据集,至少从正确的角度来看是这样。任何足够像列和行的东西都可以通过 SQL 进行查询,即使不能直接管理。数据库向用户和其他外部系统呈现单一界面,同时将请求和更改路由到适当的目的地。

SQL/MED 最初由 IBM 的 DB2 实现,但其他数据库用了几年时间才赶上。目前,Oracle 支持对平面文件进行读写访问,称之为“外部表”,而 SQL Server 可以连接到“链接服务器”,只要它们符合 Microsoft 的 OLEDB API。

真正有趣的事情发生在开源 RDBMS 中。PostgreSQL 在 9.1 版本中引入了外部数据包装器,并不断扩展其功能,而 MariaDB 的CONNECT 存储引擎可以封装多种数据源。此外,Postgres 和 MariaDB 的实现都是可扩展的:如果您有现有包装器无法处理的外部数据格式,您可以自己编写。Postgres 社区甚至开发了一个名为Multicorn的 Python 框架,以简化原本基于 C 语言的外部数据包装器开发过程。

“联邦”架构的理念源于地方政府和中央(联邦)政府并存的双重政府形式,与其他系统设计技术一样,其目的是管理复杂性。各个子系统的用户在其子系统内部和与子系统协同工作;而那些只关心整体运行的人则与整体交互。在生态角色方面,这非常类似于数据库操作的“动物”模式。联邦数据库是其所在系统的核心。它吸引信息流流向自身并穿过自身,建立连接,编码辅助模式的预期。但在这种“野兽”可以茁壮成长的信息生态系统中,SQL/MED 是一个用于整合不同数据源的强大工具。

作者简介
Dian Fay

戴安·费伊

Dian 并没有计划辍学专门研究 SQL 和后端开发,但事情就是这样发生了。十五年后,她设计的数据库支持从工业物流和可追溯系统到拥有百万用户的社交媒体游戏等各种应用。她是 MassiveJS 的当前维护者,这是一个专注于充分利用 PostgreSQL 的 Node.js 开源数据映射器。
© . This site is unofficial and not affiliated with Prisma Data, Inc.