【问题标题】:Synchronize Memcache and Datastore on Google App Engine在 Google App Engine 上同步 Memcache 和 Datastore
【发布时间】:2012-04-17 03:20:55
【问题描述】:

我正在使用 Google App Engine 编写聊天应用程序。我想记录聊天记录。不幸的是,Google App Engine 数据存储区只允许您每秒写入一次。为了解决这个限制,我正在考虑使用内存缓存来缓冲写入。为了确保不丢失数据,我需要定期将数据从 memcache 推送到数据存储中。

有没有办法在 Google App 上安排这样的工作。引擎?还是我以完全错误的方式处理这个问题?

我使用的是 Python 版本的 API,因此首选 Python 解决方案,但我对 Java 非常了解,可以将 Java 解决方案翻译成 Python。

【问题讨论】:

  • 您可以以每个实体组每秒 1 次的名义速率写入,但在现实世界中,您可以写入更多。 memcache 不是存储临时数据的好选择,因为它不能确保如果您将某些内容放入 memcache 中,它会在 1 秒后出现。
  • 您的用户聊天的速度有多快?每秒 1 次写入似乎足以跟上几个用户之间的标准聊天。
  • 一对用户的持续更新率不会超过每秒 1 条消息。即使是中等繁忙的 IRC 频道也不太可能有这种情况。
  • 我不担心超过每秒一次的持续更新率。我担心突发事件会导致我的应用超出数据存储更新 API 中的速率限制并丢失消息。

标签: python google-app-engine memcached google-cloud-datastore


【解决方案1】:

要绕过实体组的写入/更新限制(请注意,没有父级的实体是他们自己的实体组),您可以为每条聊天消息创建一个新实体,并在其中保留一个属性来引用他们所属的聊天.

然后,您将通过查询找到属于某个聊天的所有聊天消息。但这会非常低效,因为您需要为每个用户查询每条新消息。

因此,请遵循上述建议,但另外:

  1. 查看backends。这是永远在线的实例,您可以在其中聚合内存中的聊天消息(并立即/定期将它们刷新到数据存储区)。当用户请求最新的聊天消息时,您已经将它们保存在内存中并会立即提供它们(与使用 Datastore 相比节省时间和成本)。请注意,后端并非 100% 可靠,它们可能会不时出现故障 - 相应地调整聊天消息刷新到数据存储区。

  2. 查看Channels API。这将允许您在有新的聊天消息时通知用户。这样,您就可以避免轮询新的聊天消息并减少数量或请求。

【讨论】:

  • 看起来后端和通道将帮助我在 Google App 的限制内记录和执行实时更新。引擎。非常感谢!
【解决方案2】:

听起来像是错误的方式,因为您有丢失 memcache 数据的风险。

您可以每秒向一个实体组写入一次。

您可以非常快速地编写单独的实体组。因此,这实际上取决于您如何构建数据。例如,如果您将整个聊天记录保存在一个实体中,则您每秒只能编写一次该聊天记录。而且您将被限制为 1MB。

您应该在聊天中为每条消息编写一个单独的实体,您可以非常非常快速地编写,但您需要设计一种方法将所有消息集中在一起,以便记录日志。

编辑我同意 Peter Knego 的观点,即每条消息使用一个实体的成本太高了。他的后端建议也很不错,尽管如果您的应用很受欢迎,后端的扩展性就不会那么好。

我试图避免分片,但我认为这是必要的。如果您不熟悉分片,请阅读以下内容:https://developers.google.com/appengine/articles/sharding_counters

分片将是为对话中的所有消息编写一个实体与为每条消息编写一个实体之间的中间体。您将在多个实体之间随机拆分消息。例如,如果您将消息保存在 3 个实体中,则可以写入 5x/秒(我怀疑大多数人类对话会比这更快)。

在获取时,您需要抓取 3 个实体,并按时间顺序合并消息。这将为您节省很多成本。但是您需要编写代码来进行合并。

另一个好处是您的会话限制现在是 3MB 而不是 1MB。

【讨论】:

  • 好的,所以实际上我每秒只能更新一次实体。不过,我可以比这更快地创建新实体?
  • 是的,只要它们不在同一个实体组中(不共享父级等)。更专业地说,您可以每秒更新一次特定实体,但您可以非常快速地更新许多不同的实体,只要它们中的每一个仅以每秒一次的速度更新。
  • 然后他需要使用查询来为每个用户获取聊天消息,这可能会很昂贵。
【解决方案3】:

为什么不使用拉任务?如果您对任务队列不够熟悉,我强烈推荐这个 Google 视频。前 15 分钟将涵盖可能适用于您的情况的拉取队列信息。涉及每条消息更新的任何事情都可能会变得非常昂贵:数据库操作,如果您涉及任何索引,这将非常加剧。视频链接: https://www.youtube.com/watch?v=AM0ZPO7-lcE&feature=player_embedded

当用户在在线处理程序中启动它时,我会简单地设置我的聊天实体,将实体 ID 传递回聊天方。将 id+消息发送到您的拉取队列,并在聊天实体的 TextProperty 中序列化消息。您可能不会比每秒一次更频繁地安排拉取队列 cron,这样可以避免您的实体更新限制。最重要的是:您的数据库操作将大大减少。

【讨论】:

    【解决方案4】:

    我认为您可以创建将保留数据的任务。这样做的好处是,与 memcached 不同,任务是持久的,因此不会丢失任何聊天记录。

    当有新聊天进入时,创建一个任务来保存聊天数据。在任务处理程序中执行持久化。您可以将任务队列配置为每秒拉 1 次(或稍慢)并将任务中保存的每一位聊天数据保存在临时表中(在不同的实体组中),并且每个任务都拉临时表中所有未保存的聊天,将它们持久保存到聊天实体,然后将它们从临时表中删除。

    【讨论】:

      【解决方案5】:

      我认为您可以将聊天会话用作实体组并保存聊天消息。
      这个每秒一次的限制不是现实,你可以以更高的速度更新/保存,我一直在这样做,我对此没有任何问题。 memcache 是易失的,对于您想要做的事情来说是错误的选择。如果您开始遇到写入速率问题,您可以开始设置任务来保存数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多