Google App Engine 上的全栈开发






4.75/5 (4投票s)
在Google App Engine上开发和运营全栈Web应用程序和API,提高开发效率和运营效率,包括前端应用程序和UI、RESTful Web服务以及Google App Engine上的NoSQL数据库持久层。
引言
Google Cloud Platform为第三方开发者开放了Google海量、高速、广泛的网络和支持基础设施,而Google App Engine是赋能开发者在云端实现高开发效率和高运营效率的主要支柱之一。本文讨论了在初创项目案例中选择云平台的背景思考,并提供了引导您启动自己的GAE项目的框架和示例代码。
本文可以看作是Google App Engine上的一个入门级全栈项目,同时也是面向服务HTML应用程序(SOHA)在GAE上的一个实现。
背景
大约6个月前,在启动一个全新的基于n层云的项目时,我面临着不同云平台提供的各种开发、托管和运营选项。初步的筛选范围很快缩小到三个选项:Amazon Web Services、Windows Azure和Google Cloud Platform。对于成本效益、生产力敏感和快速迭代的项目,哪个是最合适的?
不进行这些流行云计算平台的优缺点比较和分析,直接切入主题,在对这三个平台进行试验和评估后,我想谈谈选择Google App Engine的最大好处:开发者生产力和运营效率。
GAE通过完全托管的平台即服务(PaaS)提供了极高的开发者生产力,利用了Google用于运行自身产品的相同基础设施上运行的大量内置服务。开发者可以更专注于自己的代码和项目,将虚拟机管理、数据库管理、系统补丁、库更新、服务器配置、分片和负载均衡等工作交给Google。开发者需要做的就是使用GAE SDK开发项目并部署到GAE,其余的都交给Google来处理。当您的应用程序走红,更多的并发用户产生更多的服务器负载时,GAE会在运行时自动动态地处理自动扩展。
此外,GAE通过消除样板代码来提高开发者的生产力,还可以轻松集成许多托管服务,如用户、地图、地理编码、Gmail、Docs API以及任务队列、Memcache和NoSQL数据存储。在GAE上启动和运行非常简单,只需下载Google App Engine SDK并启动您喜欢的IDE。
除了极高的开发者生产力,Google Cloud Platform控制台还提供了大量易于使用的工具和仪表板,用于应用程序的运营任务。Cloud Datastore仪表板在您登录时显示所有实体统计信息,控制台还允许您在浏览器中查看、查询、更新和创建实体,无需任何配置。与经典的数据库管理和模式配置模型相比,GAE通过消除数据库(Cloud Datastore)的配置和管理设置,提供了卓越的运营效率改进。
运营效率不仅仅是零配置。服务器端日志监控也可以在浏览器窗口中进行,尽管监控仪表板和警报尚未公开发布,但App Engine仪表板提供免费的高级跟踪统计信息,包括每秒请求数图表、VM实例(QPS、延迟、内存使用、启动时间等)、并发负载、服务器错误、Memcache键和状态、任务队列和配额详细信息。
GAE对多租户的支持强大而灵活,它能够轻松实现应用程序的隔离,并且通过流量分割,应用程序的A/B测试对不同的实时版本在平台级别得到了很好的支持。
Google App Engine比其他云平台(如成本效益等)还有更多优势,我暂时会局限于技术范围。Google托管的环境对开发者来说相当友好易于掌握,其内置的运营仪表板和统计/跟踪/监控/数据库查询功能更是锦上添花。
GAE的生产力和效率是我选择它进行全栈开发的首要原因,也是我撰写本文的强大动力。在软件工程方面,Google让您放弃的是选择编程语言和运营工具的自由。目前,GAE运行时或SDK仅支持四种语言:Java、Python、Go和PHP。如果偏好Node.js、Ruby或其他语言,您可能需要转向Compute Engine,或AWS EC2,或Windows Azure,但那样您还需要开始管理VM、操作系统和配置可扩展性。对我来说,这是一个可以忽略的权衡,我从一无所知Python开始,在几天内就熟练掌握了它。
本文将提供Python 2.7的代码片段和示例项目。该示例项目是一个全栈Web应用程序,我们在这里展示的是,通过关注关注点分离以及出色的可扩展性和可管理性,构建现代Web应用程序和服务的效率有多高。
我们要构建什么
我们将在Google App Engine上使用SOHA架构构建一个全栈现代Web应用程序。从高层次来看,我们的Web应用程序包含SOHA中的3个主要原则:
- 与表示无关的Web服务或API,它实现业务逻辑和数据访问层,通过RESTful端点暴露功能。它通常运行在具有数据库访问的应用服务器上,在我们的GAE实现中,我们的API是项目的一部分,部署在同一个GAE上,同时保持与任何表示或用户交互逻辑无关;
- 前端静态文件与API分离,并通过HTTP提供服务。通常这一层由Web服务器提供服务,如Apache或Nginx,由于Google App Engine上没有“Web服务器”的概念,我们将通过YAML实现它,也无需Web服务器配置;
- HTML5用户界面,通过Ajax与后端API交互。您喜欢的JavaScript框架在这里表现良好,无论是Angular、Backbone、Ember还是其他任何框架,无论是单页应用(SPA)还是具有安全导航的多页应用(MPA),都可以正常工作。
示例项目主要执行两项任务:保存和获取数据。它实现了一个端点,该端点接受并验证HTTP POST请求,然后将数据保存到Google Cloud Datastore - Google的NoSQL云数据存储版本。它还提供了一个通用的数据检索机制,展示了对ndb.Model JSON序列化、响应打包、排序、分页以及属性查询的支持,具有极大的灵活性,它不仅可以查询具有实际值的属性,还支持通过查询字符串中的字典字面量进行“OR”操作,以及通过查询字符串中的元组字面量进行范围操作,更多细节可以在GitHub上找到。
入门
快速简便:从Google获取项目ID,激活Google Cloud Datastore,启动Google App Engine App Launcher,您就可以开始使用了。
它构建于什么之上
HTML5用户界面将使用以下框架、库和工具构建:
- Angularjs:一个JavaScript框架,通过MVC功能增强基于浏览器、单页应用程序:https://angularjs.org/
- Twitter Bootstrap:时尚、直观、强大的前端框架,用于更快、更轻松的Web开发和样式设计:https://bootstrap.ac.cn/
- Less:扩展了CSS语言,增加了允许变量、混合、函数和其他多种技术的功能,使CSS更易于维护、主题化和扩展:http://lesscss.org/
- Font Awesome:专为Twitter Bootstrap设计的标志性字体:http://fortawesome.github.io/Font-Awesome/
- 前端包管理器:http://bower.io/
- Grunt-based构建系统,旨在为您节省时间和精力:https://grunt.node.org.cn/
- Web App项目结构(使用ng-boilerplate)和单元测试:https://github.com/ngbp/ngbp
至于API层,在Google App Engine上用Python构建RESTful Web服务/API有许多框架。我评估了Django、Django REST framework、Google Cloud Endpoints,由于我只需要一个轻量级、易于使用且可插拔的纯RESTful框架,最终我选择了以下堆栈:
Flask-RESTful
Flask-RESTful为构建RESTful服务提供了一个轻量级的抽象;它是Flask的一个扩展,具备了在Google App Engine上快速启动RESTful服务的全部功能。
Flask-RESTful的所有依赖项,以及依赖项的依赖项,都打包在/lib/
目录中,包括:
- aniso8601
- flask
- pytz
- werkzeug
- itsdangerous
RESTful API构建块
虽然Flask-RESTful为各种RESTful服务构建块提供了出色的起点,例如有用的装饰器、Resource基类、简单的API路由、请求解析和验证、错误处理等,但总有机会添加更多实用程序和辅助函数,使其更适合您的特定项目。为了尽可能通用,我还将以下构建块包含在api/common
目录中:
- response.py:两个基类,用于以统一的形式构建所有响应
- session.py:利用Google App Engine的Memcache验证会话
- util.py:大量实用方法,主要围绕数据类型和ndb模型处理
- validators:与ReqParse配合使用的验证器类型
CORS支持
Flask Restful中CORS的内置实现存在自动处理HTTP OPTIONS调用时的问题,它会在为方法装饰器正确设置时返回404。我对Flask Restful的CORS支持进行了两项改进(在lib/flask_restful/utils/cors.py中查找“MQZ”前缀的注释):
- 默认HTTP OPTIONS处理程序
# MQZ. 08/12/2014: without this, will get 405 responses for OPTIONS request f.required_methods = ['OPTIONS']
- 默认启用Cookie支持
# MQZ. 8/26/2014: Make sure cors support for cookies (with_credentials), default on def crossdomain(origin=None, methods=None, headers=None, max_age=21600, attach_to_all=True, automatic_options=True, with_credentials=True):
然后,在第43行
if with_credentials: h['Access-Control-Allow-Credentials'] = True
如果在CORS方面遇到问题,请在GitHub上给我留言。
源代码结构
由于Flask-RESTful默认不包含在Google App Engine中,我们需要构建项目以使其“云就绪”。所有必要的库、源树和脚本/yaml都已包含:
lib
:此目录包含Flask-RESTful所需的所有第三方Python库,无需运行特殊的安装命令,只需克隆或复制整个目录即可使用。app.yaml
:Google App Engine需要app.yaml来运行您的项目,由于本项目是SOHA架构的后端示例,因此此文件基本上是空的:它只包含另外两个yaml文件,以确保前端与后端分离,这两个yaml文件是:web_app.yaml
:这是用于在Google App Engine上托管静态网站的yaml文件的一个分支。我对该yaml文件唯一的更新是告诉GAE在/app/
文件夹下查找‘index.html’,所有其他前端静态文件,无论是Angular还是Backbone项目,都应放在/app/
文件夹下。否则,您可以修改yaml文件中的rules列表以匹配您自定义的文件夹结构;web_api.yaml:
这个yaml文件告诉Google App Engine,如果请求路径匹配/api/*
,则加载哪个Python类来运行RESTful服务。
appengine_config.py
:此Python文件用于告知Python运行时使用/lib/
目录下的Python模块。data.datastore
:用于本地测试的可选数据文件,在本地主机上运行项目时需要带有--datastore_path=<Your Clone Path>/data.datastore
命令行参数。api/config.py
:此处定义了一些API级别的配置常量和变量,包括:- 会话时间跨度
- 数据存储版本字符串
- 用于版本管理的API基础URL
- 应用程序版本等。
灵活的数据检索
如前所述,本项目提供了一个通用的数据检索机制(在modelX.retrieve_list中定义为通用静态方法),它支持ndb.Model JSON序列化、响应打包、排序、分页以及属性查询,具有极大的灵活性。它不仅可以查询具有实际值的属性,还支持通过查询字符串中的字典字面量进行“OR”操作,以及通过查询字符串中的元组字面量进行“Range”操作。以下是一些通过HTTP GET进行的查询示例:
默认查询(默认限制设置为20:最多返回20个实体)
curl -isv https://:8080/api/v1.0/calllogs/
按名称排序(升序)
curl -isv https://:8080/api/v1.0/calllogs/?order=name
按名称排序(降序)
curl -isv https://:8080/api/v1.0/calllogs/?order=-name
排序和限制
curl -isv "https://:8080/api/v1.0/calllogs/?order=-name&limit=2" notice "more_cursor" and "more_url" in the response
分页(光标值在早期调用中返回)
curl -isv "https://:8080/api/v1.0/calllogs/?cursor=E-ABAOsB8gEEbmFtZfoBChoISGVrdGhvbjXsAYICNWodZGV2fmNhbGwtbG9nLTIxMS1kYXRhLXNlcnZpY2VyFAsSB0NhbGxMb2cYgICAgID0jgoMiAIBFA%3D%3D&limit=2&order=-name"
列出所有名称为“Hekthon5”的实体(默认限制)
curl -isv https://:8080/api/v1.0/calllogs/?name=Hekthon5
OR:列出所有名称为“Hekthon5”或“Hekthon4”的实体(默认限制)
curl -isv -G --data-urlencode "name=['Hekthon5', 'Hekthon4']" https://:8080/api/v1.0/calllogs/ Notice the square bracket in the query string, this list literal will make the value to be an option ist
范围:列出所有创建时间在“2014-08-01 00:00:00”和“2014-08-04 23:59:59”(含)之间的实体(默认限制)。
curl -isv -G --data-urlencode "created=('2014-08-01 00:00:00', '2014-08-04 23:59:59')" https://:8080/api/v1.0/calllogs/ Notice the parentheses in the query string, this tuple literal will make the value to be a range
运行和部署项目
Google提供了出色的文档,介绍如何在本地开发服务器上运行,以及如何部署和管理您的应用到App Engine。您还可以参考Python教程了解更多详情。
总结
Google App Engine提供了一种经济高效且对开发者友好的方式来构建现代Web应用、API和移动后端。其完全托管的运行时环境承担了自动扩展、动态计算资源分配、关键监控和跟踪等繁重工作,再加上其他内置工具和仪表板(如浏览器中的数据库CRUD控制台等),极大地提高了开发效率和运营效率。本文讨论的示例项目进一步扩展了Google的开箱即用功能,其代码结构、yaml和appengine_config.py都已准备好用于生产环境,希望它能帮助您在GAE上的全栈开发变得更加灵活和强大。