一个键值存储的设计
一个键值存储的设计
了解功能需求、非功能需求以及键值存储的API设计。
需求
我们列出设计键值存储以克服传统数据库问题的需求。
功能需求
功能需求如下:
- 可配置的服务: 有些应用程序可能会倾向于以更高的可用性为代价来换取强一致性。我们需要提供可配置的服务,以便不同的应用程序可以使用一系列一致性模型。我们需要严格控制可用性、一致性、成本效益和性能之间的权衡。
- 始终可写: 应用程序应始终具有写入键值存储的能力。如果用户想要强一致性,则由于CAP定理的影响,这个要求可能并不总是能够满足。
- 硬件异构性: 系统不应该有区别明显的节点。每个节点应该在功能上能够执行任何任务。尽管服务器可以是异构的,但较新的硬件可能比旧的硬件更有能力。
非功能需求
非功能需求如下:
- 可扩展性: 键值存储应该运行在数万台分布在全球的服务器上。增量可扩展性是非常可取的。我们应该根据需要添加或删除服务器,并在最小或没有服务中断的情况下进行。此外,我们的系统应该能够处理大量键值存储用户。
- 可用性: 我们需要提供连续的服务,因此可用性非常重要。这个属性是可配置的。因此,如果用户想要强一致性,我们的可用性就会较低,反之亦然。
- 容错性: 键值存储应该在服务器或其组件出现故障的情况下不间断地运行。
警告
问题
为什么我们需要在多个服务器上运行键值存储?
答案
基于单节点的哈希表可能因以下一个或多个原因而不足:无论我们得到多大的服务器,这个服务器都无法满足数据存储和查询要求;
这个超级服务器的故障将导致所有人的服务停机。
因此,键值存储应该使用许多服务器来存储和检索数据。
假设
为了使我们的设计简单,我们假设以下内容:
- 托管服务的数据中心是受信任的(非敌对的)。
- 所有所需的身份验证和授权已经完成。
- 用户请求和响应是通过 HTTPS 中继的。
API设计
与普通哈希表一样,键值存储提供了两个主要功能,即 get
和 put
。
让我们看一下API设计。
get
函数
获取值的 API 调用应该如下所示:
get(key)
我们根据参数 key
返回关联的值。
当数据被复制时,它会定位与特定键相关联的对象副本,该键对终端用户隐藏。
如果存储配置为较弱的数据一致性模型,则系统会执行此操作。
例如,在最终一致性下,可能会针对一个键返回多个值。
参数 | 描述 |
---|---|
key | 它是我们要获取value 的key 。 |
put
函数
将值放入系统的 API 调用应该如下所示:
put(key, value)
它存储与key
关联的value
。系统会自动确定数据应放置在哪里。
此外,系统通常会保留有关存储对象的元数据。
这样的元数据可以包括对象的版本。
参数 | 描述 |
---|---|
key | 它是我们要存储value 的key 。 |
value | 它是要存储在key 上的对象。 |
相关信息
问题
我们通常为数据完整性检查保留值的哈希(有时为值+关联键),此类哈希应在任何数据压缩或加密之后取还是之前取?
答案
正确的答案可能取决于具体的应用程序。
但我们可以在任何压缩或加密之前或之后使用哈希。
但我们需要始终对put
和get
操作进行一致的处理。
数据类型
键通常是键值存储中的主键,而值可以是任意的二进制数据。
提示
注意: Dynamo 使用MD5哈希在键上生成一个128位的标识符。这些标识符帮助系统确定哪个服务器节点将负责这个特定的键.
在下一课中,我们将学习如何设计我们的键值存储。
首先,我们将专注于向我们的系统添加可伸缩性、复制和数据版本控制。
然后,我们将确保功能需求并使我们的系统具备容错性。
我们首先满足一些非功能需求,因为实现我们的功能需求取决于所选择的可扩展性方法。
相关信息
注意: 本章基于 Dynamo,它是键值存储领域的一个有影响力的工作。