DynamoDB 中的定期付款架构设计
定期付款业务使用场景
这个使用场景讨论了如何使用 DynamoDB 来实现定期付款系统。数据模型具有以下实体:账户、订阅以及收据。我们的使用场景的具体内容包括以下各项:
-
每个账户可以有多个订阅
-
当需要处理下一笔付款时,订阅具有
NextPaymentDate
;当向客户发送电子邮件提醒时,则具有NextReminderDate
-
订阅有一个项目,此项目在处理付款时存储并更新(平均项目大小约为 1KB,吞吐量取决于账户和订阅的数量)
-
付款处理器还将创建收据作为此过程的一部分,该收据存储在表中,并通过使用 TTL 属性设置为在一段时间后过期
定期付款实体关系图
这是我们将为定期付款系统架构设计使用的实体关系图(ERD)。
![定期付款系统 ERD 显示实体:Account、Subscription 和 Receipt。](images/DataModeling/ReoccurringPayments-1-ERD.png)
定期付款系统访问模式
这些是我们将为定期付款系统架构设计考虑的访问模式。
-
createSubscription
-
createReceipt
-
updateSubscription
-
getDueRemindersByDate
-
getDuePaymentsByDate
-
getSubscriptionsByAccount
-
getReceiptsByAccount
定期付款架构设计
通用名称 PK
和 SK
用于键属性,以允许在同一个表中存储不同类型的实体,例如账户、订阅和收款实体。用户首先创建订阅,即用户同意在每个月的同一天支付一定金额以换取产品。他们可以选择在一个月的哪一天处理付款。在处理付款之前,还会发送提醒。该应用程序的工作原理是每天运行两个批处理任务:一个批处理任务发送当天到期的提醒,另一个批处理任务处理当天到期的任何付款。
步骤 1:解决访问模式 1 (createSubscription
)
访问模式 1(createSubscription
)用于最初创建订阅,并设置详细信息,包括 SKU
、NextPaymentDate
、NextReminderDate
和 PaymentDetails
。此步骤仅显示一个账户(具有一个订阅)的表状态。项目集合中可能有多个订阅,因此这是一种一对多关系。
![这一表设计显示账户的订阅详细信息。](images/DataModeling/ReoccurringPayments-2-Step1.png)
步骤 2:解决访问模式 2(createReceipt
)和 3(updateSubscription
)
访问模式 2(createReceipt
)用于创建收据项目。每月处理付款后,付款处理器会将收据写回基表。项目集合中可能有多张收据,因此这是一对多关系。付款处理器还将更新订阅项目 [访问模式 3(updateSubscription
)],以针对下个月的 NextReminderDate
或 NextPaymentDate
进行更新。
![收据详细信息和订阅项目更新,来显示下一个订阅提醒日期。](images/DataModeling/ReoccurringPayments-3-Step2.png)
步骤 3:解决访问模式 4(getDueRemindersByDate
)
该应用程序会分批处理当天的付款提醒。因此,应用程序需要在不同的维度上访问订阅:日期而不是账户。这是全局二级索引(GSI)的一个很好的使用场景。在此步骤中,我们添加索引 GSI-1
,它使用 NextReminderDate
作为 GSI 分区键。我们不需要复制所有项目。此 GSI 是一个稀疏索引,并且未复制收据项目。我们也不需要投影所有属性 — 我们只需要包含属性的子集。下图显示了 GSI-1
的架构,它提供了应用程序发送提醒电子邮件所需的信息。
![此 GSI-1 架构包含电子邮件地址等详细信息,应用程序需要这些信息来发送提醒电子邮件。](images/DataModeling/ReoccurringPayments-4-Step3.png)
步骤 4:解决访问模式 5(getDuePaymentsByDate
)
该应用程序以与对待提醒相同的方式批处理当天的付款。我们在此步骤中添加 GSI-2
,它使用 NextPaymentDate
作为 GSI 分区键。我们不需要复制所有项目。此 GSI 是一个稀疏索引,因为未复制收据项目。下图显示了 GSI-2
的架构。
![此 GSI-2 架构包含处理付款的详细信息。NextPaymentDate 是 GSI-2 的分区键。](images/DataModeling/ReoccurringPayments-5-Step4.png)
步骤 5:解决访问模式 6(getSubscriptionsByAccount
)和 7(getReceiptsByAccount
)
应用程序可以通过对以账户标识符(PK
)为目标的基表使用查询来检索账户的所有订阅,并使用范围运算符来获取 SK
以“SUB#”开头的所有项目。应用程序还可以使用相同的查询结构来检索所有收据,方法是使用范围运算符来获取其中 SK
以“REC#”开头的所有收据。这使我们能够满足访问模式 6(getSubscriptionsByAccount
)和 7(getReceiptsByAccount
)的要求。应用程序使用这些访问模式,因此,用户可以查看他们当前的订阅和过去六个月的收据。在此步骤中,表架构没有发生任何变化,我们可以在下面看到我们如何仅将访问模式 6(getSubscriptionsByAccount
)中的订阅项目作为目标。
![对基表执行查询操作的结果。它显示特定账户的订阅。](images/DataModeling/ReoccurringPayments-6-Step5.png)
下表总结了所有访问模式以及架构设计如何解决访问模式:
访问模式 | 基表/GSI/LSI | 操作 | 分区键值 | 排序键值 |
---|---|---|---|---|
createSubscription | 基表 | PutItem | ACC#account_id | SUB#<SUBID>#SKU<SKUID> |
createReceipt | 基表 | PutItem | ACC#account_id | REC#<RecieptDate>#SKU<SKUID> |
updateSubscription | 基表 | UpdateItem | ACC#account_id | SUB#<SUBID>#SKU<SKUID> |
getDueRemindersByDate | GSI-1 | 查询 | <NextReminderDate> | |
getDuePaymentsByDate | GSI-2 | 查询 | <NextPaymentDate> | |
getSubscriptionsByAccount | 基表 | Query | ACC#account_id | SK begins_with “SUB#” |
getReceiptsByAccount | 基表 | Query | ACC#account_id | SK begins_with “REC#” |
定期付款最终架构
这是最终的架构设计。要以 JSON 文件格式下载此架构设计,请参阅 GitHub 上的 DynamoDB 示例
基表
![此基表设计显示账户信息及其订阅和收据详细信息。](images/DataModeling/ReoccurringPayments-7-Base.png)
GSI-1
![此 GSI-1 架构包含订阅详细信息,例如电子邮件地址和 NextPaymentDate。](images/DataModeling/ReoccurringPayments-8-GSI1.png)
GSI-2
![此 GSI-2 架构包含付款详细信息,例如 PaymentAmount 和 PaymentDay。](images/DataModeling/ReoccurringPayments-9-GSI2.png)
在此架构设计中使用 NoSQL Workbench
若要进一步探索和编辑新项目,您可以将此最终架构导入到 NoSQL Workbench,这是一款为 DynamoDB 提供数据建模、数据可视化和查询开发功能的可视化工具。请按照以下步骤开始使用:
-
下载 NoSQL Workbench。有关更多信息,请参阅 下载 NoSQL Workbench for DynamoDB。
-
下载上面列出的 JSON 架构文件,该文件已经采用 NoSQL Workbench 模型格式。
-
将 JSON 架构文件导入到 NoSQL Workbench。有关更多信息,请参阅 导入现有数据模型。
-
导入到 NOSQL Workbench 后,您便可编辑数据模型。有关更多信息,请参阅 编辑现有数据模型。
-
要将数据模型可视化、添加样本数据或从 CSV 文件导入样本数据,请使用 NoSQL Workbench 的数据可视化工具功能。