第 12 章 云计算:Google App Engine
我们的行业正经历一波发明浪潮,其背后的主要现象是云。但没人能知道什么是云,也不知道其确切含义。
—Steve Ballmer,2010 年 10 月
本章内容:
- 简介;
- 云计算;
- 沙盒和 App Engine SDK;
- 选择一个App Engine 框架;
- Python 2.7 支持;
- 与Django 比较;
- 将“Hello World”改成一个简单的博客;
- 添加Memchace 服务;
- 静态文件;
- 添加用户服务;
- 远程API Shell;
- 问与答(Python 实现);
- 使用XMPP 发送即时消息;
- 处理图片;
- 任务队列(非定期任务);
- 使用Appstats 进行分析;
- URLfetch 服务;
- 问与答(无Python 实现);
- 厂商锁定;
- 资源。
12.1 简介
接下来要介绍的开发系统是Google App Engine。App Engine 不提供类似 Django 的全栈框架(尽管可以在App Engine 中运行 Django,后面会介绍),这是一个开发平台,最初专注于 Web 应用(其有自己的微型框架,即 webapp,或其替代品,即新的 webapp2),但 App Engine仍然可以构建通用的应用和服务。
这里的“通用”并不是意味着任何应用都可以创建并移植到 App Engine 中,而是表示需要用到 HTTP 的网络应用,包括但不限于 Web 应用。一个著名的非 Web 应用示例就是面向用户的移动客户端的后端服务。App Engine 属于云计算的范畴,专注于为开发者提供一个平台,用于构建并托管应用或服务的后端。在实际了解平台的细节之前,首先介绍一下云计算的生态圈,这样可以更好地了解App Engine 的适用范围。
12.2 云计算
基于 Django、Pyramid,或 TurboGears 的应用都由供应商或自己的电脑运行来提供服务,而 Google App Egine 应用由 Google 运行,作为云计算范畴下许多服务的一部分。这些服务的主要前提是公司或个人将计算架构分离出去,如实际硬件、应用开发和执行或者软件托管。如果使用云计算,则将应用的计算、托管、服务等任务委托给其他公司,不再需要自己完成。
这些服务只能通过因特网来完成,用户可能并不清楚对方的实际物理地址。服务包括以应用使用的原始硬件 ①到应用的所有内容,以及其他所有可能的服务,如操作系统、数据库、文件和原始的磁盘存储、计算、通知、电子邮件、即时信息、虚拟机、缓存(多级,从Memcahed 到CDN)等。这个行业中有许多佼佼者,同时厂商会继续提供新的服务。这类服务一般通过订阅或使用次数来付费。
① 术语硬件包括物理设备(磁盘和内存)、电源设备、冷却设备、网络设备。
公司通常出于成本考虑才部署云计算服务。但各公司的需求有很大不同,所以要分别调研来判断部署云服务是否明智。一个创业公司能负担起所有硬件吗(不是租用数据中心或托管设施的设备)?没关系,可以租用亚马逊的计算设备,或使用 Google 的存储设备。过去,小型创业公司的合伙人必须自掏腰包购买这样的设备,而现在他们可以专注于应用的业务问题。
大公司或“财富 500 强”公司的情况有所不同,他们有足够的资源,但发现无法完全利用到所有潜能。这些公司无须像亚马逊那样创建云业务(下一节会介绍),只须在内部创建一个私有云服务,或者构建一个混合云,用私有设备处理敏感数据,通过如 Google 或亚马逊这些公共云外包其他部分(如计算、应用、存储等)。
根据自身管理方式,部署云服务的公司通常必须要关心物理存储地址、安全性、服务级别协议(SLA)以及承诺。很明显,当外包应用、数据等内容时,公司希望能确保这些内容安全有保障,公司的管理团队(如果有)能够在任何时候去实地查看物理存储设备。当满足了这些需求后,下面就要决定需要哪个层次的云计算。
12.2.1 云计算服务的层次
云计算有三个层次。图 12-1 显示了每个层次,以及对应层次的代表产品。最低层的是 IaaS(Infrastructure-as-a-Service),即提供计算机本身基本的计算能力(物理形式或虚拟形式)、存储(通常是磁盘)、计算。亚马逊 Web 服务(Amazon Web Services,AWS)提供了弹性计算云(Elastic Compute Cloud,EC2),以及简单存储系统(Simple Storage System,S3)服务, 这两者就在 IaaS 层面。Google 也提供了 IaaS 存储服务,称为 Google Cloud Storage。
Google App Engine 作为云计算的中间一层,称为 Paas(Platform-as-a-Service)。这一层为用户的应用提供执行平台。最高一层是 Software-as-a-Service(SaaS)。在这一层,用户只须简单地访问应用,这些应用位于本地,但只能通过因特网访问。SaaS 的例子包括基于 Web 的电子邮件服务,如 Gmail、Yahoo! Mail 和Hotmail。
图 12-1 云计算的三个层次
在这三层当中,IaaS 和 SaaS 是最常见的,而 PaaS 则没有像前者那样引起注意。不过情况正在改变,PaaS 也许是这三者之间最强大的。通过 PaaS,可以免费获得 IaaS,但 PaaS 中含有许多非常服务,自行维护这些服务的开销非常大且很麻烦。这些功能位于 IaaS 层和上面的层次中,包括操作系统、数据库、软件授权、网络和负载平衡、服务器(Web 和其他)、软件补丁和升级、监控、警告、安全修复、系统管理等。使用云服务的主要好处是与自行维护相关设备相比,使用这一层的服务不会让设备空闲。因为购买计算机设备的数量是根据原先预计的网络流量计算的。如果花费大量资金购置的设备没有充分得到利用,在那里闲置就非常令人沮丧。
云计算的概念已经出现很久了,Sun Microsystems 的John Gage 在 1984 年创立了最初令人记忆深刻的术语——网络即是计算机。但云计算在 21 世纪初才商业化。具体来说,是在2006 年年初,亚马逊推出了 AWS。亚马逊闲置的功能促使他们推出这个服务。亚马逊必须购置足够多的计算资源,来满足购物季在线购物的流量和业务需要。
根据亚马逊的白皮书 ①,亚马逊声称:“在 2005 年,他们必须花费数百万美元来构建并管理大规模、可用且高效的IT设备,来支撑世界最大的零售平台的运作。”
但凭借所有的存储和计算能力,这些设备中的大部分在一年的其他时间里会做些什么呢? 老实说,闲置在那里。所以为什么不将这些额外的 CPU 和存储能力租出去,提供一个服务呢? 亚马逊的确这样做了。从那时开始,其他几家大型科技公司也加入了这种趋势:Google、Salesforce、Microsoft、RackSpace、Joyent、VMware,以及许多其他公司都加入到这个行列中。
当亚马逊的 EC2 和 S3 服务清晰地定义了云服务的层次,为需要托管应用的客户打开了一个新的市场,具体来说,就是能够编写自定义软件系统,来利用 Salesforce 公司的(顾客关系)数据。这让 Salesforce 创建了 force.com,这是第一个专门做这个业务的平台。当然, 并不是所有人想用 Salesforce 的专有语言编写应用。所以 Google 开发了另一个更通用的 PaaS 服务,称为 App Engine,在 2008 年 4 月闪亮登场。
12.2.2 App Engine
为什么在一本介绍Python 的书中介绍 App Engine?App Engine 是Python 的核心部分, 或者重要的第三方包吗?尽管都不是,但 App Engine 的出现对 Python 社区和市场产生了深远的影响。实际上,之前许多读者都要求添加介绍 Google App Engine 的章节(他们也同样要求在 Python Web Development with Django 书中也添加相关章节,这本书是由我和我尊敬的同事——Jeff Forcier 和 Paul Bissex 共同撰写的)。
不同的 Web 框架之间有相同点和不同点,而 App Engine 与这些都有区别。因为 App Engine 不仅仅是一个开发平台,还是一个带有应用的主机服务。后者是使用 App Engine 开发应用的主要原因。用户现在可以更方便地选择开发和部署一款应用,也可以像以前那样,自己搭建支持应用的硬件设备。在 App Engine 上部署应用,所有要做的额外工作只有设计、编码、测试应用。
① http://media.amazonwebservices.com/AWS_Overview.pdf。
使用App Engine,开发者无须处理 ISP 或自行托管,只须将应用上传到 Google,Google 会处理在线维护的逻辑。普通的 Web 开发者现在可以享用与 Google 相同的资源,在相同的数据中心运行,使用支撑这个互联网巨人相同的硬件。实际上,通过 App Engine 和其他云服务,Google 实际上为自己使用的设备提供了一个公共 API。这包括 App Engine API 如,数据存储(Megastore、Bigtable)、Blobstore、Image(Picasa)、Email(GMail)、Channel(GTalk)等。另外,现在开发者无须关心计算机、网络、操作系统、电源、冷却、负载平衡等问题。
这些都很棒,但 Python 在这当中扮演什么样的角色?
当App Engine于 2008 年最先上线时,唯一支持的语言运行时就是Python。Java在一年后支持,但Python处于特殊的地位,因为Python是App Engine第一个支持的运行时。目前Python 开发者已经知道了Python是易用、鼓励协同开发、允许快速开发的语言,不需要使用者具有计算机科学的学位。这样能吸引许多不同专业背景的用户。Python的创建者自身就在App Engine的团队 ①。因为App Engine是突破性的平台,且与Python社区连接紧密,所以很有必要向读者介绍App Engine。
App Engine 整个系统由 4 个主要部分组成:语言运行时、硬件基础设施、基于 Web 的管理控制台、软件开发包(SDK)。SDK 为用户提供了相应的工具,即开发服务器及访问 App Engine 的 API。
语言运行时
关于语言运行时,很明显要将时间花在 Python 上面,但在编写本书时,App Engine 已经支持Java、PHP 和Go。同样,因为已经支持 Java,所以开发者可以使用能在 Java 虚拟机(JVM) 上运行的语言,如 Ruby、JavaScript 和Python,分别由 JRuby、Quercus、Rhino、Jython 运行, 还有Scala 和Groovy。通过 Jython 运行的 Python 是最奇妙的,有些人会困惑为什么会有用户在有Python 可用的时候去使用 Jython。首要原因是有用户希望用 Python 开发新项目,但有现成的Java 包可以利用。不难理解,用户想利用已有的包,但不想花时间将这些库移植到 Python 中。
硬件基础设置
硬件基础设施对用户来说完全是一个黑盒。用户并不知道代码运行在什么硬件上。大致就是这个黑盒使用某种配置的 Linux,坐落在连接到全球网络的数据中心。读者可能听过Bigtable,这是 App Engine 用于存储数据的非关系数据库系统。对于大多数人来说,这就是所要知道的内容。记住,有了云计算,无须关心这些内容。云计算中非常复杂的工作、设备维护的细节,以及设备的可用性,都隐藏到幕后。
① 现在跳槽到 Dropbox 了。——译者注
基于Web 的管理和系统状态
本章剩余的部分将会介绍 Google App Engine 的Python 应用编程接口(API)的不同特性。注意,在生产环境中,应用程序可能运行在不同版本的Python(或Java)解释器上。而且因为该应用与其他用户的应用程序共享资源,所以需要考虑安全问题。所有应用必须在沙盒中执行,即一个受限的环境中运行。是的,这样在某种程度上降低了控制力,增加了组件构建难度,降低了扩展性。
作为补偿,App Engine 提供了基于 Web 的管理控制台,让用户可以深入了解应用,包括流量、数据、日志、账单、设置、使用状况、配额等。图 12-2 显示了一个应用的管理控制台的截图。
图 12-2 Google App Engine 应用的管理控制台(图片由 Google 提供)
同样还有系统级别的状态页面(见图 12-3),用于监控 App Engine 中当前所有应用的运行情况。
注意,这里的“所有应用”就是字面意思。在 2010 年冬天,Google App Engine 每天要处理超过 100 万个 Web 页面。当创建并部署一个应用时,就会添加一个新的管理页面。尽管这样感觉很激动人心,但再次提醒一下,因为 App Engine 对于所有开发者都是可用的, 所以要学会如何使用沙盒。沙盒并不像听起来那么糟糕,因为 App Engine 为开发者提供了许多服务和 API。
图 12-3 Google App Engine 应用的系统状态页面(图片由 Google 提供)
12.2 沙盒和 App Engine SDK
开发者都不会希望别人的应用能访问他的应用的源代码或数据,其他应用也同样如此。在沙盒中有一些无法绕过的限制(如果某些行为现在认为是安全的,Google 会取消这些限制)。禁止的行为包括但不限于下面这些。
- 不能创建本地磁盘文件,但可以通过 Files API 创建发布的文件。
- 不能打开入站网络套接字连接。
- 不能派生新进程。
- 不能执行(操作)系统调用。
- 不能上传任何非 Python 源码。
由于这些限制,App Engine SDK 提供了一些高阶的 API,来弥补这些限制带来的功能损失。另外,因为 App Engine 使用的 Python 版本(目前是 2.7)仅仅是所有 Python 版本的一部分,所以无法使用 Python 所有的功能,特别是由 C 编译而来的特性。App Engine 中有一些C编译的 Python 模块。Python 2.7 版本支持更多的 C 库,如一些常用的外部库,如 NumPy、lxml
和PIL。实际上,2.5 版本支持的 C 库组成了一个“白名单”,2.7 版本支持更多的库,这个列表实际上是一个“黑名单”。
http://code.google.com/appengine/ kb/libraries.html 中列出了Python 2.5 中可用但Python 2.7 中不可用的 C 库(对于 Java 类也有一个类似的列表)。如果想使用任何第三方 Python 库,只要这个库是纯Python,就可以打包到源码中(纯 Python 意味着没有可执行程序,没有.so 或.dll 文件等),同时不要使用不在白名单中的模块或包。
记住,可以上传的文件总数量是有限制的(当前是 10000 个),同时对所有上传文件的总大小也有限制(当前是 1GB)。这里包括应用程序的文件,以及一些静态资源文件,如 HTML、CSS、JavaScript 等。单个文件的大小也有限制(当前是 32MB)。若想了解当前大小的限制,可以访问 https://cloud.google.com/appengine/docs/quotas,App Engine 的团队在努力提高限制的上线。当然,有几种办法能绕过这些令人头疼的限制。
如果应用需要处理的媒体文件超过了单个文件大小的限制,可以将这个文件存储在 App Engine Blobstore(见表 12-1)中,这里可以存储任意大小的文件。也就是说,没有单个文件(blob)大小的限制。如果.py 文件的数目超过了限制,需要将这些文件存储到 Zip 中并上传。不管打包了多少.py 文件,只要是单个 Zip 文件即可。当然,这个 Zip 文件必须小于单个文件大小的限制,但至少无须担心文件数目的问题。关于使用 Zip 文件的更多信息,可以参考这篇文章(http://docs.djangoproject.com/en/dev/ref/settings,注意,这篇文章开头的提示)。
解决了文件限制问题,回头来看执行限制(不能使用套接字、本地文件、进程、系统调用)。不能使用这些功能,看起来无法构建一个非常有用的应用。不要沮丧,下面会有解决办法!
12.2.1 服务和API
为了能让用户完成工作,Google 不断提供新的功能来解决这些核心限制。例如,什么情况下需要打开网络套接字呢?是否需要与其他服务器通信?在这种情况下,使用 URLfetch API。发送或接收电子邮件怎么样?那么可以使用 Email API。同样,使用XMPP(eXtensible Messaging and Presence Protocal,或简单一点的 Jabber)API 可以发送或接收即时消息。各个操作都有对应的 API,如访问基于网络的辅助缓存(Memcache API),部署反向 AJAX 或 browser push(Channel API),访问数据库(Datastore API)等。表 12-1 列出了本书编写时App Engine 开发者所能使用的所有服务和 API。
表 12-1 Google App Engine 的服务与 API(有些为实验性的)
(续表)
服务/API | 说 明 |
Blobstore | Blobstore 可以让应用处理大于 Datastore 限制的数据对象(如媒体文件) |
Capabilities | 让应用能够检测 App Engine 的 Datastore 或Memcache 是否可用 |
Channel | 直接向浏览器推送数据,即 Reverse Ajax、browser push、Comet |
Cloud SQL | 使用关系数据库(而不是默认的可扩展的分布式 Datastore) |
Cloud Storage | 使用 Files API(参见这张表后面的描述),直接向 Google Cloud Storage 读写文件 |
Conversion | 使用这个 API 在 HTML、PDF 格式、文本和图像格式之间转换 |
Cron | 使用Cron 能够在特定的日期、时间或时间间隔运行计划任务 |
Datastore | 一个分布式、可扩展、非关系持久性数据存储 |
Denial-of-Service | 使用这个 API 来设置过滤器,屏蔽发布拒绝服务(DoS)攻击应用程序的 IP 地址 |
Download | 在发生灾难时,开发人员可以下载上传到Google 的代码。 |
Files | 使用常见的 Python 文件接口创建分布式的(blobstore 或 Cloud Storage)文件 |
(Full-text)Search | 在 Datastore 中搜索文本、时间戳等 |
Images | 处理图像数据;例如,创建缩略图、裁切、调整大小和旋转图像 |
Logs | 允许用户访问应用程序和日志请求,甚至对于长时间运行的请求,在运行时进行清理 |
这个 API 让应用程序能够发送和/或接收电子邮件 | |
MapReduce | 在非常大的数据集上执行分布式计算。包括 map、shuffle、 reduce 阶段的 API |
Matcher | 高扩展的实时匹配基础设施:注册查询来匹配对象流 |
Memcache | 在应用程序和持久性存储之间的标准分布式内存数据缓存(类似 Memcached) |
Namespaces (Multitenancy) | 使用命名空间,通过划分 Google App Engine 数据,创建多租户的应用程序 |
NDB (新数据库) | 新的实验性的Python-App 引擎高级 Datastore 接口 |
OAuth | 为第三方提供一种代表用户访问数据的安全方法,无需授权(登录/密码等) |
OpenID | 用户可以使用Google 账户和 OpenID 账户登录联合身份验证服务 |
Pipeline | 管理多个长时间运行的任务/工作流,并整理运行的结果 |
Prospective Search | 有些与允许用户搜索现有数据的全文检索 API 相比,Prospective Search 允许用户查询尚未创建的数据:设置查询,当存储匹配的数据时,调用 API(想想数据库触发器加上任务队列) |
Socket | 允许用户通过出站套接字连接来创建并通信 |
Task Queue | 无需用户交互就可以执行后台任务(可以并发执行) |
URLfetch | 通过 HTTP 请求/响应与其他应用程序在线通信 |
Users | App Engine 的身份验证服务,管理用户的登录过程 |
WarmUp | 流量到来之前在实例中加载应用程序以缩短请求服务时间 |
XMPP | 让应用能够通过 Jabber / XMPP 协议来聊天(发送和/或接收即时消息) |
听起来很不错,说得够多了,现在开始动手!首先要做的就是选择一个用来构建应用的框架。
12.4 选择一个 App Engine 框架
如果编写不是面向用户的应用,也就是说,仅仅编写一个让其他应用调用的应用,那么选择框架就不那么重要。目前,有多个框架可供选择,如表 12-2 所示。
表 12-2 用 于 Google App Engine 的 框 架
框 架 | 描 述 |
webapp、webapp2 | App Engine SDK 自带的轻量级 Web 框架 |
bottle | Python 中的一个轻量级 WSGI 微型 Web 框架;附带 App Engine 适配器(gae) |
Django | Django 是一款流行的 Python 全栈 Web 框架(在GAE 中并非所有功能都可用) |
Django-nonrel | 用于在非关系数据存储(如GAE)上运行 Django 应用程序 |
Flask | 另一个微型框架(像上面的“bottle”),基 于 Werkzeug & Jinja2(像下面的 Kay),易于定制,没有本地数据抽象层,直接使用 App Engine 的 Datastore |
GAE Framework | 基于 Django,但是简化过。使用这个框架可以重用已有的应用架构,如 users、blog、admin 等。可以认为是用于 App Engine 的 Django + Pinax 简化版 |
Google AppEngine Oil(GAEO) | 如果 Web 应用太简单,而 Django 太复杂,可以使用这个MVT 框架,与 Django 类似,也是受到了Ruby 的 Rails 和 Zend 框架的启发 |
Kay | 与 Django 类似,但使用 Werkzeug 作为低层框架、使用 Jinja2 作为模板引擎、使用 babel 来翻译语言 |
MVCEngine | 受到Rails 和 ASP.NET 启发的框架 |
Pyramid | 另一种流行全栈 Web 框架,基于 Pylons 和 repoze.bfg |
tipfy | 比 webapp 更强大的轻量级框架,只为 App Engine 而建。这也导致 webapp2 的创建,意味着最初的创造者不再维护这个框架 |
web2py | 另一款 Python 全栈 Web 框架,有较高的抽象级别,这意味着它比其他的框架更容易使用,但隐藏了更多的细节(有好有坏) |
App Engine 的大多数初学者会直接使用webapp 或webapp2 来了解App Engine,因为 App Engine 自带这两个框架。这是不错的选择,因为尽管 webapp 很简单,但其提供了一些基本工具,能够构建有用的应用。但有一些熟练的 Python Web 开发者之前使用了很久的 Django, 想继续使用,由于 App Engine 中有限制环境,在默认情况下无法使用 Django 的所有特性。不过,App Engine 与Django 之间仍然有某种联系。
Django 中的一些组件已经集成进 App Engine,Google 在App Engine 的服务器上提供了某个版本的 Django(尽管有些老),用户无须将完整的 Django 安装包与自己的应用一同上传。在编写本书时,App Engine 提供了 0.96、1.2 和 1.3 版的Django,读者阅读本书时可能会包含新的版本。但Django 中有几个关键部分没有引入到 App Engine 中,最重要的包括对象关系映射器(Object-Relational Mapper,ORM),ORM 需要一个传统的 SQL 关系数据库基础。
这里使用“传统”是因为有若干计划尝试让 Django 支持非关系(NO SQL)数据库。但在编写本书时,还没有这样的项目集成到 Django 发行版中。也许在读者阅读时,Django 或许已经同时支持关系和非关系数据库。除了对 Django 1.3 和 1.4 的提议,还有一个比较著名的就是 Django-non-rel 这个项目。这是 Django 的一个分支,其中含有针对 Google App Engine 和 MongoDb 的适配器(还有其他正在开发的适配器)。同时还有将 JOIN 引入 NoSQL 适配器,但此项目仍在开发中。如果后面有与 Django 的非关系型开发者相关的信息,到时候会注明。
Tipyfy 是专门针对 App Engine 开发的轻量级框架。可以认为其是 webapp++或“webapp 2.0”,其中含有 webapp 中弃用的一些功能。Tipyfy 的功能包括(但不限于)国际化、会话管理、其他形式的验证(Facebook、FriendFeed、Twitter 等)、访问 Adobe Flash(AMF 协议访问,以及动画消息)、ACL(访问控制列表),以及额外的模板引擎(Jinja2、Mako、Genshi)。
Tipyfy 基于 WSGI 并关联到 Werkzeug 工具集,这个工具集是任何兼容 WSGI 应用的基础。关于 Tipfy 的更多信息可以访问这个链接中的站点和 wiki 页面 http://tipfy.org。
web2py 是 Python 中 4 个著名的全栈 Web 框架之一(另外 3 个是 Django、TurboGears 和Pyramid)。这是第二个兼容 Google App Engine 的框架。web2py 侧重于让开发者创建基于数据库系统的快速、可扩展、安全且可移植的 Web 应用。其中数据库可以是关系型的,也可以是 Google App Engine 的非关系数据存储。web2py 可以使用许多不同的数据库。其中有一个数据库抽象层(DAL)将 ORM 请求实时转成 SQL 形式,以此作为与数据库交互的接口。自然,对于 App Engine 应用程序,依然需要受到 Datastore 抽象出来的关系数据库的限制(即没有JOIN)。web2py 还支持多种 Web 服务器,如 Apache、ligHTTPS,或任何兼容 WSGI 的服务器。对于已经在使用 web2py 且想将应用移植到App Engine 中的用户来说,使用 web2py 是很自然的事。
用户也可以选择其他框架来开发应用。任何兼容 WSGI 的框架都可以。这里使用 App Engine 中最常用的 webapp,同时也鼓励读者使用 webapp2 来完成这里的示例,以此来提升自己。
介绍一点历史知识:一个富有热情的 App Engine 开发者不满足现有的框架,于是导致他开发了 tipfy。接着他试图改进 webapp、于是放弃了 tipfy,构建了 webapp2。webapp2 开发得很好, 于是 Google 将其集成到了 2.7 版本的运行时 SDK 中(11 章开头的引言就是说的这件事)。
12.4.1 框架:webapp 到 Django
第 11 章介绍了 Django,以及如何使用 Django 创建博客。这里默认使用 webapp 也创建博客。与 Django 示例相同,这里 将介绍如何使用 App Engine 构建相同的东西,使用 App Engine 开发环境运行。用户还可以创建Google Account 或其他 OpenID 身份(或使用已有的),并设置应用,让其运行在实时 App Engine 生产环境中。本章将介绍如何完成这些内容。虽然在应用上线时不需要信用卡,但需要一部能接收短信或文本信息的手机。
总结一下,本章会把上一章使用 Django 完成的博客应用移植到 App Engine(开发或生产环境)中。App Engine 的概念和特性足够再写一本书了,所以这里不会全面介绍。现有的介绍完全可以让读者流畅地完成这个App Engine 产品的各个方面。
下载并安装 App Engine SDK
首先,需要获取对应平台的 App Engine SDK。SDK 有多个平台的版本,所以需要注意当前系统对应的版本。访问 Google App Engine 的主页(位于 http://code.google.com/appengine),单击Downloads 链接。在这里可以找到适合当前平台的版本。SDK 还有针对Java 开发者的版本, 但这里只关注Python。
Linux 或*BSD 用户应该下载 Zip 文件,解压后,将 google_appengine 文件夹放到合适的地方(如/usr/local 中),创建 dev_appserver.py 和 appcfg.py 命令的链接。除此之外,也可以直接将/usr/local/google_appengine 添加到系统路径中(对于这些用户,可以跳过本节剩下的部分及后面一节,直接阅读 12.6.2 节)。
Windows 用户应该下载.msi 文件。Mac 用户应该下载.dmg 文件。当找到合适的文件后, 双击或启动来安装 App Engine SDK。这个过程同时会安装 Google App Engine Launcher。Launcher 可以用来管理位于开发电脑上的App Engine 应用,并能帮助将应用上传到 Google, 让其运行在生产环境里。
使用 Launcher 创建“Hello World”(仅限于 Windows 和 Mac 用户)
当启动了 Launcher 后,会看到如图 12-4 和图 12-5 所示的控制面板。
图 12-4 Mac 中 的 App Engine Launcher
图 12-5 Windows 中 的 App Engine Launcher
控制面板中会多个按钮,可以启动(或暂停)开发服务器(Run 按钮),浏览日志(Logs按钮),浏览开发管理控制台(SDK Console 按钮),编辑配置信息(Edit 按钮),将应用上传至 App Engine 生产服务器(Deploy 按钮),或者跳转至当前应用的管理控制台(Dashboard按钮)。首先创建一个新应用,在开发过程中会用到 Launcher 中的这些按钮。
为了做到这一点,从菜单栏的下拉菜单中选择创建一个新应用。赋予一个唯一的名字,“helloworld”应该已经被占用了。还可以为应用设置其他选项,如创建新样板文件的文件夹路径,以及服务器的端口号。完成这些后,将会在 Launcher 的主面板中看到这个应用, 这表示它已经可以运行了。在运行之前,先查看自动创建的三个文件:app.yaml、index.yaml和 main.py。
App Engine 的默认文件
app.yaml 文件表示应用的配置信息。默认生成的文件如示例 12-1 所示。
示例 12-1 默认的配置文件(app.yaml)
YAML(yet another markup language)文件由一系列的键值对和序列组成。关于 YAML
格式的更多信息,可以访问 http://yaml.org 和 http://en.wikipedia.org/wiki/Yaml。
逐行解释
第 1~4 行
第一部分是纯配置,为 App Engine 应用(APP_ID)赋予一个名称,其后需要跟着一个版本号。对于开发来说,可以选择任何想要的名字,如“blog”。如果需要上传到 App Engine的生产环境,则需要选择一个从来没有用过的名称。应用名称要注意以下几点,名称不能转移,不能回收。当选定名称后,该名称就会一直被占用,即使删除该应用也是如此,所以谨慎选择
版本号是一个唯一可以自行选择的字符串。其取决于读者如何设置版本号。可以使用传统的 0.8、1.0、1.1、1.1.2、1.2 等,也可以使用其他命名方式,如 v1.6 或 1.3beta。虽然这只是一个字符串,但只能使用字母或数字,以及连字符。可以为应用创建最多 10 个版本(主版本号和副版本号表示不同的版本)。在此之后,除非删除其他版本,否则不能上传新版本。
在版本号下面是运行时类型。这里是Python 和第 1 版的 AP。还可以修改 app.yaml 来使用 Java 或 JRuby ,以及其他 JVM 运行时。app.yaml 文件用于生成产 web.xml 和appengineweb.xml 文件,也就是 servlet 需要的文件。
第 6~8 行
最后几行指定了处理程序。与 Django URLconf 文件类似,需要指定匹配客户端请求的正则表达式,并提供对应的处理程序。在Django 中,这些“处理程序 url 脚本”键值对对应项目级别的URLconf 文件,在此之后是应用层面的 URLconf。在 app.yaml 中类似,脚本指令将请求发送给 Python 脚本,后者含有更精细的 URL,并将其映射到处理程序类,Django 应用中的URLconf 也是这样将请求指向一个视图函数。
关于应用配置的更多内容,阅读官方文档(参见 http://code.google.com/appengine/docs/ python/config/appconfightml)。
现在来看下 index.yaml 文件。
indexes: # AUTOGENERATED # This index.yaml is automatically updated whenever the dev_appserver . . .
index.yaml 文件用于为应用创建自定义索引。为了让 App Engine 更快地查询 datastore, 需要每个查询有对应的索引(简单的查询会自动创建索引,无须手动添加)。除非是非常复杂的索引, 否则一般无须考虑索引问题。关于索引的更多内容,可以阅读官方文档, http://code.google.com/appengine/docs/python/config/indexconfig.html)。
最后一个由 Launcher 自动生成的文件是主应用文件(main.py),如示例 12-2 所示。
示例 12-2 主应用文件(main.py)
逐行解释
第 1~2 行
前两行导入了 webapp 框架,以及其中的 run_wsgi_app()工具函数。
第 4~6 行
在导入语句之后,会看到 MainHandler 类。这是本例中的核心功能。其中定义了 get() 函数,从名称就能看出,该函数用于处理 HTTP GET 请求。处理程序的实例会有 request 和 response 属性。在这个例子中,只将 HTML/text 写出,并通过 response.out 文件返回给用户。
第 8~11 行
接下来是 main()函数,用于生成并运行应用的实例。在实例化 webapp.WSGIApplication 的调用中,会发现一些二元组,目前只有一个它指定了每个请求对应的处理程序。在这里, 目前只须处理“/”这一个URL,这个请求将由刚刚介绍的 MainHandler 类处理。
第 13~14 行
最后,根据 Python 源码是作为模块导入,还是直接作为脚本执行,以此来决定执行方式。如果不熟悉这里的代码,建议回顾第 3 章和和本章前面的内容。
这些代码都很简单,即使有些是第一次见到。从这里开始,本书后面将持续修改应用, 改进或添加新功能。
一些代码清理
在向添加应用新功能之前,先对 main.py 做一点修改,这些修改不影响代码执行,如示例 12-3 所示。
示例 12-3 应用主程序的一些清理工作(main.py)
清理内容及原因
1.不希望在每次运行应用的时候实例化 WSGIApplication。将其从 main()函数中移入全局代码块中,只实例化该类一次,而不是每次请求都实例化。这样能带来一些性能提升, 虽然不大,但无论是否是 App Engine 或其他框架,在每个 Python 应用中都能做这样类似的简单优化。唯一的小缺点是该应用现在使用了一个全局变量与一个局部变量。
2.因为只使用了 webapp.util 中的一个函数,所以可以简化导入语句,直接导入函数名称,加快调用 run_wsgi_app()时的查找速度。调用util.run_wsgi_app()与调用run_wsgi_app()在一两次时没什么区别,但考虑到应用需要处理数百万条请求,这个改进带来的收益就很大了。
3.将“URL-处理程序”对分割到多行,有利于在后续添加新的处理程序,例如:
('/', MainHandler), ('/this', DoThis), ('/that', DoThat), . . .
这就是目前所做的改动。如果非要给个称号的话,这就是偏向“Django 风格”。