【AWS系列】第五讲:什么是DynamoDB

目录

1 工作原理

 2 使用优势

3 基本使用

 3.1 基本结构

3.2 索引

3.2.1 本地二级索引 (LSI)

3.2.2 全局二级索引 (GSI)

3.3  一致性

3.4 DynamoDB流

3.5 表结构设计

3.5.1 基本查询

3.5.2 索引重载

3.5.3 稀疏索引

3.5.4 组合键

3.5.5 分级数据

 4 本地开发

DynamoDB Local

5 总结 


1 工作原理

Amazon DynamoDB 是一种完全托管式、无服务器的 NoSQL 键值数据库,旨在运行任何规模的高性能应用程序。

DynamoDB 提供内置安全性、连续备份、自动多区域复制、内存缓存和数据导入和导出工具。

可以以非常低的延迟支持 任何级别的负载 ,同时有着较完善的权限管理系统。

 2 使用优势

  • 简化运维:全托管模式,减少创建、维护数据库的开销;跨区域的分区存储,数据更安全;
  • 自动扩容:数据量的增长对数据库性能没有太多影响
  • 灵活的表结构:只需要定义分区键即可正常使用,随时增加减少字段
  • 事件流:流结合 Lambda 可以非常方便的实现一些功能

3 基本使用

DynamoDB 的数据集合是一张表,表里的每一条数据就是一个文档,

文档中可以存储基本类型的数据(BOOLEAN, NUMBER, STRING)或者一些复杂的数据(MAP, LIST, SET),可以嵌套较为深的层级。

在创建一张表的时候,

需要指定一个基本类型的属性值作为 PK

再指定一个基本类型的属性值作为 SK

PK 的作用是将数据分散到不同的分区(Partition)里,构建无序的哈希索引

SK的作用是将同一个分区中的数据按照一定的顺序排列起来,便于查找

SK 中可以使用 ==, <, >=, <=, begins with, between, contains, in 等函数来进行较为丰富的查询操作

PK 必须使用准备的值进行查询

 3.1 基本结构

  • 表(Table)
  • 文档(Document)
  • 属性(Attribute)
  • 分区键(Partition Key/Hash Key, 记为 PK,必需,数据类型必须是基本类型)
  • 排序键(Sort Key/Range Key, 记为 SK,可选)
  • 数据类型:
    • 基本类型: number, string, binary, Boolean, and null
    • 文档: list, map
    • 集合: set

3.2 索引

DynamoDB 共有两种索引:

1 本地二级索引(Local Secondary Index,简称 LSI)

2 全局二级索引(Global Secondary Index,简称 GSI)

3.2.1 本地二级索引 (LSI)

本地二级索引和原表共用一份 Partition, 使用同一个 PK, 共用这一个 PK 的存储空间,上限为 10GB

LSI 提供了不同的筛选方式和排序方式,选用不同的属性作为 SK 可以提高查询的灵活性。

3.2.2 全局二级索引 (GSI)

全局二级索引相当于一个全新的表,除了与原表共用同一个表名之外,GSI 使用了新的 Partition Key 和 Sort Key, 有自己独立的 Partition, 计算读写数量时也与原表相互独立。

GSI 会在原表发生改变的时候,通过流(Stream)将更新同步到 GSI 中。一个表可以建立 20 个全局二级索引。

推荐使用全局二级索引,避免本地二级索引引起的读写容量的竞争,同时可以重新定义 PK 和 SK,支持更多的查询模式

3.3  一致性

DynamoDB 是数据库云服务,其在设计中着重考虑了数据的 可用性分区容忍性。从 CAP(Consistency, Availability, Partitioning)理论的角度来讲,DynamoDB 是一个 AP 的数据库。

在 DynamoDB 中,共有两个部分会涉及到读一致性的问题:主表读和GSI读。

主表读过程会产生一致性问题的原因是 DynamoDB 的 Partition 是有 三个副本的(实际为可用区)

默认情况下写入到两个副本中即认为写入成功,因此在高频读取时也有一定的概率读到未完成写入的数据。

可以通过配置 GetItem, Scan 等的操作一致性为 强一致性来避免这个问题,

但可能会带来更高的延迟(10ms级别)和吞吐量开销(强一致性为最终一致性吞吐量开销的二倍)。

GSI 读写会产生一致性的原因是 GSI 和主表实际是 两个不同的存储,写入到主表的数据会通过流同步到GSI,这个过程会存在一定的延时(10ms级别),因此在读取 GSI 中的数据时,不能设置为强一致性

3.4 DynamoDB流

DynamoDB流是一项可选功能,它用于捕获DynamoDB表中的数据修改事件。有关这些事件的数据将按事件发生的顺序近乎实时的出现在流中。


