Java 开发 2.0: Play 框架在 Amazon RDS 中的应用

关系数据管理即服务?为什么不是?

Amazon 的关系数据库服务 (RDS) 将维护数据库的工作卸载到 Amazon Web 服务,这使得增加或交换应用程序的数据存储变得出奇的简单。这一月,Andrew Glover 再次探讨他的基于位置的云到移动应用程序,交换原始 NoSQL 数据存储到传统的 RDMS 中。文章中将使用 Play 框架和 AWS 控制台的。

Andrew Glover, 作家和开发人员, Beacon50

Andrew GloverAndrew Glover 是具有行为驱动开发、持续集成和敏捷软件开发激情的开发人员、作家、演说家和企业家。他是 easyb 行为驱动开发(Behavior-Driven Development,BDD)框架的创建者和三本书的合著者:持续集成Groovy 在行动Java 测试模式。您可以通过他的博客与他保持一致并在 Twitter(http://twitter.com/aglover)上关注他。



2011 年 9 月 05 日

关于本系列

自 Java 技术出现伊始,Java 开发领域发生了巨大的变化。得益于成熟的开放源码框架和可靠的可租借部署基础设施,现在我们能够以很低的成本快速组装、测试、运行和维护 Java 应用程序。在 这个文章系列 中,Andrew Glover 探讨使这种新的 Java 开发范型成为可能的技术和工具。

几个月前,我在本系列中提供了 Amazon 的 Elastic Beanstalk 的实用 Java 开发 2.0:攀登 Elastic Beanstalk,Elastic Beanstalk 是一种用于 Java 应用程序开发的平台即服务 (PaaS)。正如我所演示的,Beanstalk 功能非常丰富,允许开发人员使用几乎任何工具组合来完成工作。除了使用 Play 执行快速 Web 开发,我还能够使用另一种 PaaS MongoHQ 来管理我的 MongoDB 实例。将两种 PaaS 基础架构相结合,意味着可以为我处理大多数应用程序维护工作,我可以将精力集中在构建优秀的云到移动应用程序上。

MongoHQ PaaS 出色地完成了该项目,但如果我希望将数据存储在传统的 RDBMS 中怎么办?毕竟,大部分 Java 开发人员更熟悉向关系数据库编码。而且不是每个项目都能不使用 ACID,然而 NoSQL 数据库基本都不支持 ACID。

DB2 pureScale

无论怎么说,按需扩展关系数据库都不是新技术。IBM 的 DB2 pureScale 在许多方面都类似于 RDS,因为可以自动扩展分布式的 DB2 实例,同时实现高水平的数据可靠性。pureScale 通过无限制的容量、持续可用性和应用程序透明性(也就是无需对应用程序执行更改)来支持快速数据增长。可以在 参考资料 中了解关于 pureScale 的更多信息。

本月,我将介绍 Amazon 关系数据库服务 (RDS),这是 Amazon Web 服务家族的另一项优秀且多用途的新添成员。Amazon RDS 使用起来非常简单,类似使用由 MongoHQ 托管的 MongoDB 实例。它的关系很容易管理,但它将带来一些有趣的扩展问题。我们仅需要提前执行一些循环来定义模式,然后就可很好地使用它。

Amazon RDS

Amazon 关系数据库服务是一种 PaaS,提供了一种用于应用程序开发的按需、基于云、可扩展的 MySQL 实例。但是,如果 RDS 是一个在云中运行的 MySQL 实例,我们就不会在这里介绍它。毕竟,我已在 2009 年解释了如何使用运行 MySQL 的 Amazon EC2 映像(参见 参考资料)。

关系扩展

可伸缩性是 NoSQL 得到广泛采用的一个主要原因。NoSQL 诞生的一个原因是,传统的关系系统可能难以在节点上水平扩展,虽然我们使用分片等技术做出了一些工作。并不是说无法在关系系统中的节点上分布数据,只是这样做会增加复杂性和/或成本。关系数据库系统 RDS 中的扩展涉及到在节点之间复制整个数据库,而不是它的一部分。这反过来可能导致数据冗余问题。(参阅 参考资料 了解关于 NoSQL 数据库和 RDBMS 分片的更多信息。)

使 RDS 值得一看的是,它由 PaaS 管理并由 Amazon 操作,提供了与 Elastic Beanstalk 中相同的服务和灵活性。Amazon 提供了备份、复制甚至补丁。而且,RDS 可全面扩展,您只需几次单击即可增加应用程序的存储容量。Amazon 还支持跨可用性区域复制 RDS,所以如果一个区域出现故障或一个区域中计划了一个维护时窗,您仍然可以提供数据。甚至可以配置数据库的只读实例,确保为高容量应用程序或时间段提供更高的读取速度。

已使用 MySQL 而构建的应用程序可以不断利用 RDS,所以尽管数据库处于云中,但其他关于应用程序的所有内容都无需更改。最后,与 AWS 的其他所有方面很类似,RDS 是一种即付即用模型。没有前期的硬件或许可证成本。您会在使用容量、存储和带宽时为它们付费。


设置和配置 RDS

AWS 允许通过命令行或 AWS 管理控制台配置各种服务。我倾向于使用控制台,因为它指定了可用于 RDS 的各个方面的选项。所以,我们首先将在 AWS 管理控制台中选择 RDS 选项卡,单击 Launch Instance 按钮。

注册使用 RDS

像 Amazon Web 服务中的所有功能一样,需要 创建一个帐户 才能使用它们。创建帐户后,可以注册 Amazon RDS。请记住,Amazon 的服务都是即付即用的!

在屏幕上,您应该会看到一个对话框,可在其中指定 MySQL 数据库实例细节,比如机器大小、MySQL 版本和为数据库实例分配了多少存储。请注意,AWS 有一个向多个可用性区域部署数据库的选项。这样做会在本质上创建一个集群,这样,如果特定区域出现故障,其他区域将确保数据库可用。

如图 1 所示,您需要指定数据库的模式名称、管理用户名和密码:

图 1. 设置 RDS 实例
配置 MySQL 数据库实例。

单击 Continue,您将看到另一个对话框,可使用它对数据库进行大体配置。首先是它的名称,名称是其 JDBC URL 中的一部分。也可以更改 MySQL 将监听的端口,选择数据库将存在于的可用性区域,如图 2 所示:

图 2. 配置 RDS 实例
选择数据库可用性区域的屏幕。

接下来是与让 AWS 如何备份数据和计划何时维护相关的管理选项,如图 3 所示:

图 3. RDS 管理选项
通过 AWS 控制台启动和配置数据库管理。

单击 Continue 并检查配置之后,启动 RDS 实例。这可能需要几分钟才能完成,所以正好可以喝杯咖啡或浏览浏览 Twitter。RDS 正常运行之后,操作就快了!

RDS 安全

实例激活后,还需要执行一些操作,才能使用您最喜爱的 SQL 管理工具访问它。如果之前使用过 AWS,那么不应该对默认情况感到惊奇,一些功能被锁定,所以需要显式允许访问。

RDS 的安全约束非常强大,允许您指定可与 RDS 通信的单个 IP 或 IP 范围,但出于本文的意图,我们将保持简单,允许任何 IP 与我的实例通信。为此,我进入 RDS DB Security Group 窗格并将 CIDR/IP 约束编辑为 0.0.0.0/0,这基本上意味着允许所有 IP。这一步如图 4 所示:

图 4. RDS 安全设置
AWS 上的 RDS DB Security Group 窗格的屏幕截图。

完成此步骤后,重新启动 RDS 的实例。(右键单击 AWS Management Dashboard 中的实例,您可以看到重新启动选项。)

如果选择您正在运行的 RDS 实例,将会看到一个 Description 窗格(如图 5 所示),它提供了一些重要细节。我们现在最感兴趣的是端点,它是您将用于连接 MySQL 实例的 URL。

图 5. RDS 仪表板
AWS 控制台上的 RDS 仪表板的屏幕截图。

现在您可以获取最喜爱的数据库管理工具(或者如果愿意,使用命令行),将它指向您的 RDS 实例。我将使用 Sequel Pro,它与大部分面向 GUI 的工具一样,提供了一个优秀的界面来查看表和数据,还提供了一个查询控制台。要进行连接,您需要知道您数据库的用户名、密码和端点 URL。


Magnus、RDBMS 样式

如果阅读我的 Amazon Elastic Beanstalk 简介(参见 参考资料),您会很熟悉我为该文章构建的云到移动应用程序 Magnus。对于 Magnus,我在 MongoDB 中创建了两个集合:AccountLocation。(但是请注意,我可以让一个集合复制 Account,每个文档包含一个嵌入式的 Location 文档。)拥有两个集合使我能够持久保留帐户位置,这些位置在我的应用程序场景中来自全球的移动设备。

我将为演示 Amazon RDS 建模相同的关系,但这次我将采用老式方法。像 Magnus 这样的应用程序(具有来自分散在全球的频繁位置更新)可从 RDS 获益,尤其是在 RDS 支持在众多可用性区域执行集群化时。请记住,RDBMS 领域还有其他一些技术,比如分片,它将数据分解为逻辑分区,所以也可以按地理位置对帐户和位置进行分片。无论如何,集群、复制和分片都具有优缺点,在开始采用一种具体战略时应该认真权衡它们。

为了让 Magnus 程序使用 SQL 数据库,我需要首先定义我的关系表,(可以预测)它将调用 accountlocation。这如清单 1 中所示:

清单 1. account 表
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

在清单 2 中我的 location 表中,我提供了一个指向 account 的外键。这样,我在 account 与它们的各种 location 之间设置了一对多关系。

清单 2. location 表
CREATE TABLE `location` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account_id` int(11) DEFAULT NULL,
  `latitude` double DEFAULT NULL,
  `longitude` double DEFAULT NULL,
  `date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `account_id` (`account_id`),
  FOREIGN KEY (`account_id`) REFERENCES `account` (`id`)
)

