【问题标题】:how to keep memcache and datastore in sync如何保持内存缓存和数据存储同步
【发布时间】:2014-08-22 14:21:20
【问题描述】:

假设我有数百万用户注册了我的应用。现在有一个新用户,我想告诉他所有联系人中的哪些人都安装了这个应用程序。一个用户可以有很多联系人,比如说 500 个。现在,如果我从数据存储区为每个联系人获取一个实体,那么这将非常耗时和耗费金钱。 memcache 是一个不错的选择,但我必须让它与那种类型保持同步。我可以为这么大的数据获取专用的内存缓存,但是我该如何同步呢?我的逻辑是,如果内存缓存中不存在该联系人,则假定该联系人未在此应用中注册。具有手动缩放功能的后端模块可用于使两者保持同步。但我不知道这个设计有多好。任何帮助将不胜感激。

【问题讨论】:

  • 你使用什么语言?
  • 它是 Java。它是 servlet 上的网络服务。
  • :(。Python 有 ndb 可以为你做到这一点 :(

标签: google-app-engine memcached


【解决方案1】:

这不是 memcache 的设计用途。你永远不应该依赖内存缓存。钥匙随时可能掉落。因此,就您而言,您永远无法确定联系人是否存在。

我不知道您的数据存储有什么问题? Datastore 旨在非常快速地读取数据 - 充分利用它。

当新用户安装您的应用时,创建一个以电话号码为键的查找实体。您不一定需要任何其他属性。像这样的:

Entity contactLookup = new Entity("ContactLookup", "somePhoneNumber");
datastore.put(contactLookup);

这将记录谁安装了应用程序。

然后,要检查您的哪些用户联系人已经在使用您的应用,您可以从用户通讯录中的电话号码中创建一个密钥数组(当然要获得他们的许可!),然后执行批量获取。像这样的:

Set<Key> keys = new HashSet<Key>();

for (String phoneNumber : phoneNumbers)
    keys.add(KeyFactory.createKey("ContactLookup", phoneNumber));

Map<Key, Entity> entities = datastore.get(keys);

现在,entities 将是那些安装了您的应用的联系人。

您可能需要对密钥进行批处理以减少负载。 python api 为您执行此操作,但不确定 java api。但即使您的用户有 500 个联系人,也只有 5 个查询(假设批次为 100)。

附注:您可能需要考虑对电话号码进行哈希存储。

【讨论】:

  • 您不能使用 Memcache 来确定实体是否不存在,但您当然可以使用 Memcache 来检查实体是否已经存在 - 如果存在则避免访问数据存储。这是 Memcache 最常见的用例。
【解决方案2】:

Memcache 是降低成本和提高性能的好选择,但您不应假设它始终可用。即使是专用的 Memcache 也可能会失败,或者可能会逐出单个记录。此外,所有这些同步逻辑都会非常复杂且容易出错。

您可以使用 Memcache 来指示联系人是否已在应用中注册,在这种情况下,您无需检查该联系人的数据存储区。但我建议检查所有未在数据存储区的 Memcache 中找到的联系人。

验证数据存储中是否存在记录既快速又便宜。您可以使用.get(java.lang.Iterable&lt;Key&gt; keys) 方法通过单个数据存储调用检索整个列表。

您可以通过为注册用户创建一个没有属性的实体来进一步提高性能。这样,检索这些实体就不会产生任何开销。

【讨论】:

  • 我想我没有正确解释这个问题。当用户在他的手机上安装此应用程序时,客户端应用程序会将用户的联系人列表从手机发送到服务器。该列表可以包含 500 多个联系人。现在服务器需要检查这些联系人是否已在此应用中注册。如果服务器能够获取实体(key=contact.number),那么它可以假设联系人已注册。没有必要进入数据存储区,我只想从 memcache 中得出结论。这就是为什么我要让内存缓存和数据存储与后端实例保持同步。
  • 为了保持同步,您必须定期从数据存储中检索所有记录。现在,如果 memcache 失败,您的应用程序将假定在下一次同步完成之前没有任何联系人注册到应用程序。这将迫使您经常运行这些同步,这会变得昂贵。我会更新我的答案。
  • 是的,这就是我寻找替代品的原因。
【解决方案3】:

由于您不使用 python,因此无法访问 NDB,因此建议您在添加用户时,将他添加到 memcache 并创建异步查询(或任务队列作业)以推送相同的数据到您的数据存储。就像首先推送 memcache,然后最终推送数据存储一样。它们将始终保持同步。

然后,您需要做的就是在执行“获取”时首先查询您的内存缓存(因为内存缓存始终保持同步,因为您首先推送到那里),如果内存缓存返回空(易失性等等),然后查询要“重新填充”内存缓存的实际数据存储区

【讨论】:

  • 我无法决定何时补充。如果 memcache 返回空,则可能是联系人未在此应用中注册,或者 Key 已从 memcache 中删除。我不想去所有联系人的数据存储区。
  • 您想让 memcache 始终保持同步吗?....这听起来很昂贵...您需要在后台执行 cron 作业才能经常运行并将所有内容同步回来... . 并且由于 memcache 不稳定,我认为这不是一个好的选择成本明智的选择,因为它会耗尽你的配额并且会花费很多。
  • 我是这么认为的,这就是为什么在这里要求更好的设计:-)
  • 我很确定这不是 memcache 本来应该如何使用的不幸......你不能确定它会在那里......即使有一个 cron 工作,您基本上需要每秒运行一次,以确保您的数据始终同步。如果您的数据存储对于 memcache 来说太大了,会发生什么?我没有看到您提出问题的真正解决方案
  • 必须有一些选择。例如,whatsapp 做同样的事情,它显示谁都在我的联系人中安装了这个应用程序。它们可能不在 appengine 上,但在这个平台上有类似的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多