每个事件由一条流记录表示,若对表启用了流,每当以下事件之一 发生时,DynamoDB流都会写入一条流记录:

  • 如果向表中添加了新项目,流将捕获整个项目的映像(包括其所有属性)
  • 如果更新了项目,流将捕获项目中任何已修改属性的"之前""之后"映像
  • 如果从表中删除了项目,流将在整个项目被删除前捕获其映像
  • 每条流记录还包含表名称、事件时间戳和其他元数据。流记录的有效事件为24小时,过此事件后记录将被自动删除

启用 DynamoDB Stream 之后,可以使用 Lambda 接收 Stream 并将数据填充到

  • ElasticSearch 中便于进行复杂的查询,
  • 或者同步数据
  • 或者进行一些聚合计算

均可以通过 DynamoDB Stream 方便的完成。

3.5 表结构设计

DynamoDB 是需要提前考虑好一些查询方式,才能更好的设计表结构,否则可能会在使用的过程中遇到一些不便。

DynamoDB 限于底层结构设计,进行表扫描(Scan)的操作非常耗时,对于较大的表来说基本上是 不可接受的时间消耗,因此需要根据 DynamoDB 的特点对表结构进行巧妙的设计,以实现需要的查询组合。

因此,设计 DynamoDB 时:

第一步:是列举出可能的查询方式。当有了一组查询方式之后,便可以开始进行表结构的设计。

3.5.1 基本查询

在设计出查询方式之后,便可以优先关注使用量最多,查询方式最简单的查询需要。以下为主表中几种常见的查询方式:

  1. 使用 PK 直接查询:可以查出该分区键下的所有数据,适合于 一对多关系。例如查询一个用户下的多个订单记录,这时 PK 为用户的 ID
  2. 使用 PK + 完整 SK 进行查询:如果一个 PK 下的数据比较多,可以结合 SK 来实现更为精确的查询。例如查询一个用户下的一个特定的订单,这时 PK 为用户的 ID,SK 为订单的ID。
  3. 使用 PK + SK (==, <, >=, <=, begins with, between, contains, in) 进行查询:如果一个 PK 下数据比较多,同时每一类 SK 上有通用的前缀,可以用 begins with 来进行查询。例如查询用户的订单使用用户 ID 和 SK 前缀 order: 进行查询。

3.5.2 索引重载

AWS 的 Principal Technologist, Rick Houlihan 曾说,一个设计良好的 DynamoDB 应该只有一张表。

索引重载是使用 RDS 的用户最容易感到不适应的一部分

这意味着属性名不一定是一个有实际含义的名称,其内容也可能包含多个种类。

这显然与之前对 RDS 数据的认识完全不一样,RDS 倾向于细粒度的划分每个实体,为实体及实体之间的关系建立相关的表。

如果一个应用只有一张表,那么用户、订单、商品、发票等数据会共用一个表定义,表的结构可能类似下面这个样子:

可以使用 #User#{ID} 和 #PRODUCT#{ID}这样的方式在 ID 中带上该条记录的类型

SK 也可以采用类似的设计方式,这样可以更好的辨识一条数据的类型,另一方面当 PK 在 GSI 中作为 SK 时,可以使用 begins with 查出同一类的数据。

因为 DynamoDB 可以自动扩容,所设计好这一个表之后,便可以方便的对该表创建 GSI,开启备份,使用同样的查询、数据插入的命令来完成各种各样的操作,同时因为使用同一个读写容量,所以会减少读写容量的浪费。

新建不同的表来存储这些内容,其实新建的表与该表也不会太大的差异,使用同一张表反而更加方便。

在使用 PK 和 SK 进行 Query 之后,还可以使用 Filter 进行数据的筛选,这些筛选只能使用在基础数据类型上面,

因此如果存储 list, map, set 时可能会简化一些操作,但在筛选时遇到一些问题,可以利用 sk 的 begins with 查询功能,将数据拆分开来方便筛选。

3.5.3 稀疏索引

创建 GSI 时,会重新选择一个基础类型的字段作为主键,如果部分数据并不包含这个字段,那么这些数据就不会被添加到这个 GSI 索引中来。

因此可以利用这个特性为不同的查询模式来创建不同 GSI,以减少 GSI 中数据的数量。

3.5.4 组合键

组合键是一个非常有用的方式

如果有一些字段必须复合起来使用,并且会作出相对复杂的筛选条件,那么便可以考虑采用组合键来处理。如以下示例:

希望达成类似 SELECT * FROM Game WHERE Opponent = 'Bob' ORDER BY DATE DESC FILTER ON Status='PENDING' 的查询,

如果 Bob 的数据有上千条,但 IN_PROGRESS 的数量只有一条,那使用 Query + Filter 的结果是需要查到这千条数据,再从中过滤出需要的数据来。

但如果使用组合键 StatusDate = Status + Date, 如下示例:

可以直接查到需要的这两条数据,也可以继续使用 Filter 再进行过滤。

