使用 Lambda 在 DynamoDB 上批量写入超过 25 个项目



>Edit x1:将代码段替换为完整文件

我目前正在 DynamoDB 中播种 1.8K 行。创建用户时,需要生成并插入这些行。它们不需要立即阅读(比方说,在不到 3 - 5 秒的时间内)。我目前正在使用 AWS Lambda,但遇到超时异常(可能是因为消耗的 WCU 多于预置的 WCU,我有 5 个禁用了自动扩展)。

我尝试在Google和StackOverflow中进行搜索,这似乎是一个灰色区域(这有点奇怪,考虑到DynamoDB被宣传为每秒处理大量数据的令人难以置信的解决方案),其中没有明确的路径存在。

我们知道 DynamoDB 限制每批插入25 个项目,以防止 HTTP 开销。这意味着我们可以调用无限数量的批处理写入并增加 WCU。

我尝试通过触发它而不是等待它们来调用无限数量的 batchWrite(这算数吗?我已经读到,由于 JS 是单线程的,因此无论如何都会一个接一个地处理请求,除了如果我不使用承诺,我就不必等待响应......目前使用节点 10 和 Lambda),似乎什么也没发生。如果我承诺调用并等待它,我会得到一个 Lambda 超时异常(可能是因为它用完了 WCU)。

我目前有 5 个 WCU 和 5 个 RCU(对于这些随机加标操作来说,它们太小了吗?

我有点卡住了,因为我不想在短时间内随机增加 WCU。此外,我读到自动扩展不会自动启动,亚马逊每天只会调整容量单位 4 次。

  • 如何将超过 25 个项目/行写入 DynamoDB 的表格?
  • https://www.keithrozario.com/2017/12/writing-millions-of-rows-into-dynamodb.html

我该怎么办?

这是我用来插入 DynamoDB 的完整文件

const aws = require("aws-sdk");
export async function batchWrite(
data: {
PutRequest: {
Item: any;
};
}[]
) {
const client = new aws.DynamoDB.DocumentClient({
region: "us-east-2"
});
// 25 is the limit imposed by DynamoDB's batchWrite:
// Member must have length less than or equal to 25.
// This verifies whether the data is shaped correctly and has no duplicates.
const sortKeyList: string[] = [];
data.forEach((put, index) => {
const item = put.PutRequest.Item;
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
const hasPk = has.call(item, "pk");
const hasSk = has.call(item, "sk");
// Checks if it doesn't have a sort key. Unless it's a tenant object, which has
// the accountType attribute.
if (!hasPk || !hasSk) {
throw `hasPk is ${hasPk} and hasSk is ${hasSk} at index ${index}`;
}
if (typeof item["pk"] !== "string" || typeof item["sk"] !== "string") {
throw `Item at index ${index} pk or sk is not a string`;
}
if (sortKeyList.indexOf(item.sk) !== -1) {
throw `The item @ index ${index} and sortkey ${item.sk} has duplicate values`;
}
if (item.sk.indexOf("undefined") !== -1) {
throw `There's an undefined in the sortkey ${index} and ${item.sk}`;
}
sortKeyList.push(put.PutRequest.Item.sk);
});
// DynamoDB only accepts 25 items at a time.
for (let i = 0; i < data.length; i += 25) {
const upperLimit = Math.min(i + 25, data.length);
const newItems = data.slice(i, upperLimit);
try {
await client
.batchWrite({
RequestItems: {
schon: newItems
}
})
.promise();
} catch (e) {
console.log("Total Batches: " + Math.ceil(data.length / 25));
console.error("There was an error while processing the request");
console.log(e.message);
console.log("Total data to insert", data.length);
console.log("New items is", newItems);
console.log("index is ", i);
console.log("top index is", upperLimit);
break;
}
}
console.log(
"If no errors are shown, creation in DynamoDB has been successful"
);
}

您面临两个问题,但我会尝试解决它们。

尚未提供正在写入的项目的完整示例以及显示项目的实际batchWrite请求,因此不清楚实际请求的格式是否正确。根据提供的信息和面临的问题,请求的格式似乎不正确。

可在此处找到 AWS Javascript 开发工具包中batchWrite操作的文档,此处的先前答案显示了正确构建和格式化batchWrite请求的解决方案。

尽管如此,即使请求的格式正确,仍然存在第二个问题,即有足够的容量来处理写入请求,以便在所需的时间内插入 1800 条记录,上限为 5 秒。

TL;灾难恢复 容量问题的快速简便解决方案是从预置容量切换到按需容量。如下所示,数学表明,除非您具有一致和/或可预测的容量要求,否则大多数情况下按需容量不仅会消除预置容量的管理开销,而且还会大大降低成本。

根据此处预置容量的 AWS DynamoDB 文档,Write Capacity UnitWCU按如下方式计费并因此定义:

将数据写入表的每个 API 调用都是一个写入请求。对于大小不超过 1 KB 的项目,一个 WCU 每秒可以执行一个标准写入请求。

此处的batchWrite / batchWriteItemAPI 的 AWS 文档指出,batchWriteAPI 请求每个请求最多支持 25 个项目,单个项目最多支持 400kb。此外,处理batchWrite请求所需的 WCU 数量取决于请求中项目的大小。此处有关在 DynamoDB 中管理容量的 AWS 文档建议处理batchWrite请求所需的 WCU 数量计算如下:

BatchWriteItem— 最多将 25 个项目写入一个或多个表。DynamoDB 将批处理中的每个项目作为单独的 PutItem 或 DeleteItem 请求进行处理(不支持更新)。因此,DynamoDB 首先将每个项目的大小舍入到下一个 1 KB 边界,然后计算总大小。结果不一定与所有项目的总大小相同。例如,如果 BatchWriteItem 写入一个 500 字节的项目和一个 3.5 KB 的项目,DynamoDB 将计算大小为 5 KB (1 KB + 4 KB),而不是 4 KB(500 字节 + 3.5 KB)。

尚未提供batchWrite请求中项目的大小,但为了回答,假设每个项目<1KB。 如果请求中有 25 个项目,每个项目<1KB,则每秒处理单个批处理写入请求所需的至少预置容量为 25 个 WCU。假设预配了至少 25 个所需的 WCU,考虑到插入项目的时间限制为 5 秒,仅预配了 25 个 WCU,每秒只能发出一个包含 25 个项目的请求,在 5 秒的时间限制内总共插入了 125 个项目。基于此,为了实现在5秒内插入1800个项目的目标,需要360个WCU来实现目标。

根据此处找到的预置容量的当前定价,360 WCU 的预置容量的成本约为 175 USD/月(不考虑免费套餐积分)。

有两种选项可以处理此问题

  1. 增加预置容量。要在 5 秒内实现 1800 个项目,您需要预配 360 个 WCU。
  2. 更好的选择是简单地切换到On Demand容量。该问题提到写入请求是"随机尖峰操作"。如果写入请求不是对表的可预测且一致的操作,则结果通常是过度预置表并为空闲容量付费。"按需"容量解决了这个问题,并坚持无服务器理念,即只为使用的内容付费,而你只按使用的内容付费。目前,按需定价为1.25美元/100万WCU消费。 基于此,如果每个新用户生成 1800 个要插入的新项目,则每月需要创建 97,223 个新用户,然后表的预置容量与使用按需容量相比具有竞争力。换句话说,在平均每 26 秒注册一个新用户之前,数学建议坚持按需容量(值得注意的是,这不考虑 RCU 或表中的其他项目或其他访问模式)。

相关内容

最新更新