在Google App Engine中使用缓存

标签:Google App Engine, Python

由于GAE的数据库很慢,所以当需要一些更快速的持久性存取操作时,数据库就显得力不从心了。
好在Google也考虑到这个问题,提供了Memcache API来解决性能问题。方法就是把经常使用的、在数据库中查询比较耗时的数据放在内存中缓存起来,然后直接访问内存即可。

由于是放在内存中,服务器或应用程序重启后,缓存数据就清空了。但庆幸的是,这些缓存也和数据库一样是分布式的;除非这些分布式的服务器都同时重启了,否则缓存是不会失效的。
当然,缓存也是有大小限制的,超过缓存大小后,部分数据就会被“挤出”缓存。但是Google并没说明缓存的具体大小,也没解释缓存的替换原则。(据我的测试表明,这个缓存应该不到30MB,而且在超过25MB时,就会将部分数据按情况“挤出”缓存。)
此外有个很无语的问题,缓存API的调用也是算在配额内的,而且配额比数据库要少。这意味着你不能把所有东西都尽可能放在缓存中,否则可能超出配额。

由于Memcache API的函数非常简单,所以就直接说示例代码了:
from google.appengine.api import memcache

# 增加一个值,过期时间为1小时
memcache.add(key="weather_USA_98105", value="raining", time=3600)

# 同时设置多个值,注意可以用key_prefix
memcache.set_multi({ "USA_98105": "raining",
                     "USA_94105": "foggy",
                     "USA_94043": "sunny" },
                     key_prefix="weather_", time=3600)

# 自动增加整型值
memcache.set(key="counter", 0)
memcache.incr("counter")
memcache.incr("counter")
memcache.incr("counter")
当然,你可以把取数的逻辑写在一个函数里,缓存中找不到时就从数据库中取:
def getData(key):
  data = memcache.get(key)
  if data is None:
    data = db.get(key)
    if data:
      memcache.add(key, data)
  return data
这个函数是通过对象的key来取数的,你还能写个一般性的函数:
def getData(key, getDataFromDB):
  data = memcache.get(key)
  if data is None:
    data = getDataFromDB(key)
    if data:
      memcache.add(key, data)
  return data

def getDataFromDB(key)
  #这里面就可以写自己的取数逻辑了,我这里只是个例子
  #你可以可以定义多个不同的这个函数(当然名字也是不同的)
  return db.GqlQuery("SELECT * FROM Person WHERE name = :1", key).get()

#调用也是非常简单的
person = getData('keakon', getDataFromDB)
我感觉最有用的就是计数器了,因为查询对象的count操作最多只能返回1000,放在缓存中则没这个限制(不过要确保不会被替换出去):
class Image(db.Model):
  content = db.BlobProperty()
  type = db.StringProperty(choices = set(["jpeg", "gif", "png"]))
  def getCounter(self):
    counter = memcache.get('ImageCounter')
    if counter is None:
      counter = Image.all().count()
      if counter:
        memcache.add('ImageCounter', counter)
    return counter
当然,别忘了在增加和删除实体时,用incr和decr函数来更改counter(这个也能封装成函数)。

0条评论 你不来一发么↓

    想说点什么呢?