使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx
- 文档编号:3997016
- 上传时间:2022-11-27
- 格式:DOCX
- 页数:12
- 大小:30.81KB
使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx
《使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx》由会员分享,可在线阅读,更多相关《使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用.docx(12页珍藏版)》请在冰豆网上搜索。
使用GoogleAppEngine实现基于云计算的小型Java数据服务应用
使用GoogleAppEngine实现基于云计算的小型Java数据服务应用
周鹏,软件工程师,IBM
胡沙,软件工程师,IBM
蔡林,软件工程师,IBM
简介:
GoogleAppEngine 提供给网站开发人员以极其优惠的起步价格,因而深受关注。
在计算方面,它提供了Python和Java两种运行时框架。
在存储方面,它又提供了基于特有的 BigTable 技术,适用于结构化、半结构化数据存储的云存储服务接口。
最新的适用于非结构化数据的 GoogleStorage 也进入了测试阶段。
因而,完整的云计算解决方案大大的提升了Google在这一领域的领先地位。
GoogleAppEngineforJava是2009年Google推出的云计算服务。
与Amazon的EC2比较起来,GoogleAppEngine提供了一个免费的初级版本,这对于广大的Java网站开发人员来说是很有吸引力。
关于如何开始使用AppEngine,developerWorks上已经提供了 GoogleAppEngineforJava 系列文章,因此本文重点介绍AppEngine上的开发数据应用所需的常见技术。
GoogleAppEngine的数据存储是基于Google特有的BigTable技术,与常见的关系型数据库有所不同,因此使用GoogleAppEngine也有别于常。
考虑到Google提供的免费数据空间对于小型应用来说,还是绰绰有余的(目前是根据API的调用次数或数据查询来统计的,而免费的额度很高,一天的免费查询上限为417,311,168次,免费存储空间有1G),所以还是值得开发人员来花一定的时间来学习掌握的。
使用JDO/JPA实现数据对象持久化
面向数据服务的应用关键在于一致、可靠的数据储存模型,在传统计算模型下,基于关系数据库的数据对象存储与查询一直是主流,而AppEngine则采用基于datastore的数据对象存储与查询模型,来实现分布式架构下海量数据的管理及扩展。
尽管datastore不是一个关系型数据库,但仍具有极强的一致性,使得datastore的接口具有与传统数据库一样的特征,从而在延续传统编程接口规范性和便利性的同时,获得了云端存储的高扩展性。
在AppEngine提供的JavaSDK中包含了JDO和JPA两种对象建模与持久化的API实现。
JDO是一个用于存取某种数据仓库中的对象的标准化API,提供透明的对象存储;JPA通过Javaannotation或XML描述对象-关系表的映射关系(O/RMapping),并将运行的实体对象持久化到数据库中。
JDO与JPA同时作为数据对象持久化API,尽管在关系数据库的支持上功能有所重叠,但针对的领域是不同的,JDO更注重提供通用底层数据格式的存储功能,如文件、XML、关系数据库甚至对象数据库。
因此,本文将重点阐述AppEngine的JDOAPI的使用方法。
设置JDO
(1)拷贝appengine-java-sdk/lib/user/orm/目录中的JAR包到应用程序的war/WEB-INF/lib/目录,并确保appengine-api.jar也在该目录中。
(2)在应用程序的war/WEB-INF/classes/META-INF/目录创建jdoconfig.xml配置文件,其内容如下:
xmlversion="1.0"encoding="utf-8"?
>
xmlns: xsi="http: //www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation=" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> (3)设置数据读取策略和datastore调用期限。 AppEnginedatastore会复制所有的数据到多个存储位置,用以保证当其中一个出现故障时,datastore能迅速的切换到其他位置并正常的访问数据。 为了保证多个数据节点的一致性,应用程序会使用其中一个位置作为主位置(primarylocation),当主位置的数据更新时,其它位置的数据将被并行地改变。 在许多情况下,短时间内返回一些数据格式比等待返回当前数据更为重要,因此当主位置出现故障时,您可以让datastore从其它位置读取数据(可能数据不是最新的),这时就需要设置读取策略(readpolicy)。 Appengine提供两种策略: strongconsistency和eventualconsistency,其默认策略是strongconsistency。 strongconsistency表示任何情况下都从主存储位置读取数据,而eventualconsistency则表示当主位置不可用时,可从其它存储位置读取数据。 其相应配置如下: 在默认情况下,对datastore的调用直到调用成功才会返回。 如果调用请求的期限到了,运行环境将会终止此次调用请求。 应用程序可以指定调用期限的具体时间,对于批量更新的请求,如果在提交过程中,限定的时间已到,那么到期之前的更新将会被持久化,而之后的更新将不会发生;对于一个事务处理,如果在事务提交过程中期限已到,那么整个事务将会回滚。 其相应的配置如下: 增强数据类 JDO使用一种后置编译处理的增强步骤来实现数据类与JDO实现之间的关联。 如果您使用Eclipse,GooglePluginforEclipse工具会自动完成这个步骤;如果您使用ApacheAnt,可以使用如下命令对已经编译出来的class文件进行增强处理。 java-cpclasspathcom.google.appengine.tools.enhancer.Enhanceclass-files 需要注意的是,Classpath必须包含appengine-tools-api.jar这个JAR包和所有的数据类文件。 获取PersistenceManager实例 应用程序与JDO进行交互是通过PersistenceManager类来实现的,您可以通过PersistenceManagerFactory来获取该类的实例。 由于PersistenceManagerFactory是根据JDO配置来构造的,较为耗时,因此,一个应用应该共享一个单一的实例。 我们可采用一个简单的单例模式类来对其进行封装,例如: importjavax.jdo.JDOHelper; importjavax.jdo.PersistenceManagerFactory; publicfinalclassPMF{ privatestaticfinalPersistenceManagerFactorypmfInstance= JDOHelper.getPersistenceManagerFactory("transactions-optional"); privatePMF(){} publicstaticPersistenceManagerFactoryget(){ returnpmfInstance; } } 通过该工厂实例,就可以为每次的datastore访问请求创建PersistenceManager实例了,例如: importjavax.jdo.PersistenceManager; importjavax.jdo.PersistenceManagerFactory; importPMF; //... PersistenceManagerpm=PMF.get().getPersistenceManager(); try{ //...dostuffwithpm... }finally{ pm.close(); } 需要注意的是,在使用完PersistenceManager实例后,您需要调用close()方法,以确保不会在其它地方调用。 基于JDOAPI的CRUD (1)要将简单数据对象存储到数据存储区中,可以调用PersistenceManager的makePersistent()方法,将实例传递给该方法。 对makePersistent()的调用时同步的,直到保存对象并更新索引后才会返回。 要在JDO中保存多个对象,可以使用makePersistentAll(...)方法。 (2)要获取对象,最简单、直接的方法就是通过键(key),利用PersistenceManager的getObjectById()方法来获取。 更加复杂的查询可通过JDO规范中的JDOQL来完成,例如通过lastName来查询Employee信息的查询可通过以下JDOQL完成。 Queryquery=pm.newQuery("selectfromEmployee"+ "wherelastName==lastNameParam"+ "parametersStringlastNameParam"+ "orderbyhireDatedesc"); List (3)要将对象从数据存储区中删除,可以使用PersistenceManager的deletePersistent()方法。 (4)使用JDO更新对象的一种方式是抓取对象,然后在返回该对象的PersistenceManager仍然处于打开状态的情况下对该对象进行修改。 当关闭PersistenceManager时,修改部分会自动保留。 基于YAML描述文件以及bulkloader实现大批量结构化数据导入/导出 大批量数据导入,导出是常见的数据服务操作。 目前,对于AppEngineforJava的数据上传,还不是非常简便,需要以下四个步骤: RemoteApiSelvlet的web.xml的例子。 (1)即使是AppEngineforJava,在批量数据下载和上传方面,还是依赖于AppEngineforPythonSDK的若干Python脚本,如bulkloader.py或是appcfg.py等等。 因而,用户还是需要安装AppEngineforPythonSDK在开发机上。 (2)在AppEngineforJava的google服务器端,需要部署com.google.apphosting.utils.remorteapi.RemorteApiServlet,该Servlet会与安装在AppEgnineforPythonSDK的开发机交互,来实现数据从开发机到服务器端的数据传输。 下面是一个部署RemoteApiSelvlet的web.xml的例子。 com.google.apphosting.utils.remoteapi.RemoteApiServlet (3)获取当前的AppEngineforJava服务器所用的数据表的Schema,写成yaml格式。 以下面的命令为例,该命令将 用户可以编辑该描述文件,上传后以实现对DBschema的修改。 appcfg.pycreate_bulkloader_config--filename=bulkloader.yaml --urlhttp: // (4)下面是一个DBSchema的实例,该实例的含义是,数据表名为Person,主键是email,还包含属性name,surname,文件传输格式为CSV。 ------------------------------------------------------------ transformers: -kind: Person connector: CSV property_map: -property: __key__ external_name: email export_transform: transform.key_id_or_name_as_string -property: name external_name: name -property: surname external_name: prenom ------------------------------------------------------------ (5)上述步骤完成以后,即可使用appcfg.py来实现数据的上传下载。 如下例所示, appcfg.pydownload_data--config_file=bulkloader.yaml --filename= --kind=Person --urlhttp: // appcfg.pyupload_data--config_file=bulkloader.yaml --filename= --kind=Person --url --batch_size=200 --num_threads=5 使用Blobstore实现非结构化数据存储 基于Web的数据应用常会遇到非结构化数据存储的需求,如文件、图片或视频的管理。 Appengine采用BlobstoreAPI来管理这些不易被datastore管理的大尺寸(总配额为2GB)数据对象(Blobs)。 一般来说,应用不会直接创建blobs数据,而是由提交的Web表单或者HTTPPOST请求间接创建的。 Blobs在创建之后能够被删除,但不能被修改。 每一个blob在datastore中都有相对应的记录信息,如创建时间、内容类型。 可通过blobkey来查询相关的记录和属性信息。 Blobstore的具体应用过程如下: 上传Blob (1)编写上传JSP页面,并且设置blobstoreService.createUploadUrl()作为表单的action。 例如: method="post"enctype="multipart/form-data"> (2)编写BlobHandlerServlet,存储Blobkey。 当用户提交表单并触发Handler被调用时,blob就已被Appengine保存并将相关信息添加datastore。 如果应用程序不想保存blob,应立即删除,避免其成为不能被引用到的孤立数据,浪费应用空间。 Handler的主要处理逻辑如下: Map BlobKeyblobKey=blobs.get("myFile"); if(blobKey==null){ res.sendRedirect("/"); }else{ res.sendRedirect("/serve? blob-key="+blobKey.getKeyString()); } 如果不明确指定上传文件的contenttype,Blobstore将会从文件的后缀名推断出contenttype。 如果contenttype不能确定下来,新创建的blob将被赋予application/octet-stream类型。 下载Blob 获取blobkey,编写DownloadHandlerServlet。 这个Handler必须将blobkey传递给blobstoreService.serve(blobKey,response)函数。 下面的例子中,blobkey是通过URL的参数来传递的。 在实际应用中,DownloadHandler可以以任何您需要的方式获取blobkey。 不过每次从Blobstore读取的数据大小被被限制为1MB。 publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres) throwsIOException{ BlobKeyblobKey=newBlobKey(req.getParameter("blob-key")); blobstoreService.serve(blobKey,res); } 基于JCache提高数据存取性能 高性能、可扩展性是Web应用的普遍设计目标,而采用分布式内存数据缓存,并部署于健壮的数据持久层之上,是实现该目标的可靠方法。 AppEngine也包含了内存缓存服务,并支持JCache缓存接口。 JCache提供一个类似于Map的接口用于缓存数据,并通过键(keys)来存取键值,键和值可以是任何可序列化的数据类型和类。 创建并使用JCacheAPI的示例代码如下: importjava.util.Collections; importnet.sf.jsr107.Cache; importnet.sf.jsr107.CacheException; importnet.sf.jsr107.CacheManager; //... Cachecache; try{ cache=CacheManager.getInstance() .getCacheFactory().createCache(Collections.emptyMap()); }catch(CacheExceptione){ //... } Stringkey;//... byte[]value;//... //Putthevalueintothecache. cache.put(key,value); //Getthevaluefromthecache. value=(byte[])cache.get(key); 使用缓存的一个主要目的是为了提升datastore查询的速度。 如果Web应用中的某些基础数据在整个程序的生命周期中变化不
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 Google App Engine 实现基于云计算的小型 Java 数据服务应用 实现 基于 计算 小型 数据 服务 应用
![提示](https://static.bdocx.com/images/bang_tan.gif)