分享到

简介

数据库从不孤单。用户、应用程序、脚本,甚至其他数据库都将信息馈入其中并从中提取信息,就像生物消耗和分配环境能量——以及彼此的能量一样。没有哪个数据库的规模或复杂性可以与地球的全球生态系统相提并论,但设计和支持信息系统仍然与照料较小的生态系统(如花园、温室或玻璃容器)有许多相似之处。

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

Animal, vegetable, and mineral modes

“动物”似乎描述了一种活跃的组织原则,嵌入(或者委婉地说,纠缠)在运营流程和工作流程中,经过调整、编程——总之,是专用的。“动物”方法在围绕单个数据库作为信息流的收集器和单一事实来源而显式构建的、高度集中的系统或子系统中表现出色。如果失去这种关注,“动物”数据库可能会变得更像一只大熊猫:行动迟缓、维护成本高昂,并且是后勤和官僚主义的噩梦。

更“植物”类型的数据库组织它获取的数据,仅此而已,约束和提炼信息,而不对其采取积极行动。这些数据库用适应性换取集中化和对工作流程的积极控制,收集和组织信息,而不在更严格的数据库结构中编码行为和使用假设。在数据库不是唯一的信息处理场所,或者较大的团队和沟通结构相互作用的系统中,使用不太编程的数据库(将其视为一个组织原则,而不是唯一的组织原则)可能会更容易。

还有其他“矿物”数据库设计甚至放弃了对信息的最低限度的权威,仅提供具有最基本结构的存储,例如五千年前的泥板,苏美人在其上盖章了从分类账到投诉的所有内容。有时情况确实只需要一个 符合 ACID 标准的 电子表格,但更仔细地查看系统是很有必要的。也可能现有的“矿物”数据库的实现未能考虑或笨拙地近似了更复杂的数据模型,或者部分或全部数据模型本身不适合关系表示。

数据库,复数

每个与数据库交互的程序或系统——不排除设计人员、用户或开发人员——也具有生态角色,消耗和生成信息,组合信息,分离信息,为了好的或坏的目的添加或消除细微差别。这些交互系统中的许多系统都有自己的数据模型,其中目标系统的数据模型的部分或全部现在构成一个组件(有时是通过众所周知的“雾里看花”,任何曾经诅咒过意外的 VARCHAR(20) 的人都可以证明这一点)。

这些连接意味着数据库设计必须经常适应至少一些假设,如果不是结构元素,也必须适应它们自身之外的其他数据模型。信息被拆分:一个数据库中的用户和预订,另一个数据库中的酒店空房情况,航空公司的航班预订以及用户和预订方面的重复信息。模式变得纠缠不清,一个数据库中的更改会影响其他数据库。

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

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

专用解决方案

与任何其他事物一样,参照完整性是一个可以协商的约束,如果能获得足够的回报,牺牲它也是一种选择。有时,如果数据模型在图论意义上足够简单,实体很少,实体之间的连接很少或主要是分层连接,或者两者兼而有之,那么甚至不会提出这个问题。性能和可伸缩性要求也可以为引入关系模型的替代方案提供理由,其中数据模型的某些部分表示的真实信息量更大,流量更快,而这些信息量和流量无法在 RDBMS 中轻松容纳。

00 年代后半期见证了这些替代方案的寒武纪大爆发。突然出现了“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,即提取-转换-加载,即使在没有发生提取或转换的情况下也是如此。典型的 ETL 过程是一个 cron 作业或计划任务,它从外部系统下载存档数据导出,通常是平面分隔格式,如 CSV 或 TSV。记录可能会在 ETL 任务将其写入数据库时进行转换,或者,违反首字母缩略词,在之后进行批量转换。当涉及到与现有数据的连接时,批量转换尤其有用,因为数据库可以一次优化数千行的连接,比数千次单行连接更有效。

Integrating external information

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

但是,第三方 ETL 自动化正在成为一个可行的商业领域,尤其是在越来越多的数据库托管在云端的情况下。如果您有许多不同的传入流或严格的法规遵从性约束,那么值得研究这些服务。它们并没有做任何您无法使用现有工具做到的事情——问题是您是否有时间自己实施和维护足够强大的 ETL 流程。

联邦:统一的信息来源

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

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

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

“联邦”架构的概念源于区域和中央(联邦)政府共存的双重政府形式,并且像其他系统设计技术一样,其目的是管理复杂性。各个子系统的用户在这些子系统中工作和使用这些子系统;那些只关心整体运行的人与整体互动。就生态角色而言,这非常像“动物”模式的数据库操作。联邦数据库是其所处系统的中心。它将信息流吸引到自身并贯穿自身,建立连接,编码对附属模式的期望。但在可以蓬勃发展此类野兽的信息生态系统中,SQL/MED 是控制不同数据源的强大工具。

关于作者
Dian Fay

Dian Fay

Dian 并没有完全计划从大学辍学来专门研究 SQL 和后端开发,但事情就是这样发生的。十五年后,她设计的数据库支持从工业物流和可追溯性系统到百万级用户的社交媒体游戏的一切。她是 MassiveJS 的当前维护者,MassiveJS 是一个用于 Node.js 的开源数据映射器,专注于充分利用 PostgreSQL。