amazon推荐的在生产DynamoDB中更改大型表的模式的方法是什么?
想象一个假设的情况,其中我们有一个Person表,其主哈希键为SSN。这个表可以包含1000万个条目。
现在有消息说,由于身份盗窃的数量非常多,这个假想的国家的政府引入了另一种个人身份识别:唯一个人标识符,或UPI。
我们必须添加一个UPI列并更改Person表的模式,因此现在主哈希键是UPI。我们希望在一段时间内同时支持使用SSN的当前系统和使用UPI的新系统,因此我们需要这两列在Person表中共存。
amazon推荐的模式更改方法是什么?
有几种方法,但首先您必须了解不能更改现有表的模式。要获得不同的模式,必须创建一个新表。您可能能够重用您现有的表,但结果将与创建另一个表相同。
- 延迟迁移到同一个表,没有流。每次修改Person表中的条目时,使用UPI而不是SSN作为散列键值,在Person表中创建一个新项,并删除以SSN为键值的旧项。这假定UPI从不同于SSN的值范围中提取。如果SSN看起来像XXX-XX-XXXX,那么只要UPI的位数与SSN的位数不同,就永远不会有重叠。
- 延迟迁移到同一表,使用Streams。当流变得普遍可用时,您将能够为Person表打开流。创建具有NEW_AND_OLD_IMAGES流视图类型的流,并且每当您检测到对person表中现有人员添加UPI的项的更改时,创建一个Lambda函数,删除以SSN为键值的人员,并添加以UPI为键值的具有相同属性的人员。这种方法具有竞争条件,可以通过向项添加原子反版本属性并在版本属性上约束DeleteItem调用来缓解。
- 先发制人(脚本化)迁移到另一个表,使用Streams。运行一个脚本,扫描您的表,并向Person表中的每个Person-item添加唯一的UPI。使用NEW_AND_OLD_IMAGES流视图类型在Person表上创建一个流,并向该流订阅一个lambda函数,当lambda函数检测到具有UPI的Person被更改或当Person添加了UPI时,该流将在新的Person_UPI表中写入所有新的Persons。基表上的变化通常需要数百毫秒才能作为流记录出现在流中,因此您可以对应用程序中的新Person_UPI表进行热故障转移。拒绝请求几秒钟,在这段时间内将应用程序指向Person_UPI表,然后重新启用请求。
DynamoDB流使我们能够在不停机的情况下迁移表。我这样做非常有效,我遵循的步骤是:
- 创建一个新表(我们称之为NewTable),包含所需的键结构,LSIs, GSIs。
- 在原表上启用DynamoDB Streams
- 将Lambda关联到Stream,将记录推入NewTable。(这个Lambda应该在步骤5中去掉迁移标志)
- [可选]在原始表上创建GSI以加速扫描项。确保此GSI只有以下属性:主键和已迁移(见步骤5)。
-
扫描在上一步(或整个表)中创建的GSI,并使用以下过滤器:
FilterExpression = "attribute_not_exists(migrate) "
用迁移标志更新表中的每个项(即:" migrate ": {" S ": " 0 "},将其发送到DynamoDB Streams(使用UpdateItem API,以确保没有数据丢失发生)。
:您可能希望在更新时增加表上的写容量单元。
- Lambda将拾取所有项,修剪掉migrate标志并将其推入NewTable。
- 一旦所有的项目都被迁移,重新将代码指向新的表
- 删除原表,Lambda函数一次皆大欢喜。
遵循这些步骤应该确保您没有数据丢失和停机时间。
我已经在我的博客上记录了这个,用代码来帮助:https://www.abhayachauhan.com/2018/01/dynamodb-changing-table-schema/
如果更改涉及更改分区键,则可以添加新的GSI(全局二级索引)。此外,您可以随时向DynamoDB添加新的列/属性,而无需迁移表。
我使用Alexander的第三种方法的变体。同样,您将创建一个新表,该表将随着旧表的更新而更新。不同之处在于,您在转换时使用现有服务中的代码来写入两个表,而不是使用lambda函数。您可能有不想在临时lambda函数中重新生成的自定义持久性代码,并且很可能必须为这个新表编写服务代码。根据您的体系结构,您甚至可以在不停机的情况下切换到新表。