我有一个网络应用程序,可以让用户提交博客文章。我想跟踪每个博客帖子页面的页面浏览量。所以当一些访问:
/post/123
用户的访问者应该会看到访问此页面的人数。
我想到的一个看似不可扩展的解决方案是将一个page_views属性添加到Blog类:
class Blog(ndb.Model):
title = ndb.StringProperty()
page_views = ndb.IntegerProperty()
然后,每当访问该页面时,只需blog.page_views
加1.然后blog.put()
。但是,这种尝试意味着我们会过于频繁地写入数据库。
有更好的方法吗?
答案 0 :(得分:0)
由于ndb中的一致性问题,写入数据存储区中的计数器可能非常不准确,尤其是当您的应用程序获得大量流量时。其中一个实例可能会读取当前计数1234 page_views
,然后尝试将1235写入数据存储区。但是,与此同时,其他访问者可能会来,并且他们都会看到相同的page_views
价值。另外,由于一致性,您获得的读数可能只是一分钟陈旧。所以,你的1235实际上可能是1278,甚至更大。
要避免这么多写操作,请考虑在memcache中创建计数器,然后在那里增加计数。 Memcache持续跨越实例,并且值几乎立即发生变化。然后,定期将Memcache计数转储到数据存储区,在那里递增,然后将其删除。
示例,每当访问者查看帖子,增加内存缓存计数,并在5分钟后设置延迟任务以将计数持久保存到数据存储区。这样,你可以在一个写操作中收集5分钟的观看次数。
Memcache容易出现故障,因此您的计数永远不会100%准确。但是,每5分钟左右倾倒可以减少错误。
答案 1 :(得分:0)
如果您打算使用非常准确的页面浏览计数,则必须将其保留在数据存储区中,并且您必须解决超过最大实体组写入速率的风险〜 1秒。在这种情况下,典型的方法是Sharding counters。
但是,如果您可以偶尔遗漏一些视图(恕我直言可以完全接受),您可以使用不同的策略,使用memcache存储计数器和时间戳,您可以调整,以便在数据存储区操作方面更加轻松。在每个页面视图中,您都可以调用事务功能(以防止破坏数据存储计数器值),这将是:
我选择的任务延迟值等于"最近的"之一。
通过调整"最近的"值,您可以控制更新数据存储计数器值的频率。
当您想要显示视图数量时,您只需读取数据存储区值和内存缓存值(按此顺序,以防止可能的竞争条件,其中您将对memcache计数器值进行两次计数并添加它们以获得访问次数。