目录
1 工作原理
Amazon DynamoDB 是一种完全托管式、无服务器的 Nosql 键值数据库,旨在运行任何规模的高性能应用程序。
DynamoDB 提供内置安全性、连续备份、自动多区域复制、内存缓存和数据导入和导出工具。
2 使用优势
3 基本使用
DynamoDB 的数据集合是一张表,表里的每一条数据就是一个文档,
文档中可以存储基本类型的数据(BOOLEAN,NUMBER,STRING)或者一些复杂的数据(MAP,LIST,SET),可以嵌套较为深的层级。
在创建一张表的时候,
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)
3.2.2 全局二级索引 (GSI)
全局二级索引相当于一个全新的表,除了与原表共用同一个表名之外,GSI 使用了新的 Partition Key 和 Sort Key,有自己独立的 Partition, 计算读写数量时也与原表相互独立。
GSI 会在原表发生改变的时候,通过流(Stream)将更新同步到 GSI 中。一个表可以建立 20 个全局二级索引。
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 基本查询
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 索引中来。
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 无法写入空值、空字符串,会直接忽略相应字段
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。