我想知道您是否可以帮我找到一种方法来在GAE数据存储区中对以下内容进行建模,使其具有可扩展性并且可以经常更新。我以为我有一个解决方案,我在 this question中表达过,但在等待回复的过程中,我意识到它可能过于复杂。我在下面解释了为什么我将它作为一个单独的问题保留。
问题: 构建一个系统,用户可以相互发送许多消息。每个用户都必须能够检索他们的消息 - 例如在线聊天。当用户可能在短时间内收到许多消息时,希望避免争用。
解决方案1: 如上所述here我想知道是否可以使用分片列表来实现这一点。我的意思是将消息存储为实体对象,发送者和接收者将这些对象的密钥(它们之间发送的消息)存储在列表中。我想到了分片,因为收到许多消息的用户必须经常更新列表,而分片方法可能会阻止数据存储争用。
问题 - 当说出用户收到的消息的密钥列表变大时会发生什么?会不会变得缓慢?我可以将列表分成几个实体,但这需要仔细考虑分配方案和检索方法。如果这是最好的方式,愿意这样做。
替代方法: 将消息存储为实体对象(如上所述),但这次让它们存储索引的属性(date,from,to等)。使用查询(日期大于...,来自= ...等)为用户检索消息。这可能会很好,但我担心 - 所有索引都会降级,因为它们会变得非常大,许多用户会发送许多消息吗?似乎它会降级为类似SQL的系统。
有什么想法吗?
我已经阅读了如何在GAE文档中建模复杂关系,但是他们使用python作为示例,我在抽象整体设计模式时遇到了问题。
非常感谢任何有此输入的人
PS目前直接使用低级数据存储区。
答案 0 :(得分:0)
我之前创建了一个类似于此的系统。我选择实现它的方式是我创建了一个Conversation
实体,它是许多Message
实体的父实体。对话有两个参与者(尽管你可以做更多),每个参与者都是User
实体的关键。
像这样(假设是)
@Entity public class Conversation {
@Id Long id;
@Index Key<User> participant1;
@Index Key<User> participant2;
@Index String participant1ExternalId;
@Index String participant2ExternalId;
}
@Entity public class Message {
@Id Long id;
@Parent Ref<Conversation> conversation;
@Index String senderExternalId;
@Index String recipientExternalId;
String message;
}
通过这种方式,您可以以最一致的方式查询参与者的所有会话,以及以强烈一致的方式接收或发送(或两者)对话的所有消息。我有一个额外的要求,即用户无法识别彼此,因此使用的消息生成了UUID(externalId属性)。
因此,通过这种方式,分片和1写/秒限制适用于会话级别。您可以将未读的计数器放在每个用户的会话对象上,或者如果需要,可以在每条消息上放置(在争用级别它没有真正的区别,所以无论什么都是最有意义的。)
如果您的用户每次会话每秒定期超过1条消息,那么除了数据存储区争用之外,您还需要解决许多其他问题,因此它可能是一个很好的起点。在一般情况下,最终的一致性对于这种操作(即检查新消息)非常有效,因此您可以严重依赖它。