Redis、Spring Data 和 Cloud Foundry 入门

工程 | Costin Leau | 2011 年 4 月 27 日 | ...

NoSQL 解决方案流行的驱动因素之一是性能(尤其是在高负载下)。由于其数据模型,键值存储位居前列,提供了轻量级而灵活的数据处理方式。在这篇文章中,我将快速展示如何使用 Spring (Spring Redis) 通过 Spring Data 的一个示例 (RetwisJ) 与键值存储 (Redis) 协作,并将应用程序部署到(通过 Cloud Foundry)中与世界分享。我甚至更进一步,尝试使用 Windows 作为部署平台。

Redis

在键值存储中,一个受欢迎的选择Redis,一个开源的、速度极快的数据库,用 ANSI C 编写,服务器大约只有 200 KB(没错,是字节),整个软件包(包括命令行客户端和一些管理工具)也只有 400 KB,几乎支持所有主流平台,这也使其成为示例的选择。请注意,除非您想在本地运行示例,否则不需要 Redis 实例。如果是这样,对于 Windows 用户(例如本文作者),我本人使用(并推荐)这个预打包版本,提供 32 位和 64 位版本。

Spring 与 NoSQL

如果您在 Java 环境中使用 NoSQL,请看看 Spring Data:它本身不是一个项目,而是一个涵盖各种新数据访问技术的项目伞,例如非关系型数据库(如 Redis 或 MongoDB)、MapReduce 框架(如 Hadoop)以及基于云的 Java 应用数据服务。Spring Data 倡导经典的 Spring 价值观,通过消除 API 噪音、样板代码和资源管理,并提供一致的编程模型来提高开发人员的工作效率。它建立在现有的 Spring 特性和项目之上(例如控制反转、生命周期管理、类型转换、可移植数据访问异常、缓存等等),因此可以立即将其添加到应用程序中,只需极少的努力。当然,就像所有 Spring 项目一样,它是开源的,并遵循 Apache 许可证。

Spring Data Redis

对于 Redis,Spring Data 通过 Spring Data Redis 或简称 Spring Redis 项目提供了专门的支持。它提供低级和高级功能,包括可移植的 Redis 客户端抽象(允许通过一行配置切换不同的 Redis 客户端,如 Jedis、JRedis 或 RJC),以及由 Redis 支持的原子集合或计数器,或发布-订阅支持。项目参考文档详细介绍了这些主题。

RetwisJ, YATC - 又一个 Twitter 克隆

RetwisJ 源代码,包括本博客中的代码,可以在 Spring Data Key Value 的示例项目中下载。此外,文档可以在此处获取

RetwisJ 可以看作是 Redis Retwis 示例的 Java 移植:一个简单的 Twitter 克隆,演示了如何用 Redis 灵活的数据模型(例如集合交集)替代传统关系型数据库中开销高昂的联接。

从表格思维模式迁移到键值关联可能看起来很难,但事实并非如此:与其将多个值存储在一个键下,不如将每个值存储在“类似的键”下;事实上,关系本身也可以这样存储。正如文档中所述,与其为用户创建一个表(包含用户名、密码等列),不如通过 Redis 哈希(或 map)存储各项,并为条目之间的关系添加一个单独的、反向的或查找键,而不是创建索引。因此,以下表格结构(用户)可以部署为以下键值对:

用户名密码
1springrodinterface21
2costinlthis is fun
  变为  
类型
uid:1hash{name: springrod, pass: interface21}
uid:2hash{name: costinl, pass: secret}

类似地,关注者与被关注者(或目标)之间的关联表可以通过 Redis Sets 进行映射。因此,与其执行表联接,不如简单地进行集合交集。Redis 丰富的数据模型(Sets、Z-Sets(或有序集合)、Lists 和 Hashes)通过 Spring Redis 可以很好地映射到 Java 集合,Spring Redis 提供了相应的java.util基于 Redis 的实现。这意味着可以使用众所周知的接口遍历、查找或修改列表和集合,而无需手动发出任何 Redis 命令。

