Play 框架在 Amazon RDS 中的应用

IBMdW 发布于 2011/09/05 21:57
阅读 515
收藏 1

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

几个月前,我在本系列中提供了 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。

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

Amazon RDS

Amazon 关系数据库服务是一种 PaaS,提供了一种用于应用程序开发的按需、基于云、可扩展的 MySQL 实例。但是,如果 RDS 是一个在云中运行的 MySQL 实例,我们就不会在这里介绍它。

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

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

设置和配置 RDS

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

在屏幕上,您应该会看到一个对话框,可在其中指定 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 会为您处理维护。

文章转自 IBM developerWorks

加载中
0
wenivan
wenivan
好文章,支持。
返回顶部
顶部