本节主要介绍DynamoDB 基本概念、核心组件、数据结构、Api
DynamoDB 基本概念
DynamoDB 是 AWS 独有的完全托管的 NoSQL Database。它的思想来源于 Amazon 2007 年发表的一篇论文:Dynamo: Amazon’s Highly Available Key-value Store。在这篇论文里,Amazon 介绍了如何使用 Commodity Hardware 来打造高可用、高弹性的数据存储。想要理解 DynamoDB,首先要理解 Consistent Hashing。Consistent Hashing 的原理如下图所示:
它的概念是:
我有一个足够大的Keyspace(2的160次方,比较一下:IPv6是2的128次方),我们记作X。
然后将X放在一个环形的空间里划分成大小相等的Y个 Partition,依次循环排列(如图),每个 Partition 由一个Vnode(Riak的概念)管理,
当你有M个Database Server(Node),Y个Vnode再平均映射到M个Node上。
当数据要插入时,将其主键(Hash Key)映射到K中的一个地址(Addr),对应到某个Vnode,再进一步对应到某个Node,如果这个数据需要N个Replica,则将数据写入Addr(Vnode a),Addr + 1(Vnode b), …,Add + N(Vnode n)。
这里,M就是你的Shards,N是Replica。
以后添加新的Node时,映射发生变化,只需要把相应的变化了的Vnode迁移到新的Node上即可。在这种结构下,Sharding/Replica对程序员基本上是透明的。
DynamoDB 核心组件
基本 DynamoDB 组件包括:表、项目、属性
表 - 类似于其他数据库系统,DynamoDB将数据存储在表中。表是数据的集合。(类似于关系型数据库中的表)
项目 - 每个表包含多个项目。项目是一组属性,具有不同于所有其他项目的唯一标识。(类似于其他数据库系统中的行、记录或元组。)
属性 - 每个项目包含一个或多个属性。属性是基础的数据元素,无需进一步分解。(类似于其他数据库系统中的字段或列。)
下图是一个名为 People 的表,其中显示了一些示例项目和属性:
请注意有关 People 表的以下内容:
表中的每个项目都有一个唯一的标识符或主键,用于将项目与表中的所有其他内容区分开来。在 People 表中,主键包含一个属性 (PersonID)。
与主键外不同,People表是无架构的,这表示属性及其数据类型都不需要预先定义。每个项目都能拥有其自己的独特属性。
大多数属性是标量类型的,这表示它们只能具有一个值。字符串和数字是标量的常见示例。
某些项目具有嵌套属性 (Address)。DynamoDB 支持最高 32级深度的嵌套属性。
这里,我们将看到第一个概念:主键。
主键
创建表时,除表名称外,您还必须指定表的主键。主键唯一标识表中的每个项目,因此,任意两个项目的主键都不相同。
DynamoDB 支持两种不同类型的主键:
分区键 - 简单的主键,由一个称为分区键的属性组成。
如果表具有简单主键(只有分区键),DynamoDB 将根据其分区键值存储和检索各个项目。同时,DynamoDB 使用分区键的值作为内部哈希函数的输入值,从而将项目写入表中。哈希函数的输出值决定了项目将要存储在哪个分区。
要从表中读取某个项目,必须为该项目指定分区键值。DynamoDB 使用此值作为其哈希函数的输入值,从而生成可从中找到该项目的分区。(此时,分区键必须是唯一的,不可重复。)
下图显示了名为 Pets 的表,该表跨多个分区。表的主键为 AnimalType(仅显示此键属性)。在这种情况下,DynamoDB 会根据字符串 Dog 的哈希值,使用其哈希函数决定新项目的存储位置。请注意,项目并非按排序顺序存储的。每个项目的位置由其分区键的哈希值决定。
分区键和排序键 - 称为复合主键,此类型的键由两个属性组成。第一个属性是分区键,第二个属性是排序键。
DynamoDB 使用分区键值作为对内部哈希函数的输入。来自哈希函数的输出决定了项目将存储到的分区(DynamoDB 内部的物理存储)。具有相同分区键的所有项目按排序键值的排序顺序存储在一起。两个项目可具有相同的分区键值,但这两个项目必须具有不同的排序键值。
为将某个项目写入表中,DynamoDB 会计算分区键的哈希值以确定该项目的存储分区。在该分区中,可能有几个具有相同分区键值的项目,因此 DynamoDB 会按排序键的升序将该项目存储在其他项目中。
要读取表中的某个项目,您必须为该项目指定分区键值和排序键值。DynamoDB 会计算分区键的哈希值,从而生成可从中找到该项目的分区。
如果我们查询的项目具有相同的分区键值,则可以通过单一操作 (Query) 读取表中的多个项目。DynamoDB 将返回具有该分区键值的所有项目。或者,也可以对排序键应用某个条件,以便它仅返回特定值范围内的项目。
假设 Pets 表具有由 AnimalType(分区键)和 Name(排序键)构成的复合主键。
下图显示了 DynamoDB 写入项目的过程,分区键值为 Dog、排序键值为 Fido。
为读取 Pets 表中的同一项目,DynamoDB 会计算 Dog 的哈希值,从而生成这些项目的存储分区。然后,DynamoDB 会扫描这些排序键属性值,直至找到 Fido。
要读取 AnimalType 为 Dog 的所有项目,您可以执行 Query 操作,无需指定排序键条件。默认情况下,这些项目会按存储顺序(即按排序键的升序)返回。或者,您也可以请求以降序返回。
要仅查询某些 Dog 项目,您可以对排序键应用条件(例如,仅限 Name 在 A 至 K 范围内的 Dog 项目)。
Note
每个主键属性必须为标量(表示它只能具有一个值)。主键属性唯一允许的数据类型是字符串、数字和二进制。对于其他非键属性没有任何此类限制。
DynamoDB 会自动分配足够的存储,每个分区键值的非重复排序键值无数量上限。所以即使需要在 Dog 表中存储数十亿 Pets项目,DynamoDB 也能这一需求。
二级索引
DynamoDB支持在一个表上创建一个或多个二级索引。利用 secondary index,除了可对主键进行查询外,还可使用替代键查询表中的数据。
DynamoDB 支持两种索引:
Global secondary index - 一种带有可能与表中不同的分区键和排序键的索引。
Local secondary index - 一种分区键与表中的相同但排序键与表中的不同的索引。
最多可以为每个表定义 5 个全局二级索引和 5 个本地二级索引。
下图显示了示例 Music 表,该表包含一个名为 GenreAlbumTitle 的新索引
对于Music表,我们不仅可以按 Artist(分区键)或按 Artist 和 SongTitle(分区键和排序键)查询数据项。还可以按 Genre 和 AlbumTitle 查询数据。
Note
请注意有关 GenreAlbumTitle 索引的以下内容:
每个索引属于一个表(称为索引的基表)。在上述示例中,Music 是 GenreAlbumTitle 索引的基表。
DynamoDB 将自动维护索引。当添加、更新或删除基表中的某个项目时,DynamoDB 会添加、更新或删除属于该表的任何索引中的对应项目。
当创建索引时,可指定哪些属性将从基表复制或投影到索引。DynamoDB 至少会将键属性从基表投影到索引中。对于 GenreAlbumTitle 也是如此,只不过此时只有 Music 表中的键属性会投影到索引中。
DynamoDB 数据类型
DynamoDB 对表中的属性支持很多不同的数据类型。可按以下方式为属性分类:
标量类型 - 标量类型可准确地表示一个值。标量类型包括数字、字符串、二进制、布尔值和 null。
文档类型 - 文档类型可表示具有嵌套属性的复杂结构。文档类型包括列表和映射。
集类型 - 集类型可表示多个标量值。集类型包括字符串集、数字集和二进制集。
当创建表或secondary index时,必须指定每个主键属性(分区键和排序键)的名称和数据类型。此外,每个主键属性必须定义为字符串、数字或二进制类型。
标量类型
标量类型包括数字、字符串、二进制、布尔值和 null。
数据类型 | 说明 | 示例 |
---|---|---|
字符串 | 字符串是使用 UTF-8 二进制编码的 Unicode。字符串的长度必须大于零且受限于最大 DynamoDB 项目大小 400 KB。 | "Bicycle" |
数字 | 数字可为正数、负数或零。数字最多可精确到 38 位 - 超过此位数将导致意外 | 300 |
二进制 | 二进制类型属性可以存储任意二进制数据,如压缩文本、加密数据或图像。DynamoDB 会在比较二进制值时将二进制数据的每个字节视为无符号。二进制属性的长度必须大于零且受限于最大 DynamoDB 项目大小 400 KB。 | 这是一个采用 Base64 编码文本的二进制属性: dGhpcyB0ZXh0IGlzIGJhc2U2NC1lbmNvZGVk |
布尔值 | 布尔类型属性可以存储 true 或 false。 | true |
空 | 空代表属性具有未知或未定义状态。 | NULL |
字符串
如果将主键属性定义为字符串类型属性,以下附加限制将适用:
对于简单的主键,第一个属性值(分区键)的最大长度为 2048 字节。
对于复合主键,第二个属性值(排序键)的最大长度为 1024 字节
DynamoDB 使用基础的 UTF-8 字符串编码字节整理和比较字符串。例如,“a”(0x61) 大于“A”(0x41),“¿”(0xC2BF) 大于“z”(0x7A)。
可使用字符串数据类型表示日期或时间戳。执行此操作的一种方法是使用 ISO 8601 字符串,如以下示例所示:
2016-02-15
2015-12-21T17:42:34Z
20150311T122706Z
也可以使用数字数据类型表示日期或时间戳
数字
数字范围
正数范围:1E-130 到 9.9999999999999999999999999999999999999E+125
负数范围:-9.9999999999999999999999999999999999999E+125 到 -1E-130
在 DynamoDB 中,数字以可变长度形式表示。系统会删减开头和结尾的 0。
所有数字将作为字符串通过网络发送到 DynamoDB,以最大程度地提高不同语言和库之间的兼容性。但是,DynamoDB 会将它们视为数字类型属性以方便数学运算。
Note
如果数字精度十分重要,则应使用从数字类型转换的字符串将数字传递给 DynamoDB。
二进制
如果将主键属性定义为二进制类型属性,以下附加限制将适用:
对于简单的主键,第一个属性值(分区键)的最大长度为 2048 字节。
对于复合主键,第二个属性值(排序键)的最大长度为 1024 字节。
在将二进制值发送到 DynamoDB 之前,我们必须采用 Base64 编码格式对其进行编码。收到这些值后,DynamoDB 会将数据解码为无符号字节数组,将其用作二进制属性的长度。
文档类型
文档类型包括列表和映射。这些数据类型可以互相嵌套,用来表示深度最多为 32 层的复杂数据结构。
只要包含值的项目大小在 DynamoDB 项目大小限制 (400 KB) 内,列表或映射中值的数量就没有限制。
数据类型 | 说明 | 示例 |
---|---|---|
列表 | 列表类型属性可存储值的有序集合。列表用方括号括起:[ ... ]。列表类似于 JSON 数组。列表元素中可以存储的数据类型没有限制,列表元素中的元素也不一定为相同类型。 | FavoriteThings: ["Cookies", "Coffee", 3.14159] |
映射 | 映射类型属性可以存储名称/值对的无序集合。映射用大括号括起:{ ... }。映射类似于 JSON 对象。映射元素中可以存储的数据类型没有限制,映射中的元素也不一定为相同类型。 | 示例如下 |
{
Day: "Monday",
UnreadEmails: 42,
ItemsOnMyDesk: [
"Coffee Cup",
"Telephone",
{
Pens: { Quantity : 3},
Pencils: { Quantity : 2},
Erasers: { Quantity : 1}
}
]
}
Note
DynamoDB 让您可以使用映射/列表中的单个元素
集
DynamoDB 支持表示数字、字符串或二进制值集的类型。集中的所有元素必须为相同类型(
集中的每个值必须是唯一的。集中的值的顺序不会保留。不支持空集。
Example (字符串集、数字集和二进制集)
# 必须是相同的数据类型
# 字符串集
["Black", "Green" ,"Red"]
# 数字集
[42.2, -19, 7.5, 3.14]
# 二进制集
["U3Vubnk=", "UmFpbnk=", "U25vd3k="]
DynamoDB API
DynamoDB 的api操作主要用于控制层面、数据层面和DynamoDB Streams。
控制层面
控制层面 操作可让我们可以创建和管理DynamoDB表。它们还可让我们可以使用依赖于表的索引、流和其他对象。
CreateTable - 创建新表。或者,也可以创建一个或多个二级索引并为表启用 DynamoDB Streams。
DescribeTable - 返回有关表的信息,例如,表的主键架构、吞吐量设置、索引信息等。
ListTables - 返回列表中所有表的名称。
UpdateTable - 修改表或其索引的设置、创建或删除表上的新索引或修改表的 DynamoDB Streams 设置。
DeleteTable - 从 DynamoDB 中删除表及其所有依赖对象。
数据层面
数据层面操作可让我们对表中的数据执行创建、读取、更新和删除(也称为 CRUD)操作。某些数据层面操作还可让我们可以从secondary index中读取数据。
创建数据
PutItem - 将单个项目写入到表中。您必须指定主键属性,但不必指定其他属性。
BatchWriteItem - 将最多 25 个项目写入到表中。
读取数据
GetItem - 从表中检索单个项目。我们必须为所需的项目指定主键。我们可以检索整个项目,也可以仅检索其属性的子集。
BatchGetItem - 从一个或多个表中检索最多 100 个项目。
Query - 检索具有特定分区键的所有项目。我们必须指定分区键值。
可以检索整个项目,也可以仅检索其属性的子集。或者,也可以对排序键值应用条件,以便只检索具有相同分区键的数据子集。我们可以对表使用此操作,前提是该表同时具有分区键和排序键。还可以对索引使用此操作,前提是该索引同时具有分区键和排序键。
Scan - 检索指定表或索引中的所有项目。我们可以检索整个项目,也可以仅检索其属性的子集。或者,我们也可以应用筛选条件以仅返回感兴趣的值并放弃剩余的值。
更新数据
UpdateItem - 修改项目中的一个或多个属性。必须为要修改的项目指定主键。
可以添加新属性以及修改或删除现有属性。还可以执行有条件更新。也可以实施一个原子计数器,该计数器可在不干预其他写入请求的情况下递增或递减数字属性。
删除数据
DeleteItem - 从表中删除单个项目。您必须为要删除的项目指定主键。
BatchWriteItem - 从一个或多个表中删除最多 25 个项目
Note
Batch 操作比调用多次单个请求(DeleteItem, GetItem, PutItem)更有效,因为秩序一个网络请求即可操作多个项目。
DynamoDB Streams
DynamoDB Streams 操作可对表启用或禁用流,并能允许对包含在流中的数据修改记录的访问。
ListStreams - 返回所有流的列表,或仅返回特定表的流。
DescribeStream - 返回有关流的信息,例如,流的 Amazon 资源名称 (ARN) 和您的应用程序可开始读取前几条流记录的位置。
GetShardIterator - 返回一个分区迭代器,这是我们的应用程序用来从流中检索记录的数据结构。
GetRecords - 使用给定分区迭代器检索一条或多条流记录。
命名规则
DynamoDB 中的表、属性和其他对象必须具有名称。名称应该简明扼要 - 例如,Products、Books 和 Authors 之类的名称是都是不言而喻的。
下面是 DynamoDB 的命名规则:
所有名称都必须使用 UTF-8 进行编码,并且区分大小写。
-
表名称和索引名称的长度必须介于 3 到 255 个字符之间,而且只能包含以下字符:
a-z
A-Z
0-9
_(下划线)
-(短划线)
.(圆点)
属性名称的长度必须介于 1 到 255 个字符之间。
保留关键字和特殊字符
与很多其他数据库管理系统相似,DynamoDB 也具有一系列保留关键字和特殊字符。
有关 DynamoDB 中的保留关键字的完整列表,请参阅 DynamoDB 中的保留关键字。
(哈希)和 :(冒号)在 DynamoDB 中具有特殊含义
DynamoDB允许使用这些关键字和特殊符号用于命名,但我们不建议这么做
有关更多信息,请参阅 为属性名称和值使用占位符。
读取一致性
Amazon DynamoDB 在全世界多个 AWS 区域可用。每个区域均与其他 AWS 区域完全独立和隔离。
例如,如果我们在 us-east-1 区域有一个名为 People 的表,并在 us-west-2 区域有另一个名为 People 的表,则这两个表将被视为完全独立的表。
每个 AWS 区域包含多个不同的称为“可用区”的位置。每个可用区都被设计成不受其他可用区故障的影响,并提供低价、低延迟的网络连接,以连接到同一区域其他可用区。此设计可保证我们可以在某个区域的多个可用区中快速复制数据。
当我们将某个数据写入 DynamoDB 表并收到 HTTP 200 响应 (OK) 时,该数据的所有副本都会更新。但是,要将数据传播到当前 AWS 区域内的所有存储位置需要耗费一定的时间。该数据最终将在上述所有存储位置中保持一致,通常只需一秒或更短时间。
为了支持各种应用程序要求,DynamoDB 同时支持最终一致性 读取和强一致性 读取。
最终一致性读取
当我们从 DynamoDB 表中读取数据时,返回的可能不是刚刚完成的写入操作的结果。响应可能包含某些旧的数据。但是,如果我们在短时间后重复读取请求,响应将返回最新的数据。
强一致性读取
当我们请求强一致性读取时,DynamoDB 会返回具有最新数据的响应,从而反映来自所有已成功的之前写入操作的更新。但是,如果网络延迟或中断,可能会无法执行强一致性读取。
Note
DynamoDB 默认使用最终一致性读取。读取操作(例如 GetItem、Query 和 Scan)提供了一个 ConsistentRead 参数:此参数设置为 true,DynamoDB 将在操作过程中使用强一致性读取。
示例:
{
TableName: "Music",
Key: {
"Artist": "No One You Know",
"SongTitle": "Call Me Today"
},
ConsistentRead: true
}
python 示例
table = db3.Table('Music')
response = table.get_item(
Key={
"Artist": "The Acme Band",
"SongTitle": "Still In Love"
},
ConsistentRead=True
)
下一篇主要介绍DynamoDB表的基本操作