同时会有一些特殊的要求,在不使用组合键时,如果进行查询会是一个相当大的挑战。

3.5.5 分级数据

与组合键类型,分级数据意味着该字段中的数据不是一个简单的数据,也会是一个拼起来的数据

最简单的例子是地域信息:比如四川省成都市,可以存储为 #SICHUAN#CHENGDU,如果后面有多少级均可以继续接在后面。通过这种方式便把一个层级很深的数据转化成了一个简单的数据,

同时使用 begins with便可以查某个区划下的所有信息。

 4 本地开发

DynamoDB 是 AWS 的云服务,可以使用 AWS 提供的 aws-cli, 通过命令行来完成常见的表操作及数据操作。

最为常用的功能是结合其它命令一起进行查询及数据分析,或者清除表中的数据。

同时,如果在开发过程中需要使用 DynamoDB,依然需要付出相应的服务费用

使用 DynamoDB Local 可以减少这部分开销。

DynamoDB Local

如果在本地进行开发,可以使用 DynamoDB Local,

  • 通过 DynamoDBLocal 的 jar 包直接运行
  • 使用 Docker 运行 DynamoDB 的镜像

命令为

docker run -p 8000:8000 -v $(pwd)/data:/data/ amazon/dynamodb-local:1.11.477 -jar DynamoDBLocal.jar -sharedDb -dbPath /data

可以使用 DynamoDB GUI 作为图形化的管理工具或者直接使用 aws-cli 加上参数,进行管理。

 --endpoint-url http://localhost:8000 

CLI代码示例:

aws dynamodb create-table \
    --table-name music \
    --attribute-definitions \
        AttributeName=artist,AttributeType=S \
        AttributeName=song_title,AttributeType=S \
    --key-schema \
        AttributeName=artist,KeyType=HASH \
        AttributeName=song_title,KeyType=RANGE \
--provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5

aws dynamodb describe-table --table-name music | grep TableStatus

aws dynamodb put-item \
    --table-name music  \
    --item \
        '{"artist": {"S": "No One You Know"}, "song_title": {"S": "Call Me Today"}, "album_title": {"S": "Somewhat Famous"}, "awards": {"N": "1"}}'

aws dynamodb get-item --consistent-read \
    --table-name music \
    --key '{ "artist": {"S": "Acme Band"}, "song_title": {"S": "Happy Day"}}'

aws dynamodb update-item \
    --table-name music \
    --key '{ "artist": {"S": "Acme Band"}, "song_title": {"S": "Happy Day"}}' \
    --update-expression "SET album_title = :newval" \
    --expression-attribute-values '{":newval":{"S":"Updated Album Title"}}' \
    --return-values ALL_NEW

aws dynamodb update-table \
    --table-name music \
    --attribute-definitions AttributeName=album_title,AttributeType=S \
    --global-secondary-index-updates \
    "[{\"Create\":{\"IndexName\": \"album_title-index\",\"KeySchema\":[{\"AttributeName\":\"album_title\",\"KeyType\":\"HASH\"}], \
    \"ProvisionedThroughput\": {\"ReadCapacityUnits\": 10, \"WriteCapacityUnits\": 5      },\"Projection\":{\"ProjectionType\":\"ALL\"}}}]"

aws dynamodb query \
    --table-name music \
    --index-name album_title-index \
    --key-condition-expression "album_title = :name" \
    --expression-attribute-values  '{":name":{"S":"Somewhat Famous"}}'

aws dynamodb query \
    --table-name music \
    --key-condition-expression "artist = :name" \
    --expression-attribute-values  '{":name":{"S":"Acme Band"}}'

aws dynamodb scan --table-name music --filter-expression 'attribute_exists(artist)'

aws dynamodb delete-table --table-name music

// 使用 jq 获取某个字段并取得不重复值
aws dynamodb scan \
    --table-name music \
    --index-name business-index \
    --projection-expression some_data \
    | jq '.Items[] | .data.S' | sort --unique

5 总结 

1. Truncate 操作:DynamoDB 不支持 Truncate 操作,

最简单的办法是删表重建即可;

如果需要删掉一部分数据,

  • 可以写脚本用 scan 查出 PK 的列表逐个进行删除;
  • 还可以设置表的过期时间,让这批数据定期失效即可。

2. JavaScript 有两个类库:一种使用了 DynamoDB Json

其中包括了数据的类型,需要调用相关的 marshal 和 unmarshal 方法来转换成标准的 Json

3.批量操作:DynamoDB 中批量操作有 25 的数据量限制,部分情况下需要手动分批分成多个请求来处理,部分类库提供了自动分批的功能

4.空值操作:DynamoDB 无法写入空值、空字符串,会直接忽略相应字段

5.查询:非基本类型的数据可以当作 String 进行查询

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜淡慕潇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值