amazon-dynamodb - DynamoDB 预置的读/写容量单位意外超出
问题描述
我运行一个使用 api 网关和 lambdas 将数据发送到 dynamodb 的程序。
发送到数据库的所有数据都很小,仅从大约 200 台机器发送。
我仍在使用免费套餐,有时出乎意料的是,在月中我开始获得更高的预置读/写容量,然后从今天开始,我每天支付固定金额,直到月底。
有人能从下图中理解 03/13 中发生了什么导致图表中出现这种情况并导致这些配置从 50 上升到 65 吗?
解决方案
我无法仅根据这些图表来判断发生了什么,但需要考虑一些事项:
您可能不知道 DynamoDB 表的新“PAY_PER_REQUEST”计费模式选项,它使您几乎可以忘记手动配置吞吐量容量:https ://aws.amazon.com/blogs/aws/amazon-dynamodb-on-需求无容量规划和按请求付费定价/
此外,对于您的用例可能没有意义,但对于免费层项目,我发现通过 SQS 队列代理对 DynamoDB 的所有写入很有用(将队列用作具有兼容的预留并发的 Lambda 的事件源与您提供的吞吐量)。如果您的项目是合理的事件驱动的,这很容易,即构建您的 DynamoDB 请求对象/参数,写入 SQS,然后下一步是从 DynamoDB 流触发的 Lambda(因此您不会期望同步响应来自第一个 Lambda 中的写入操作)。像这样:
SQS 触发的 Lambda 的示例无服务器配置:
dynamodb_proxy:
description: SQS event function to write to DynamoDB table '${self:custom.dynamodb_table_name}'
handler: handlers/dynamodb_proxy.handler
memorySize: 128
reservedConcurrency: 95 # see custom.dynamodb_active_write_capacity_units
environment:
DYNAMODB_TABLE_NAME: ${self:custom.dynamodb_table_name}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
Resource:
- Fn::GetAtt: [ DynamoDbTable, Arn ]
- Effect: Allow
Action:
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:GetQueueAttributes
Resource:
- Fn::GetAtt: [ DynamoDbProxySqsQueue, Arn ]
events:
- sqs:
batchSize: 1
arn:
Fn::GetAtt: [ DynamoDbProxySqsQueue, Arn ]
写入 SQS 的示例:
await sqs.sendMessage({
MessageBody: JSON.stringify({
method: 'putItem',
params: {
TableName: DYNAMODB_TABLE_NAME,
Item: {
...attributes,
created_at: {
S: createdAt.toString(),
},
created_ts: {
N: createdAtTs.toString(),
},
},
...conditionExpression,
},
}),
QueueUrl: SQS_QUEUE_URL_DYNAMODB_PROXY,
}).promise();
SQS 触发的 Lambda:
import retry from 'async-retry';
import { getEnv } from '../lib/common';
import { dynamodb } from '../lib/aws-clients';
const {
DYNAMODB_TABLE_NAME
} = process.env;
export const handler = async (event) => {
const message = JSON.parse(event.Records[0].body);
if (message.params.TableName !== env.DYNAMODB_TABLE_NAME) {
console.log(`DynamoDB proxy event table '${message.params.TableName}' does not match current table name '${env.DYNAMODB_TABLE_NAME}', skipping.`);
} else if (message.method === 'putItem') {
let attemptsTaken;
await retry(async (bail, attempt) => {
attemptsTaken = attempt;
try {
await dynamodb.putItem(message.params).promise();
} catch (err) {
if (err.code && err.code === 'ConditionalCheckFailedException') {
// expected exception
// if (message.params.ConditionExpression) {
// const conditionExpression = message.params.ConditionExpression;
// console.log(`ConditionalCheckFailed: ${conditionExpression}. Skipping.`);
// }
} else if (err.code && err.code === 'ProvisionedThroughputExceededException') {
// retry
throw err;
} else {
bail(err);
}
}
}, {
retries: 5,
randomize: true,
});
if (attemptsTaken > 1) {
console.log(`DynamoDB proxy event succeeded after ${attemptsTaken} attempts`);
}
} else {
console.log(`Unsupported method ${message.method}, skipping.`);
}
};
推荐阅读
- android - Android:JSONDownloader 返回空字符串
- ios - 更改在 TestFlight 上使用但不是 App Store 的应用程序的捆绑包 ID
- javascript - 在数组对象内过滤数组后返回值
- ios - Xcode 10 自动完成功能在其他 swift 文件中不起作用
- zend-framework - Swoole http 服务器中的 Zend View 行为
- qt - 如何实时可视化来自不同线程的图像?
- android - Progressive Web App - 迄今为止所有可用的权限
- php - 在php中删除重复并合并数组
- php - 将 SQL 数据列分组到行
- javascript - JQuery - 运行窗口调整大小或方向更改。