定义表之后,我需要在我的 RDS 实例中创建它们。在 RDS 实例中创建表就像在本地机器上运行的 MySQL 实例中创建它们一样。只需打开一个终端或使用您最喜爱的 GUI 打开您的 RDS 端点并创建表。就这么简单。


配置 Play

Play Web 应用程序框架(参见 参考资料)在 Amazon RDS 中的工作原理与在 Elastic Beanstalk 中类似,所以我将再次使用它来开发我的应用程序。Play 使得切换各种数据存储非常轻松,它开箱即用地支持 JPA。从 MongoHQ 实现切换到使用 Amazon RDS 的实现只需对我的模型进行少量更改。首先,Play 内置的 JPA 支持意味着我需要修改 Magnus 的 application.conf 文件并将内容指向我的 RDS 实例,如清单 3 所示:

清单 3. location 表
db.url=jdbc:mysql://magnus.cp3pl5vineyp.us-east-1.rds.amazonaws.com/magnus_locations
db.driver=com.mysql.jdbc.Driver
db.user=admin
db.pass=g3tf0kl

这里没有需要注意的特殊内容。清单 3 百分之百是 JDBC!

建模关系

与几乎所有 RDBMS ORM 库一样,我将使用顶级 Java 对象在一种一对一关系中建模我的表:一个 Account 类型和一个 Location 类型。我的 Location 将链接回 Account