例如

private RedisSet<String> following(String uid) {
   return new DefaultRedisSet<String>(KeyUtils.following(uid), template);
}
      
public Collection<String> commonFollowers(String uid, String targetUid) {
   Set<String> followers = following(uid).
       intersectAndStore(following(targetUid),
       KeyUtils.commonFollowers(uid, targetUid));
   ...
}

对于通用数据访问,Spring Redis 的核心是RedisTemplate它允许进行各种操作,从轻松地对富对象进行一行式操作、序列化(无论是字节数组、XML 还是基于 Jackson 的)或消息发布,到高级查询功能和数据获取(例如通过 Redis SORT/GET 模式避免臭名昭著的 N+1 问题)。

// adding entries into a hash
BoundHashOperations<String, String, String> userOps = template.boundHashOps(KeyUtils.uid(uid));
userOps.put("name", name);
userOps.put("pass", password);
valueOps.set(KeyUtils.user(name), uid);

有关数据模型和示例的更深入解释,请查阅 RetwisJ 文档

连接到 Redis

Java 用户连接到 Redis 时面临的一个常见问题是使用哪个客户端(或驱动程序)。Spring Redis 以一致的方式支持三个不同的库(JedisJRedisRJC),因此可以在它们之间切换而无需重写任何代码。让我们选择 Jedis,看看应用程序配置是什么样的

<beans>
  <context:property-placeholder location="classpath:redis.properties"/>

  <!-- Redis client -->
  <bean id="connectionFactory" class="org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory"
		p:host-name="${redis.hostname}" p:port="${redis.port}" p:password="${redis.password}"/>

	<bean id="redisTemplate" class="org.springframework.data.keyvalue.redis.core.StringRedisTemplate" 
		p:connection-factory-ref="connectionFactory"/>

	<context:annotation-config />
	<context:component-scan base-package="org.springframework.data.redis.samples"/>

</beans>

非常直观 - 我们声明驱动程序和 Redis 属性(通过属性占位符从redis.properties)在运行时替换),我们启用注解配置并扫描 classpath 以查找 bean。

从部署的角度来看,RetwisJ 只是一个 Web 应用程序,一个 WAR 包,可以部署到任何 (Servlet 2.5) Web 容器中,例如 Tomcat。它由一个简单的 Spring@MVC控制器、一个Repository类和两个领域对象PostUser。为了遵循 Retwis 示例,即使安全也将通过 Redis 处理,而不是容器的HttpSession- 这不仅展示了键值存储的另一个用例,而且还提高了可伸缩性,因为 Redis(以及用户数据)本身就是分布式的。

要构建它,只需在根文件夹中键入

./gradlew build

要运行它,请将生成的 war 包(build/libs/retwisj.war)部署到您选择的 Web 容器中。

将 RetwisJ 部署到 Cloud Foundry

Cloud Foundry 就绪的 RetwisJ 示例可在专门的示例仓库中获取

将上面的 WAR 包部署到 Cloud Foundry 非常简单 - 您只需要一个账户(可以在此处免费注册)。注册后,您可以使用该账户通过 STS(如之前文章详细描述的)或命令行(vmc)部署您的应用程序,这就是本文将使用的方式。

由于我们使用 Redis,我们需要将本地实例属性替换为适用于 Cloud Foundry 的属性,这些属性以环境变量的形式公开。正如这些文档中提到的,Spring 通过以下方式提供了专门的支持cloud命名空间。

我们可以利用这一点,而不是从本地文件读取 Redis 属性,而是从环境中获取它们

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:p="http://www.springframework.org/schema/p"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:cloud="http://schema.cloudfoundry.org/spring"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
      http://schema.cloudfoundry.org/spring http://schema.cloudfoundry.org/spring/cloudfoundry-spring.xsd">

  	<cloud:service-properties id="cfoundryEnv" />
  	<context:property-placeholder properties-ref="cfoundryEnv"/>
	  
    <bean id="connectionFactory" class="org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory"
      p:host-name="${redis.hostname}" p:port="${redis.port}" p:password="${redis.password}"/>

