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

Jos*_*e A 1 javascript node.js amazon-dynamodb aws-lambda

编辑 x1:用完整文件替换片段

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

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

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

我已经尝试通过触发它而不是等待它们来调用无限数量的 batchWrite(这会算数吗?我已经读过,因为 JS 是单线程的,所以请求将被一一处理,除了我不会如果我不使用承诺,就等待响应......目前使用 Node 10 和 Lambda),但似乎什么也没发生。如果我承诺调用并等待它,我会收到 Lambda 超时异常(可能是因为它用完了 WCU)。

我目前有 5 个 WCU 和 5 个 RCU(对于这些随机尖峰操作来说,这些是否太小了?)。

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

我该怎么办?

这是我用来插入 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"
  );
}
Run Code Online (Sandbox Code Playgroud)

hep*_*ump 11

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

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

在文档batchWrite中AWS的Javascript SDK操作可以发现这里和以前的答案在这里显示了正确建立和格式化的解决方案batchWrite的要求。

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

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

根据 AWS DynamoDB此处的预置容量文档,a Write Capacity UnitorWCU是计费的,因此定义如下:

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

此处batchWrite / batchWriteItemAPI的 AWS 文档表明,一个API 请求最多支持每个请求 25 个项目,单个项目最大可达 400kb。此外,处理请求所需的 WCU 数量取决于请求中项目的大小。此处用于管理 DynamoDB 容量的 AWS 文档建议处理请求所需的 WCU 数量计算如下:batchWritebatchWritebatchWrite

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 的预置容量来处理单个 batchWrite 请求。假设供应了最少 25 个所需的 WCU,考虑到插入项目的 5 秒时间限制,仅供应 25 个 WCU,每秒只能发出一个具有 25 个项目的请求,在 5 秒的时间限制内总共插入 125 个项目。基于此,为了实现在 5 秒内插入 1800 个项目的目标,需要 360 个 WCU 来实现目标。

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

如何处理此问题有两种选择

  1. 增加配置容量。要在 5 秒内实现 1800 个项目,您将需要配置 360 个 WCU。
  2. 更好的选择是简单地切换到 On Demand容量。问题提到写请求是“随机尖峰操作”。如果写请求在一个表上是不可预测的和一致的操作,那么结果通常是表的过度供应并为空闲容量付出代价。“按需”容量解决了这个问题,并遵循无服务器理念,即只为您使用的内容付费,而您只需为您使用的内容付费。目前,按需定价为 1.25 美元/100 万个 WCU。基于此,如果每个新用户生成 1800 个要插入的新项目,那么每月需要创建 97,223 个新用户,然后为表配置容量与使用按需容量相比具有竞争力。换句话说,直到平均每 26 秒注册一个新用户,