14

这个问题涉及计数器的两种实现,它们旨在在不分片的情况下进行扩展(在某些情况下它们可能会被低估):

  1. http://appengine-cookbook.appspot.com/recipe/high-concurrency-counters-without-sharding/(评论中的代码)
  2. http://blog.notdot.net/2010/04/High-concurrency-counters-without-sharding

我的问题:

  • 关于#1:memcache.decr()在延迟的事务性任务中运行似乎有点矫枉过正。如果memcache.decr()在事务之外完成,我认为最坏的情况是事务失败并且我们错过了计算我们减少的任何内容。 我是否忽略了这样做可能会出现的其他问题?
  • 两种实现之间的重要权衡是什么?

以下是我看到的权衡:

  • 2 不需要数据存储事务。

  • 要获取计数器的值,#2 需要获取数据存储,而使用 #1通常只需要执行memcache.get()and memcache.add()
  • 当增加一个计数器时,两者都调用memcache.incr(). 定期,#2 将任务添加到任务队列,而#1 事务性地执行数据存储获取和放置。#1 也总是执行memcache.add()(以测试是否是时候将计数器持久化到数据存储区)。

结论

(没有实际运行任何性能测试):

  • 1 通常在检索计数器时应该更快(#1 memcache vs #2 datastore)。虽然 #1 也必须执行额外的操作memcache.add()

  • 但是,在更新计数器时,#2 应该更快(#1 数据存储 get+put 与 #2 使任务入队)。
  • 另一方面,对于 #1,您必须更加小心更新间隔,因为任务队列配额几乎比数据存储或 memcahce API 小 100 倍。
4

2 回答 2

1

访问数据存储可能比通过 memcache 更昂贵。否则,memcache 一开始就不会那么有用:-)

我推荐第一个选项。

如果你有一个合理的请求率,你实际上可以更简单地实现它:

1) update the value in memcache
2) if the returned updated value is evenly divisible by N
2.1) add N to the datastore counter
2.2) decrement memcache by N

这假设您可以在 memcache 上设置足够长的超时以在连续事件之间存在,但如果事件非常稀疏以至于您的 memcache 超时,您可能不需要“高并发”计数器 :-)

对于较大的站点,依靠单个内存缓存来完成诸如计算总页面点击量之类的事情可能会给您带来麻烦;在这种情况下,你真的想对你的内存缓存进行分片,并更新一个随机计数器实例;计数器的聚合将通过数据库更新发生。

但是,在使用 memcache 时,请注意某些客户端 API 会假定一秒超时意味着该值不存在。如果发送到 memcache 实例的 TCP SYN 数据包被丢弃,这意味着您的请求将错误地假定数据不存在。(使用 UDP for memcache 可能会发生类似的问题)

于 2010-06-04T23:57:20.913 回答
-2

Memcache 被刷新,你失去了你的计数器。哎哟。使用 mysql 数据库或 NOSQL 解决方案将解决可能影响性能的问题。(Redis、Tokyotyrant、MongoDB 等...)可能不会受到这种性能影响。

请记住,您可能需要执行 2 个操作:

  1. 仅出于高性能原因保留一个 memcache 计数器。
  2. 保留日志,然后从中获得更准确的指标。
于 2010-05-27T19:32:42.537 回答