1. NoSQL
2. schema less设计。也就是每个item(行)的列名不固定可省空间。原理是每item按json存。
3. 只能query(partition)/sort (range key),不能query/sort非主键。除非创建GSI(global secondary index)
4. 计价方式颠覆传统数据库。传统用空间大小计费,而DynamoDB用request峰值计算
5. 存储按partition key来分配存储位置,不用像传统一样做增加空间、shrink、备份等DBA工作
6. 每份数据至少有3个备份
新特性:
1. 无需规划容量read/write capacity,采用按请求付费的定价模式
2. 支持事务await dynamoDb.transactWriteItems
3. Accelerator - dynamoDB的cache
架构
重点:存储key-value和更改trigger(stream)
核心概念:
Table:与传统DB一样
Item:传统DB的行
Attribute:传统DB的列名
Primary key:是必须的。有两种primary key:一种只用partition key,此时partition key在全表中唯一。另一种是partition key+sort key作为组合主键(如名字+生日唯一确定一个人)。数据时按partition key来存储的,同一partition内,数据按sort key排序。partition key叫hash attribute只能用于相等性比较,而sort key叫range attribute,可以进行相等和大小比较。
Secondary Indexes:额外索引来提高非主键数据读取速度,由于primary key已是索引,所以这里叫额外索引。索引包括全局和局部索引。全局索引针对全表,如studentID(HashKey), courseID(SortKey), score(IndexHashKey)可以获得某个分数的所有人。局部索引是针对每个partition key的索引,类似于SQL Server的filter index。指定index时还要选include primary key还是其他非key属性或是全部,类似与SQL Server中index的include。但是数据一致性并不能保证。写入新数据,可能需要一些时间才会写到二级索引。
read capacity:默认的read capacity为5,表示每秒只允许5个读操作。
最佳实践:
CID, DeviceId+type
EntityType, entityId
如果存epoch time,用Number存
customerid+startPoint作为hash key,endPoint做range Key,再对startPoint做secondary index
底层API:
创建table如下,dynamoDB.getTable("Movies").putItem, getItem, batchGetItem, batchWriteItem, query, scan, delete,这是dynamoDB的API属于low level API。AmazonDynamoDBClient client = new AmazonDynamoDBClient()
.withEndpoint("http://localhost:8000");
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.createTable(“Movies”,
Arrays.asList(
new KeySchemaElement("year", KeyType.HASH), //Partition key
new KeySchemaElement("title", KeyType.RANGE)), //Sort key
Arrays.asList(
new AttributeDefinition("year", ScalarAttributeType.N),
new AttributeDefinition("title", ScalarAttributeType.S)),
new ProvisionedThroughput(10L, 10L));
table.waitForActive();
封装层 - Mapper:
AWS SDKDeveloper Guide中的例子:
代表一个item:
@DynamoDBTable(tableName="Music")
public class MusicItem {
private String artist;
private String songTitle;
private String albumTitle;
private int year;
@DynamoDBHashKey(attributeName="Artist")
public String getArtist() { return artist;}
public void setArtist(String artist) {this.artist = artist;}
@DynamoDBRangeKey(attributeName="SongTitle")
public String getSongTitle() { return songTitle;}
public void setSongTitle(String songTitle) {this.songTitle = songTitle;}
@DynamoDBAttribute(attributeName = "AlbumTitle")
public String getAlbumTitle() { return albumTitle;}
public void setAlbumTitle(String albumTitle) {this.artist = albumTitle;}
}
@DynamoDBAttribute不是必须,与lombok连用:
@DynamoDBTable(tableName="Music")
@Data
public class MusicItem {
@DynamoDBHashKey(attributeName="Artist")
private String artist;
private String albumTitle;
@DynamoDBVersionAttribute
private Integer version;
}
根据primary key读取一个item:
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
DynamoDBMapper mapper = new DynamoDBMapper(client);
MusicItem keySchema = new MusicItem();
keySchema.setArtist("No One You Know");
keySchema.setSongTitle("Call Me Today");
MusicItem result = mapper.load(keySchema);
AmazonDynamoDBClient client = new AmazonDynamoDBClient(new ProfileCredentialsProvider());
DynamoDBMapper mapper = new DynamoDBMapper(client);
CatalogItem item = new CatalogItem();
mapper.save(item);
query第一个参数是结果类,第二参数为query条件也是用结果类封装:
CatalogItem partitionKey = new CatalogItem();
partitionKey.setId(102);
DynamoDBQueryExpression<CatalogItem> queryExpression = new DynamoDBQueryExpression<CatalogItem>()
.withHashKeyValues(partitionKey);
List<CatalogItem> itemList = mapper.query(CatalogItem.class, queryExpression);
for (int i = 0; i < itemList.size(); i++) {
System.out.println(itemList.get(i).getTitle());
System.out.println(itemList.get(i).getBookAuthors());
}
mapper的方法包括save, batchSave, load, query, delete
用非DynamoDBMapper方法去读数据
Index:
DynamoDBQueryExpression<TableClass> expression = new DynamoDBQueryExpression<TableClass>()
.withIndexName("index-name")
.withConsistentRead(false)
.withHashKeyValues(tableObject)
功能
操作:
GUI:创建表格、增加item都可以通过AWS界面完成
Table区域:
table按区域,也就是east-2有table,west-1就不会有。
Auto scaling:
30min才会生效。
GSI/LSI:
GSI是任何两个属性,而LSI的分区键与原分区键一致,sort key不同。GSI是不保证强一致性,LSI则可以。
乐观锁:
指定一个属性作为版本号。如果保存,版本号不一致,更新失败。用意在于确保,更新的改动不会被其他transaction覆盖。具体实现是客户端版本号+1,输入后端,若match DDB中版本号+1,就成功更新,返回整个item包括新版本号。否则不成功。
PutItem:
覆盖现有item。但可以用条件先判断是否存在。
TTL:
每个item的生存时间(time to live),dynamoDB会48小时内删除过期的项目。用户修改table属性指定TTL的attribute,然后写入item时候用户指定过期时间如currentTime+5 days.
DDB streams:
用例有DB不同区域sync,DDB数据分析,新用户通知。一个stream是一个改动,只能保留24小时。Kinesis是DDB streams客户端适配器。
DDB stream->lambda->SNS->notification
DDB stream默认设置Retry = -1 无限重试 (这个retry控制lambda的retry,lambda本身的retry不起作用,所以lambda设的DLQ也没用)Maximum age of event = -1 无时间限制,event永远留在Streamhttps://enrico-portolan.medium.com/how-aws-lambda-retry-really-works-fb823e78b4a1
DDB stream->lambda->SNS->notification
全局表:
跨区的相同表结构,不保证强一致性,只保证最终一致性。
静态加密:
加密敏感数据。
事务:
仅支持10个项目
DAX:
Cache层,若需要强一致性,不推荐使用。从10毫秒降到微秒。
QueryFilter
用于DAO层的实现如contains, id=(:id).
On-demand mode
provisioned会让request throttled,即使设置了auto-scaling也会有delay。但on-demand就自动30分钟增加两倍,对于6000以下RPU的,就可以设置这个。因为初始为6000。
Cache层,若需要强一致性,不推荐使用。从10毫秒降到微秒。
用于DAO层的实现如contains, id=(:id).
On-demand mode
provisioned会让request throttled,即使设置了auto-scaling也会有delay。但on-demand就自动30分钟增加两倍,对于6000以下RPU的,就可以设置这个。因为初始为6000。
最佳实践:
多对多关系:同一个表中,用自join存储。
最佳实践:
多对多关系:同一个表中,用自join存储。
Export/Import:
用data pipeline来export到S3. 不要设onTerminate的时间,因为大概要过10分钟才会真正开始,若设置了时间过短,就不会开始。
常见问题
resource not found exception
由于throttling,提高read capacity可以解决
常见问题
resource not found exception由于throttling,提高read capacity可以解决
AWS CLI:
shorthand syntax:aws dynamodb create-table --table-name MusicCollection --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5
CLI比较方便,但文档不足,也可以用于其他AWS产品如S3。或者backup到S3再import
Ref:
官方指南(中文)
DynamoDB深度体验
DynamoDB使用经验
No comments:
Post a Comment