我希望在azure表存储中实现页面视图计数器。如果说两个用户同时访问该页面,并且PageViews = 100上的当前值,是否保证更新操作后PageViews = 102?
答案 0 :(得分:23)
答案取决于您如何实施计数器。 : - )
表存储没有“增量”运算符,因此您需要读取当前值(100)并将其更新为新值(101)。表存储采用乐观并发,因此如果您在使用.NET存储客户端库时自然而然地做到了这一点,那么当两个进程同时尝试执行此操作时,您可能会看到异常。这将是流程:
收到错误时,显而易见的事情是重复此过程。 (读取当前值,现在为101,并更新为102.)这将始终(最终)导致您的计数器具有正确的值。
还有其他可能性,我们完成了关于如何实现真正可扩展的计数器的整个云封面集:http://channel9.msdn.com/Shows/Cloud+Cover/Cloud-Cover-Episode-43-Scalable-Counters-with-Windows-Azure。
如果不太可能发生碰撞,该视频中描述的内容可能过度。即,如果您的命中率是每秒一次,那么正常的“读取,增量,写入”模式将是安全有效的。另一方面,如果你每秒收到1000次点击,你会想要做一些更聪明的事情。
修改强>
只是想澄清那些阅读此内容以理解乐观并发性的人......条件操作并非真正“将PageViews设置为101,只要它当前为100”。它更像是“将PageViews设置为101,只要它自上次查看它以来没有改变。” (这是通过使用HTTP请求中返回的ETag来完成的。)
答案 1 :(得分:9)
您还可以重新考虑“计数”部分。为什么不把它变成两步过程?
第1步 - 录制网页浏览量
每次有人查看页面时都会向表中添加一条记录(让我们称之为PageViews)。您将在其中一个商店中添加的信息如下:
在几次观看之后你会有这样的事情:
第2步 - 计算网页浏览量
我们现在要做的是获取所有这些记录,计算它们,在某处增加一个计数器并删除所有记录。假设您有多个工作人员正在运行。你的工人都会有一个随机运行1到10分钟的循环。每次工作人员的时间过去,如果尚未进行任何租约,则需要租用blob(这应该始终是相同的blob,您可以使用AutoRenewLease)。
获得锁定的第一个工人可以继续进行计数:
这里的问题是很难将其变成幂等的过程。如果您的实例在计数和删除之间崩溃会发生什么?您的页面数量会增加,但由于这些项目未被删除,因此下次处理时它们会被添加到总计数中。
这就是我建议如下的原因。在同一表(PageViews)中,您还将在同一分区中记录总页面视图。但数据会有所不同(这将是该分区中包含总计数的单个记录):
这是完全可能的,因为表存储模式较少。为什么我们这样做?因为我们确实有交易,如果我们将自己限制在最多100个实体的同一个表+分区。我们能做些什么?
每隔X分钟,你的工人会看到blob上是否有租约,获得租约并重新启动流程。
这个答案是否足够清楚,还是应该添加一些代码?
答案 2 :(得分:1)
我提出了同样的问题。使用Azure python库,我正在使用eTag
和If-Match
而不是锁来开发一个简单的计数器增量。基本思路是重试增加计数器,直到更新在某个条件下成功运行,这是其他更新不会干扰此运行更新。如果更新请求很重,则应调用分片。
https://github.com/flyakite/simple-scalable-datastore/blob/master/datastore/azuretable.py
答案 3 :(得分:1)
如果使用Azure网站,则Azure Queues和WebJobs是另一种选择。 在我的一个场景中,虽然我实际上将采用分片方法并让WebJobs定期更新聚合。 UserPageViews的Azure表存储表,其中PartitionKey = User和RowKey = Page。将不允许具有相同用户ID的两个同时用户。