迟到的Google App Engine折腾笔记

last modified : 2015-08-29 | published: 2016-01-05 | category:

缘起

毕竟不是程序员,写代码不为赚钱,都是带着自己的目的性,笔记什么的,似乎也就没记过。 其实第一次接触GAE是2010年,也是最早接触python的时候,做了一个简单的随机头像的应用,那时候GAE还没被墙,大家还在探索GAE有什么奇奇怪怪的用途。 借助GAE,完成了python的自学和启蒙,感谢GAE。 但后来,goagent被发扬光大,GAE被墙,就接着几年没碰过了。 直到最近,django做了一个股票新闻抓取并关键词提醒的app。但毕竟爱折腾,在折腾各种乱七八糟的过程中,vps瘫痪了,突然想起来,程序如果跑在GAE上,似乎可以杜绝折腾VPS引起的问题。但一切并不顺利,一倍时间django写的程序,用了2倍时间,才迁移到GAE。

NOTE1:免费的GAE配额,以及一些坑

相比之下,其他的配额对应用的影响微不足道:Memcache是免费的。UrlFetch除非抓来的数据不做任何处理,Mail除非用来滥发邮件。

NOTE2:节省各种配额

NOTE3:节省CPU配额:使用asynchronous urlfetch

为节约网络延迟而浪费的cputime,使用异步urlfetch就十分重要。 官方手册在这里,例如:在抓取多个feed时:

q = Feed.query()
results = ndb.get_multi(q.fetch(keys_only=True))

rpcs = []
for f in results:
    rpc = urlfetch.create_rpc()
    urlfetch.make_fetch_call(rpc, f.url)
    rpcs.append(rpc)

for rpc in rpcs:
    rpc.wait()
    result = rpc.get_result()
    d = feedparser.parse(result.content)
    for e in d['entries']:
        # do something....

NOTE4:节省CPU配额:需要初始化的资源,在本地进行序列化,GAE上直接读取序列化的资源。

以jieba词库为例:默认情况,jieba每次初始化,都会将本地词库dict.txt进行readline操作,生成字典,这个过程在GAE默认的CPU上需要将近6秒。而在本地,先将这个字典使用marshal.dump,在GAE中在load,初始化阶段则只消耗1.x秒。

try:
    with open(cache_file, 'rb') as cf:
        object_a, object_b = marshal.load(cf)
except :
    for line in open(dict, 'rb').read().decode('utf-8').splitlines():
        # do something....
with open(cache_file, 'wb') as cf:
    marshal.dump((object_a, object_b), cf)

NOTE5:节省CPU配额:减少服务器端的请求

self.response.headers['Cache-Control'] = 'public, max-age:300'
self.response.headers['Pragma'] = 'Public'

NOTE6:资源优化:删掉过时的数据

节约数据库存储空间最简单的方法,就是删掉过时的数据,而对于ndb,不存在Object.query().del() 这样的方法,需要使用:

earliest = datetime.datetime.now() - datetime.timedelta(days=10)
keys = EntryCollect.query(EntryCollect.published <= earliest).fetch(keys_only=True)
ndb.delete_multi(keys)

NOTE6:使用robots.txt 减少搜索引擎对app的负载

不失为一个办法,一个个位数pv的app,被bot拖到配额超限真的好23333...

NOTE7:自定义webapp2模板的tags

和django不同,webapp2稍微麻烦一点,这里以新建一个在模板里使用时区的tags为例。

首先,新建一个目录common,新建一个文件common\customtags.py

from datetime import timedelta
from google.appengine.ext.webapp import template
register = template.create_template_register()

def timezone(value, offset):
    return value + timedelta(hours=offset)

register.filter(timezone)

在views.py顶端加入

from google.appengine.ext.webapp import template
template.register_template_library('common.customtags')

最后,在模板内可以直接使用,不需要 load xxxxx published|timezone:8|date:"H:i"

NOTE8:使用代理服务器部署代码

set HTTP_PROXY=http://127.0.0.1:1080
set HTTPs_PROXY=http://127.0.0.1:1080
c:\Python27\python.exe x:\google_appengine\appcfg.py update x:\ProjectDir

待编辑...

心里只有一万个WTF,一万个草泥马。 GAE的Datastore收费方法简直令人恶心,一个App的开发过程中,想着怎么优化write/read Op,浪费的时间和精力,你定可以转换为很多创新点子...特别是对于一个不存在code review的个人App来说。 如果app自用且足够小,放到GAE上追求个稳定,还是可以接受的,但也仅限如此了...