构建无痛元数据存储的最佳实践

90 阅读9分钟

元数据是关于其他数据的数据。

但这是一个非常广泛的定义。当你开始尝试具体化时,它可能很快就会变得模糊不清。在我们与客户的接触中,我们看到 "元数据 "通常被用来描述两种不同的使用情况。

  1. 鉴证数据。这包括诸如日志文件和机器数据--例如,你想挖掘的那种数据,以分析一个安全事件。它通常是时间序列数据。

  2. 控制数据。例如,这是你可能拥有的描述某个特定用户的文件数据,其中可能包括登录凭证、账单细节、应用程序和使用数据等。

不同的行业,甚至不同的公司可能会以不同的方式定义元数据。但是在这篇文章中,我们要关注的是第二项:控制数据的使用情况。

这种类型的元数据带来了一些独特的挑战,因为虽然它"关于其他数据的数据",但它往往是关键性的任务。例如,关于一个用户的登录凭证的数据,是应用程序的登录功能所需要的。关于物品在仓库中的位置的数据,是物品被拣选和运输所需要的。

此外,它往往是关系型的。一个用户的登录凭证、账单信息和应用程序的使用数据可能都会被存储在不同的表中--可能是在不同的数据库中--但它们也都必须相互连接。设计一个能适用于这种复杂的、相互关联的数据的模式,会很快变得复杂。

那么,你是如何处理这种元数据的呢?

为你的数据找到合适的数据库

第一步是评估你的需求,并找到一个适合的数据库,而不是一个你可以让它适合的数据库。

为什么呢?因为虽然实施一个Postgres数据库(例如)可能是最快的,如果这是你最熟悉的,但从长远来看,该数据库的局限性可能最终会让你付出更多的时间。花点时间评估你的需求,并在前期寻找合适的数据库,可以确保你不会签下大量的手工工作--甚至更糟的是,迁移到一个不同的数据库--在以后的日子里。

有时,这种搜索是相对容易的。如果你试图存储时间序列格式的法医元数据,有专门的解决方案,如TimescaleDB,准备就绪,等待。

但是,事实证明,这往往是比较复杂的。例如,数据安全公司Rubrik在为他们的CDM建立元数据存储时开始使用Cassandra。乍一看,它似乎符合该公司的要求,即其数据库是可扩展的、容错的、高性能的,并且易于部署。

但是,魔鬼在细节中,当他们开始运行时,他们发现了一些问题。这里详细介绍了这些问题,但最大的问题是一致性问题。Cassandra使用墓碑--在一个固定的时间段后标记要删除的行,而不是立即删除它们--实际上可能导致被删除的行被 "复活 "并重新添加到数据库中,如果一个节点在错误的时间发生了中断。

虽然Rubrik在使用Cassandra时遇到了一些问题,但他们最终决定寻找一个分布式数据库,以满足他们在规模、容错、性能和易用性方面的需求,并且即使在节点中断的情况下也能提供更强的一致性保证。这使他们找到了CockroachDB。

也就是说,CockroachDB并不是每一个元数据使用案例的正确解决方案。一个应用程序的需求,以及在较小程度上你的开发人员的需求,应该指导你为你的元数据存储选择数据库。

设计一个周到的数据库模式

一旦你选择了你的数据库,就是设计你的模式的时候了。就像选择正确的数据库一样,花时间仔细设计你的模式会在前期花费你的时间,但从长远来看却能为你节省时间。一旦你的应用程序进入生产阶段,对你的模式进行重大修改可能是一个很大的痛苦--我们将在本文后面讨论这个问题--而周到的模式设计可以帮助你避免这种情况,至少在一段时间内。

设计模式可能是一个具有挑战性的步骤,特别是当你正在处理大量复杂和相互关联的数据时(你经常会这样做)。它需要仔细的计划和远见,因为在你的应用程序启动和运行后,不得不对模式进行重大的修改,这可能是很痛苦的(我们将在本文后面介绍这个问题)。

