【问题标题】:When to use a certain type of persistence in Google App Engine?何时在 Google App Engine 中使用某种类型的持久性?
【发布时间】:2009-07-28 11:53:13
【问题描述】:

首先我会解释这个问题。持久性是指在执行单个请求之外存储数据。它可能不是最好的问题标题,所以请随意编辑它。

在我看来,GAE 中存在三种持久化类型,每一种都“更接近”请求本身:


数据存储

这是所有数据最有可能建立的地方。它可能会暂时进入更高层的持久性,但最终,这才是数据真正所在的地方。不幸的是,重复查询数据存储很慢,而且会占用大量资源。

在...时使用

  • 存储应无限期存储的数据。

避免使用when...

  • 获取经常查询但很少更新的数据。

内存缓存

这是一个高度复杂的缓存引擎,它将数据存储在内存中,并确保所有用户都读取/写入相同的缓存。与使用数据存储相比,这是一种基于键→值获取/设置数据的更快方法。不幸的是,数据只能在内存中保留这么长时间,并且不能保证它会保留多久,只要你告诉它;如果其他地方需要内存,数据可能随时消失。

在...时使用

  • 您需要更频繁地获取数据而不是需要更新它。即使需要经常更新数据,也可以通过设置task queue 将数据从内存缓存持久保存到数据存储区,从而发挥作用(如果认为一些错过的更新还可以)。

避免使用when...

  • 数据需要经常更新,并且在获取时必须是最新的。

全局变量

这不是持久化数据的官方方法,但它确实有效。但是,它是最不可靠的方法,并且由于它没有跨服务器的数据同步,因此不同用户的持久数据可能会有所不同(但据我发现,服务器很少为同一用户更改。)理论上,这应该然而,它是获取/设置值开销最小的方法,并且可能有它的用途。

在...时使用

  • 地狱结冰了?我不知道......我对幕后发生的事情没有足够的了解,无法真正依赖这种方法。讨论!

避免使用when...

  • 您依赖于跨服务器的数据相同。

Cookies

如果数据是特定于用户的,则将其作为 cookie 存储在用户浏览器中会很有效。不过有一些陷阱需要注意:

  • 安全 - 用户可以干预 cookie,恶意人员也可能这样做。为确保内容对所有人不可读且不可更改,可以使用 GAE 上提供的 PyCrypto 库对 cookie 进行加密。
  • 性能 – 由于 cookie 随每个请求(甚至图像)一起发送,它可以增加正在使用的带宽,并减慢请求。一种解决方案是为静态内容使用另一个域,这样浏览器就不会发送该内容的 cookie。

什么时候应该使用不同类型的持久性?如何将它们结合起来以减少/平衡所花费的资源量?

【问题讨论】:

  • 另一种保存数据的方法是在用户的浏览器中放置一个cookie。

标签: google-app-engine persistence


【解决方案1】:

数据存储

使用数据存储来保存任何长期存在的信息。应该像使用普通数据库一样使用数据存储来保存将在您的站点/应用程序中使用的数据。

内存缓存

使用它来访问数据比尝试访问数据存储要快得多。 MemCache 可以非常快速地返回数据,并且可以用于需要跨越用户多次调用的任何数据。通常是数据最初在数据存储中,然后移动到内存缓存中。

def get_data():
  data = memcache.get("key")
  if data is not None:
    return data
  else:
    data = self.query_for_data() #get data from the datastore
    memcache.add("key", data, 60)
    return data

当项目过期时,memcache 将自行刷新。您在上面显示的 add 的最后一个参数中设置它。

全局变量 我根本不会使用这些,因为它们不能跨越实例。在 GAE 中,一个请求会创建一个新实例,而在 python 中它确实如此。如果你想使用全局变量,我会将所需的数据存储在内存缓存中。

【讨论】:

  • 不正确:App Engine 中的每个请求都不会创建新实例。
  • 我阅读code.google.com/appengine/docs/python/tools/webapp/… 的方式确实如此。如果不使用 memcache 或数据存储,我永远无法在 GET 之间共享信息。如果您有一些代码,那么我很乐意看到它,因为我有一些有用的实例。
  • Request 对象总是新的,是的。但是,您的应用程序的全局范围在请求之间保持“活动”,因此不必再次导入所有内容。尝试检查全局变量是否有值,如果没有,请将其设置为随机值。然后尝试在您的应用程序中打印出它的值。
【解决方案2】:

您的帖子很好地总结了 3 个主要选项。你大多已经回答了这个问题。但是,如果您目前正在构建一个应用程序并为是否应该使用内存缓存而感到压力,请尝试以下操作:

  1. 使用数据存储区编写您的应用程序,以处理需要超过一个请求的所有内容。
  2. 在您的应用(或一些可用的子集)运行后,运行一些功能测试或模拟以查看慢点(或高配额使用率)在哪里。
  3. 找到最慢或最低效的请求路径,并找出如何使其更快(通过使用内存缓存,或更改数据结构以便您可以执行获取而不是查询,或者可能将某些内容存储在全局实例变量中*)
  4. 转到 2 直到您满意为止。

*可能对“全局”变量有好处的东西是创建/获取相对昂贵的东西,你的大部分请求将使用它,并且不需要在请求/用户之间保持一致。

【讨论】:

  • 是的,实际上我已经这样做了...我已经启动并运行了一个仅使用数据存储的应用程序,我目前正在让一群人尝试看看哪些请求使用最多的资源。但我创建这篇文章部分是为了帮助其他人寻找相同的东西,部分是因为我不确定是否使用全局对象(它们必须以某种方式耗尽内存,但不像 memcache 那样以受控的方式;谷歌的大型政策是什么?全局对象等?)
【解决方案3】:

我使用全局变量来加速 json 转换。在将我的数据结构转换为 json 之前,我对其进行哈希处理并检查 json 是否已经可用。对于我的应用程序,这提供了相当快的速度,因为纯 python 实现非常慢。

【讨论】:

    【解决方案4】:

    全局变量

    为了补充 AutomatedTester 的回答,并回答他关于如何在 没有 memcache 或数据存储的情况下在 GET 之间共享信息的进一步问题,下面是如何使用全局变量的快速说明:

    if 'i' not in globals():
        i = 0
    
    def main():
        global i
        i += 1
        print 'Status: 200'
        print 'Content-type: text/plain\n'
        print i
    
    if __name__ == '__main__':
        main()
    

    多次调用这个脚本会给你 1、2、3... 当然,正如 Blixt 前面提到的,你不应该过多地依赖这个技巧('i' 有时可以切换回零)但它可以是对于将用户特定信息存储在字典中很有用,例如会话数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-14
      • 2012-05-28
      • 2013-04-17
      相关资源
      最近更新 更多