属性名称不需要改变 - 我们可以命名(本例中为redis)绑定到应用程序的 Redis 实例,并利用这一点最小化本地环境和云环境之间的变化。

请注意,这只是众多选项之一:您可以使用 Spring 3.1 的profiles 自动进行切换,使用 cloud 命名空间自动创建一个RedisConnectionFactory或将其自动注入到您的应用程序中。有关各种可用功能的更多信息,请参阅此章节

现在,让我们将我们的 Twitter 克隆部署到云中!

对于像我这样的命令行爱好者,Cloud Foundry 提供了vmc工具,允许您与 Cloud Foundry 实例进行交互。它是用 Ruby 编写的,因此需要安装 Ruby 和 Ruby Gem - 请查看下载页面,找到适合您操作系统的软件包。对于 Windows,出色的RubyInstaller 提供安装程序或 zip 形式,通过提供原生集成(如果您不想使用 Cygwin 等工具)很好地解决了问题。如果gem命令不可用,请从官方网站下载,解压后即可使用

有关可用命令的更多信息,请参阅入门指南

q:\>gem install vmc
Successfully installed vmc-0.3.10
1 gem installed
Installing ri documentation for vmc-0.3.10...
Installing RDoc documentation for vmc-0.3.10...

登录您的账户

Q:\>vmc target api.cloudfoundry.com
Succesfully targeted to [http://api.cloudfoundry.com]

Q:\>vmc login
Email: <signup email>
Password: **************
Successfully logged into [http://api.cloudfoundry.com]

最后一步是简单地上传我们的 WAR 包


Q:\>dir /B
retwisj.war

Q:\>vmc push
Would you like to deploy from the current directory? [Yn]: y
Application Name: my-retwisj
Application Deployed URL: 'my-retwisj.cloudfoundry.com'?
Detected a Java SpringSource Spring Application, is this correct? [Yn]: y
Memory Reservation [Default:512M](64M, 128M, 256M, 512M or 1G)
Creating Application: OK
Would you like to bind any services to 'my-retwisj'? [yN]: y
The following system services are available::
1. mongodb
2. mysql
3. rabbitmq
4. redis
Please select one you wish to provision: 4
Specify the name of the service [redis-866fb]: redis
Creating Service: OK
Binding Service: OK
Uploading Application:
  Checking for available resources: OK
  Processing resources: OK
  Packing application: OK
  Uploading (32K): OK
Push Status: OK

Staging Application: OK

Starting Application: OK

Q:\>vmc apps

+-------------+----+---------+------------------------------+-------------+
| Application | #  | Health  | URLS                         | Services    |
+-------------+----+---------+------------------------------+-------------+
| my-retwisj  | 1  | RUNNING | my-retwisj.cloudfoundry.com  | redis       |
+-------------+----+---------+------------------------------+-------------+

即使在慢速连接下,上述过程也不应超过 1 分钟(这篇博客文章深入介绍了在执行push操作期间发生的事情)。您可能注意到只上传了 32K;这不是错误,vmc足够聪明,能够识别它已经知道的文件(例如已部署的文件)以及实际发生变化的文件。

就是这样!- 只需在浏览器中访问上面的 URL,即可体验您的 RetwisJ 示例。'官方'在线实例可在 http://retwisj.cloudfoundry.com/ 找到

总结

这篇文章涵盖了相当多的内容:Redis、Spring Data 和 Cloud Foundry 部署。我希望这能展示入门的便捷性以及这种组合在本地环境或云中的强大之处。而这仅仅是个开始!Spring Redis(即将达到 RC 状态)和 Cloud Foundry 都将添加更多功能,无论是更多服务还是更好的工具。

尝试一下吧,并告诉我们您的想法和需求!

订阅 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您快速进步。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

近期活动

查看 Spring 社区所有近期活动。

查看全部