不幸的是,在模式设计方面没有一个放之四海而皆准的指南,因为你的模式将高度依赖于你的数据的具体情况。然而,我们已经把数据库模式设计最佳实践的快速指南放在一起,应该可以帮助你开始工作。

这也是花时间考虑你的元数据存储将如何与使用它的各种应用服务进行交互的步骤,是有意义的。如果你使用的是像CockroachDB这样的关系型数据库,数据库本身可以执行你的模式,但如果你选择的是NoSQL数据库,你的一些模式要求可能必须在应用本身中实现。

不要忘记 "人的模式"

除了设计数据库模式外,考虑我们称之为人类模式的东西也很重要,确定谁将以什么方式与什么数据进行交互,并准备相应的资源。

这里需要的东西会根据你的组织的规模而有很大的不同,但是有一项任务几乎总是要包括的,那就是创建一个数据字典,定义模式中每个表中的每一列,最好是用非技术团队成员也能理解的术语。

即使现在只有一个开发人员在接触数据,如果你的应用程序开始运行,你最终会有营销人员、分析人员、产品人员,甚至可能有高管在挖掘数据。彻底记录一切,并确保正确的访问控制到位,将确保每个人都能访问和理解他们需要的数据。

请注意,这并不意味着让所有这些人都能访问你的生产应用数据库。从长远来看,你可能希望你的团队中的大多数人都在不同的数据库中工作,因为你不希望你的应用程序的性能被(例如)分析团队的查询所影响到。理想情况下,你的生产数据库会有像CockroachDB的CDC这样的功能,可以很容易地将数据从应用数据库推送到Kafka和/或单独的分析数据库,保持两者之间的一致性,以确保你的应用和你的分析师的准确性。

模式变化应该是加法的

在一个理想的世界里,你可以设计一个完美的模式,部署你的应用程序,并且永远不需要改变任何东西。

在现实中,我很确定这种情况从未发生过。

模式变化是生活中的一个事实,随着你的应用程序的增长和变化,它们是必要的。一个好的一般规则是,这些变化应该始终是相加的。例如,你可以在表中增加一列,以适应你的应用程序的一个新功能所产生的数据。

这样做的原因是,你所有的应用服务都必须能够理解和处理你数据库中的数据。添加新的数据(可以简单地被任何不使用它的应用服务忽略)比删除数据(这将破坏任何使用它的应用服务)更可取。

不过,无论哪种方式,你几乎肯定要对你的一些应用逻辑进行修改,以说明你对数据库模式所做的修改。

与还原性变化相比,加法模式的变化问题较少,但它们往往意味着你必须想出一种方法来回填那些没有你刚刚添加的列(例如)的数据的旧行。

理想情况下,这可以逐渐发生,作为一个背景过程。例如,一个增加了图像识别功能的照片分享应用需要改变其元数据模式,以存储每张照片中的人脸数据。在添加该功能之前上传和处理的照片将缺乏这些数据,因此应用程序开发人员需要建立一个流程,逐步扫描所有的旧照片来回填这些数据。

需要这种回填数据的速度越快,这个任务就越有挑战性。

当迁移出现时,确保一致性

这并不理想,但迁移会发生。在某一点上,小的模式变化可能无法适应你的应用程序中的所有变化,而迁移可能成为必要。这可能意味着迁移到一个全新的模式,甚至是--就像Rubrik的情况--一个新的数据库。

元数据迁移是非常具有挑战性的,因为你通常需要找到一种方法来建立新旧系统之间的一致性,直到你可以完全切换到较新的系统,而且你还需要更新所有与元数据交互的应用服务,以确保它们在新模式启动和运行时可以使用。

不幸的是,这里没有什么灵丹妙药--所需要的东西在很大程度上取决于你的应用程序的具体情况和你要迁移的东西。但是,这就更有理由遵循本文前面的提示了。有了前期的充分规划,你就可以在未来几年内避免迁移的痛苦。