使用 Apache ofBiz 和 Amazon Aurora DSQL 启动并运行
在设计 Amazon Aurora DSQL 时,我们花了很多时间试图在创新和改进与易用性之间取得适当的平衡。除非有非常令人信服的理由,否则我们不想打乱现有 PostgreSQL 用户的熟悉程度。属于这一类别的两个领域是乐观并发控制 (OCC) 行为和身份验证模型,习惯于常规 PostgreSQL 的应用程序开发人员可能会对系统的行为感到陌生。
在这篇文章中,我们向您展示了一个成功的示例,该示例使用了在 PostgreSQL 数据库上运行的现有应用程序,然后对其进行调整以使其与 Amazon Aurora DSQL 数据库配合使用。除了适应前面提到的方面外,我们还解决了一些数据类型不兼容的问题,并绕过了 Amazon Aurora DSQL 中目前存在的一些限制。
该应用程序
为了使这个示例尽可能具有代表性,我们选择了一个开源应用程序,该应用程序具有代表现实世界应用程序的显著功能多样性和复杂性。该应用程序是 Apache ofBiz,源代码可以从 GitHub 存储库中下载。本概念验证中使用的版本是 18.12.16。
ofBiz 应用程序是一个功能强大的 ERP 和 CRM 软件包,它为我们的目标提供了一个很好的例子:
- 复杂架构:837 个表,4161 个索引
- 抽象实体引擎(Java 持久化、Java 事务、自定义 ORM)
- 已经支持 PostgreSQL
- 演示数据和内置加载器功能
- 本质上主要是核心关系,这与 Amazon Aurora DSQL 最初的兼容性重点非常吻合
这篇文章的目的是将我们内部概念验证的叙述与一些具体的代码示例相结合,说明如何在基于连接池的 Java 应用程序中进行 Amazon Aurora DSQL 身份验证。尽管我们提供了尽可能多的上下文,但我们的目标并不是提供一组详尽的命令和代码来重现同样的旅程。
Amazon Aurora DSQL
与社区 PostgreSQL 相比,Amazon Aurora DSQL 是一个兼容 PostgreSQL 的数据库,但有一些语义差异,旨在提高该服务的可扩展性和安全性。其中一些方面,尤其是与 PostgreSQL 特性的功能兼容性广度,将随着时间的推移而迅速发展,但少数方面是系统的基础。这些是 OFBiz 应用程序中所做更改的主要重点,如本文所示。这些方面是:
- Amazon Aurora DSQL 身份验证模型 — 如何连接到数据库并保持连接。
- 交易大小限制 — Amazon Aurora DSQL 不支持无限交易大小。
- 隔离级别 — Amazon Aurora DSQL 仅支持快照隔离,相当于 PostgreSQL 中的可重复读取。
- 乐观的并发控制 — Amazon Aurora DSQL 不会在交易的构建阶段解除锁定;它在提交时强制保持一致性。这意味着提交可能会失败,必须从一开始就重试。
- 密钥中的数据类型限制 — 目前,主密钥和辅助密钥支持的类型(和大小)存在限制。随着产品的额外类型支持,Amazon Aurora DSQL 中的数据类型限制将随着时间的推移而减少。本文中记录的缓解措施反映了 Amazon Aurora DSQL 预览阶段的限制。
为 Amazon Aurora DSQL 创建数据源配置
我们需要做的第一件事是为 Amazon Aurora DSQL 数据库定义新的数据源配置。我们在 framework/entity/config/entityengine.xml 中添加了一个名为 localdsql 的新数据源并将其选为活动数据源。数据源参数是从现有的 localpostgres 数据源复制的,带下划线的设置已更改,如下所示:
在前面的示例配置中,我们编辑了的终端节点部分 jdbc-uri
——如果您在自己的集群上尝试此操作,请不要忘记更新该 <Aurora DSQL_URL>
值以反映您的 Amazon Aurora DSQL 集群的终端节点。
我们将设置 jdbc-password
为一个神奇的常量值 IAM_AUTH
。OfBiz 假设我们将使用常规密码认证来连接数据库,但是 Amazon Aurora DSQL 需要基于 Amazon Identity and Access Management(IAM)的身份验证,从而提供更加集成和安全的环境。在下一步中,我们在代码中添加对此的支持。
我们还将隔离级别更改为 RepeatableRead
(这是相当于 Amazon Aurora DSQL 快照隔离级别的 PostgreSQL 行为),并增加了最低池大小(在 Amazon Aurora DSQL 中维护连接的成本较低,但加密连接的创建速度相对较慢)。Amazon Aurora DSQL 仅支持加密连接,因此我们将该参数添加到 JDBC URI 中。我们还部署了最新的 PG JDBC 驱动程序 jar(撰写本文时为 42.7.4),以确保它是 Amazon Aurora DSQL 的认证修订版。
实现 Amazon Aurora DSQL 连接逻辑
为 Amazon Aurora DSQL 构建连接逻辑时有三个注意事项:
- 密码实际上是动态身份验证令牌,在验证 IAM 身份验证时按需生成。
- 身份验证令牌过期——它们仅在生成时指定的时间段内有效。这可能长达一周,这对于使用开发工具很有好处,但我们建议应用程序连接的到期时间要低得多,以限制未经授权的访问风险。在本例中,我们选择了 3 个小时。
- 连接也会过期,目前每小时一次。起初,对于新的 Amazon Aurora DSQL 用户来说,身份验证令牌和连接到期之间的交互可能会感到困惑,因此请记住,身份验证令牌仅在建立连接时适用(令牌在新连接时必须仍然有效),连接到期仅影响现有连接(建立连接后不考虑令牌到期)。
为了实现对该方案的支持,我们首先进行了修改 framework/entity/src/main/java/org/apache/ofbiz/entity/config/model/EntityConfig.java
以支持 Amazon Aurora DSQL 特定的身份验证流程,并添加了以下逻辑:
然后,我们修改 framework/entity/src/main/java/org/apache/ofbiz/entity/connection/DBCPConnectionFactory.java
为在数据源为 localdsql 时使用 Amazon Aurora DSQL 专属的 ConnectionFactory。我们还将池中的最大连接寿命设置为略小于 Amazon Aurora DSQL 中支持的最大连接时间。
最后,我们添加了管理连接的核心逻辑,包括将 Amazon Aurora DSQL SessionID 添加到连接属性中以更好地进行诊断。就涉及 Amazon Aurora DSQL 的事项联系亚马逊云科技支持部门时,能够提供受影响的特定连接的会话 ID 会很有帮助。
我们实现了以下具体类:
- 框架/实体/src/main/java/org/apache/ofbiz/Entity/Connection/Aurora DSQLAuth.java
- 框架/实体/src/main/java/org/apache/ofbiz/Entity/Connection/Aurora DSQLConnectionFactory.java
- 框架/实体/src/main/java/org/apache/ofbiz/Entity/Connection/Aurora DSQLConnection.java
修改架构
为了符合目前适用于 Amazon Aurora DSQL 的限制,我们对基础架构进行了最少的更改。大部分架构已经与 Amazon Aurora DSQL 兼容,但如果我们不想使用现有的演示数据,我们本可以走得更远(将在下一节中详细介绍)。
我们需要解决的限制都与适用于 Amazon Aurora DSQL 在密钥中支持的类型的限制有关:
NUMERIC
密钥中目前不支持类型:- 我们将的类型修改
applications/datamodel/entitydef/product-entitymodel.xml
并更改minimumOrderQuantity
为 afloating-point
(float
) 而不是fixed-point
(NUMERIC(18,6)
)。通常,这两种类型在逻辑上不可互换,但是一些演示数据表示为十进制数据。回想起来,这里更好的更改是修改演示数据,但是逻辑似乎确实可以正常工作(因为它使用的不仅仅是测试)。 - 我们进行了修
framework/entity/fieldtype/fieldtypepostgres.xml
改,将的定义更改<field-type-def type="numeric" sql-type="NUMERIC(20,0)" java-type="Long"/>
为<field-type-def type="numeric" sql-type="bigint" java-type="Long"/>
。的使用实际上bigint
比更合适NUMERIC(20,0)
。
- 我们将的类型修改
VARCHAR
密钥支持类型,但最大大小比非密钥VARCHAR
要适中:- 我们进行了修
framework/entity/fieldtype/fieldtypepostgres.xml
改,将的定义更改<field-type-def type="email" sql-type="VARCHAR(320)" java-type="String"/>
为<field-type-def type="email" sql-type="VARCHAR(220)" java-type="String"/>
。
- 我们进行了修
进行这些更改后,可以在数据加载步骤中成功创建架构(参见下一节)。我们在 OFBIZ 加载器实用程序中明确使用了该 -l drop-constraints
选项,以确保没有尝试使用外键约束创建表,Amazon Aurora DSQL 目前不支持外键约束。
如前所述,我们本可以选择进一步优化架构。我们不需要做的一项具体更改是将 ID
字段类型更改为使用该 UUID
类型,这在基于 ORM 的应用程序中通常是预期的。因为我们使用的是演示数据,所以我们需要修改演示数据中的所有密钥(和引用)才能采用 UUID
类型。取而代之的是,我们保留了当前使用 VARCHAR
基于密钥的方式,并未更改加载演示数据。
加载演示数据
OFBIZ 数据加载器(参见 OFBIZ 技术设置指南)最初在两次提交之间执行了大量插入,在某些情况下,这超过了 Amazon Aurora DSQL 中的交易大小限制。为了解决这个问题,我们修改了中的 storeAll()
方法, framework/entity/src/main/java/org/apache/ofbiz/entity/GenericDelegator.java
将批量数据批量加载为 1,000 行增量:
注意:Amazon Aurora DSQL 中的交易大小限制大于 1,000 行,但我们选择这个较低的数字是为了更容易观察逻辑更改的批处理行为。
我们还修复了另一个很有意思的问题。部分数据加载逻辑将调用 findKey()
framework/entity/src/main/java/org/apache/ofbiz/entity/util/EntityCrypto.java
以验证数据库中是否存在加密密钥。如果密钥不在预期存在的地方,则数据加载将因错误而停止。使用 Amazon Aurora DSQL 进行测试时,每次都会触发这个不变量。经过一番挖掘,我们确定这里的逻辑中存在一个通用错误,这导致读取提交隔离的行为与可重复读取不同。该 findKey()
方法是在没有启动新事务的情况下调用的,因此它只能看到截至当前事务快照时的数据。由于该快照时间早于相应的提交时间 INSERT
, findKey()
因此无法观察到新插入的行。在已提交读取隔离级别中, findKey()
调用成功,因为会话可以观察自事务开始以来提交的数据。为了解决这个问题,我们只需在每次输入时开始一笔新的交易 findKey()
:
我们按照 OFBIZ 技术设置指南中的说明加载了种子和演示数据。
在事务命令模式中处理 OCC 中止
ofBiz 应用程序使用命令模式(带有 Callable
接口)将交易提交到数据库,这使得处理 Amazon Aurora DSQL 交易变得简单。以这种方式包装完整交易的其他(非 OFBIZ)应用程序也同样可以管理,因为所有情况的交易边界都有明确的定义。至少出于演示的目的,这里所需要的只是围绕交易执行的重试循环,可以在 InTransaction.call()
方法中 framework/entity/src/main/java/org/apache/ofbiz/entity/transaction/TransactionUtil.java
找到:
注意:对于生产应用程序,我们还建议实现逻辑以提供指数退避和抖动,从而改善高争用条件下的系统行为。
不以这种方式对交易进行正式建模的现有应用程序可能需要更深入的分析,才能确定正确处理 OCC 中止所需的条件。在我们进一步了解客户体验并确定最常见的模式之后,我们计划在未来写一篇关于这个主题的文章。
结论
在这篇文章中,我们向您介绍了我们对现有复杂应用程序所做的各种更改。我们对架构进行了细微修改以使用支持的数据类型,创建了与 Amazon Aurora DSQL 身份验证机制进行正确交互的新逻辑,为数据加载实现了提交批处理,并使事务处理程序在 OCC 语义上正常运行。
尽管这种概念验证侧重于技术可行性而不是生产就绪性,但它成功地证明了 Amazon Aurora DSQL 可以通过合理的迁移工作来支持诸如 OFBIZ 之类的复杂数据库应用程序。该练习证实,即使是具有复杂架构的应用程序也可以通过对身份验证、交易处理和架构设计进行有针对性的修改,调整以适应 Amazon Aurora DSQL,包括增强安全性和可扩展性功能。
在规划自己向 Amazon Aurora DSQL 的迁移时,同样的方面是主要关注领域:
- 在架构中使用支持的数据类型,包括密钥
- 实现 Amazon Aurora DSQL 所需的基于 IAM 的身份验证逻辑
- 确保交易大小在 Amazon Aurora DSQL 限制之内
- 实现指数和可重试事务
如果您正在使用 Amazon Aurora DSQL 开发现有应用程序,我们邀请您在评论部分留下您的经验和观察的评论!
作者简介
詹姆斯·莫尔是亚马逊云科技的首席工程师,从一开始就深入参与了 Amazon Aurora DSQL 的设计和交付。自 20 世纪 90 年代初以来,他一直在设计和构建超大规模的数据库。