从 Play 的模型类型扩展,为我提供了一些内置的免费服务。首先,我获得一个类似 finder 的方法,以及典型的 CRUD 方法 savedelete

我的 Account 类利用了两个 JPA 注释。清单 4 中所示的 Table 注释需要指向我重命名的(小写的)account 表。

清单 4. 一种 Account 类型
package models;

import play.db.jpa.Model;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "account") //required otherwise table is Account
public class Account extends Model {
 public String name;
}

我的 Location POJO(如清单 5 中所示)稍微复杂一点。我需要向它添加两个额外的注释,以在 LocationAccount 之间创建一种多对一的关系。

清单 5. 使用 JPA 定义的 Location 类
package models;

import play.db.jpa.Model;
import javax.persistence.*;
import java.math.BigDecimal;
import java.sql.Timestamp;

@Entity
@Table(name = "location")
public class Location extends Model {

 public BigDecimal latitude;
 public BigDecimal longitude;
 public String name;
 @Column(name = "date_time")
 public Timestamp timestamp;

 @ManyToOne
 @JoinColumn(name="account_id", nullable = false)
 public Account account;

}

最后,在清单 6 中,我更新了 Application 控制器的 saveLocation 方法。(请记住,在以前的 Magnus 实现中,我将所有对 /location/ 的 HTTP PUT 路由到了此方法。)saveLocation 创建一个新 Location 对象(因此创建了一条相应的记录)并将此 Location 实例链接到现有的 Account。因为我扩展了之前的 Play 的 Model 对象,所以我也获得了一个方便的 findById 方法。

清单 6. 使用 RDS 进行基于位置的更新
public static void saveLocation(String id, JsonObject body) throws Exception {
 String eventname = body.getAsJsonPrimitive("name").getAsString();
 double latitude = body.getAsJsonPrimitive("latitude").getAsDouble();
 double longitude = body.getAsJsonPrimitive("longitude").getAsDouble();

 Location loc = new Location();
 loc.longitude = new BigDecimal(longitude);
 loc.latitude = new BigDecimal(latitude);
 loc.name = eventname;
 loc.account = Account.findById(new Long(id));

 loc.save();

 renderJSON(getSuccessMessage());
}

使用 RESTClient 进行测试

我可以使用 RESTClient 确定我更新的位置服务是否有效。就像我对 Magnus 所做的一样,我将形成一些 JSON 文档并发送它们。

图 6. 使用 RESTClient 进行测试
RESTClient 界面的屏幕截图。

当我的方法成功持久化一条新 Location 记录时,会发送回一条 JSON 响应来表明成功。因为我的二选一式 GUI 允许我查看 RDBMS 中的数据,我只需检查我的 location 表,您猜怎么着?我通过 RDS 看到位于云中的新 Magnus 记录!

图 7. 瞧,您将到达的目的地!
云中的 Magnus,显示在 AWS 控制台上。

结束语

PaaS 是希望快速开发和部署 Web 应用程序的软件开发团队的好伙伴。在本文中,我介绍了 Amazon RDS,一个将关系数据库(在本例中为 MySQL,但 RDS 也支持 Oracle 数据库)放在云中的 PaaS 解决方案。Amazon RDS 很容易配置,它的操作与您可能构建了多年的各种 RDBMS 系统没什么区别。重要的区别在于 Amazon 会为您处理维护。

参考资料

学习

获得产品和技术

讨论

  • 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology, Cloud computing
ArticleID=755736
ArticleTitle=Java 开发 2.0: Play 框架在 Amazon RDS 中的应用
publish-date=09052011