App Engine简单游戏模型实验(可扩展)

时间:2009-12-25 15:58:35

标签: google-app-engine

所以我已经阅读了所有RMDB与BigTable的争论

我尝试使用BigTable概念建模一个简单的游戏类。

目标:提供非常快速的读取和相当容易的写入

场景:我的用户模型中有500,000个用户实体。我的用户在他/她的游戏页面顶部看到了一个用户统计信息(想想像黑手党战争一样的状态栏),所以无论他/她进入游戏,统计数据都会刷新。

由于频繁调用,为什么我不围绕这个事实对用户进行建模?

代码:

# simple User class for a game
class User(db.Model):
  username = db.StringProperty()

  total_attack = db.IntegerProperty()

  unit_1_amount = db.IntegerProperty()
  unit_1_attack = db.IntegerProperty(default=10)

  unit_2_amount = db.IntegerProperty()
  unit_2_attack = db.IntegerProperty(default=20)

  unit_3_amount = db.IntegerProperty()
  unit_3_attack = db.IntegerProperty(default=50)

  def calculate_total_attack(self):
    self.total_attack = self.unit_1_attack * self.unit_1_amount + \
                        self.unit_2_attack * self.unit_2_amount + \
                        self.unit_3_attack * self.unit_3_amount + \

这就是我如何接近它(随意评论/批评)

优点:
一切都在一张大桌子上 2.无需使用ReferenceProperty,也无需使用MANY-TO-MANY关系 3.更新非常容易:只需按键名称获取用户实体 4.将查询的实体转移到模板引擎很容易。

缺点:
1.如果我拥有100个具有不同能力(攻击,防御,灵巧,魔法等)的不同单位,那么我将拥有一张非常巨大的桌子。
2.如果我必须更改某个攻击单位的值,那么我将不得不通过所有500,000个用户实体来更改它们中的每一个。 (也许一个cron作业/任务队列会有帮助)

每个实体的大小为5-10 kb(顺便说一下,如果我将它们上传到生产服务器,我如何检查实体的大小?)。

所以我指望App Engine上的磁盘空间很便宜,我需要最小化数据存储API调用的数量。我会尝试将实体记忆一段时间。

从本质上讲,这里的一切都违背了RMDB

很想听听你的想法/想法/经历。

3 个答案:

答案 0 :(得分:1)

首先简单回答“我怎么知道一个实体有多大?”:一旦你在应用引擎服务器上的应用中获得了一些数据,你就可以转到你的应用了控制台并单击“数据存储区统计信息”链接。这将为您提供有关您的实体的一些基本统计信息,例如每种类型使用的空间大小,使用最多磁盘空间的属性类型等等。但我认为您不能深入到某个特定用户的级别。

现在这里有一些关于你的设计的想法。为你的单位创建一个单独的表是值得的。即使您最终只有几百个单位,也很容易将它们全部保存在内存中,因此查找每个单元的详细信息可以忽略不计。它会花费你一些额外的API调用,以便在第一次使用单元的信息时初始填充内存缓存,但之后你将不必从数据库中获取每个单元的详细信息,从而节省了大量的CPU周期。 ,当你需要更新一个单元时(你已经意识到它将非常昂贵),并节省大量的API调用。此外,如果每个User对象只需要一个Unit实体的引用而不是持有,它将使用更少的磁盘空间所有细节本身。 (当然这取决于你需要存储的每个单元的信息量,但你确实提到最终你会为每个单元存储大量的统计数据)

如果您有单独的单位表,它还可以让您更灵活地保持用户对象。您可以只获得一个单位参考列表,而不是每个单元都需要特定字段。这样,如果添加单位类型,则无需修改用户类型。

答案 1 :(得分:1)

您应该为您的单位创建独立模型。 “虽然单个实体或实体组对其更新速度有限制,但App Engine擅长处理分布在不同实体上的许多并行请求,我们可以通过使用分片来利用这一点。” Have a look at this article。它可能很有用。

答案 2 :(得分:0)

根据彼得的想法,我提出了以下修订后的用户模型。你们的人怎么想?

class Unit(db.Model):
  name = db.StringProperty()
  attack = db.IntegerProperty()

#initialize 4 different types of units
Unit(key_name="infantry",name="Infantry",attack=10).put()
Unit(key_name="rocketmen",name="Rocketmen",attack=20).put()
Unit(key_name="grenadiers",name="Grenadiers",attack=30).put()
Unit(key_name="engineers",name="Engineers",attack=40).put()

class User(db.Model):
  username = db.StringProperty()

  # eg: [10,50,100,200] -> this represents 10 infantry, 50 rocketmen, 100 grenadiers and 200 engineers
  unit_list_count = db.ListProperty(item_type=int)

  # this holds the list of key names of each unit type: ["infantry","rocketmen","grenadiers","engineers"]
  unit_list_type = db.StringListProperty()

  # total attack is not calculated inside the model. Instead, I will use a
  # controller file ( a py file ) to call the contents of unit_list_count and 
  # unit_list_type of a certain user entity, and make simple multiplications and additions to get total attack

并且是的,所有unit_types都将被memcached,以便可以检索它们以快速计算总攻击点。

希望听到大家对此的看法。