简体   繁体   English

使用并发,线程,静态变量实现GAE / Java计数器

[英]Implementing A GAE/Java Counter using Concurrency, Threads, Static variables

I've read a lot of the GAE articles on counters and this pesky write limit in GAE. 我已经阅读了很多关于计数器的GAE文章和GAE中令人讨厌的写入限制。 I've seen solutions with sharding, cron tasks, memcache, etc. Then I learned enough about java threads to be able to ask the question: 我已经看到了带有分片,cron任务,内存缓存等的解决方案。然后我学到了足够多的java线程能够提出问题:

Q: Can we implement a counter in servlet threads using concurrency / servlet static varibales? 问:我们可以使用并发/ servlet静态varibales在servlet线程中实现计数器吗?

This would have the added benefit of fewer writes to the datastore and memcache (cost the same $), and remove the cron requirement as the last servlet in a series of fast counter hits would update the datastore. 这将带来额外的好处,即减少对数据存储区和内存缓存的写入(花费相同的$),并删除cron要求,因为一系列快速计数器命中中的最后一个servlet将更新数据存储区。

I don't know enough about concurrent programming to come up with a solution, but I imagine something with static servlet variables, maybe "atomic-integers" and a last-update flag to enable checking if THIS servlet was the last servlet to update the static var, in the last 200ms, thus triggering a save to the datastore. 我不太了解并发编程以提出解决方案,但我想象一下静态servlet变量,可能是“atomic-integers”和last-update标志,以便检查这个servlet是否是最后一个更新servlet的servlet static var,在最后200ms内,从而触发对数据存储区的保存。

// Servlet gets a hit
// static var counter++
// Checks last datastore save time of the static var, if longer than 200ms
// save to datastore & save "last update time"
// If shorter than 200 ms ago, let the next servlet call update the datastore

Can this be done? 可以这样做吗? Any proposals? 有什么建议? Mucho appreciado on your thoughts. Mucho赞赏你的想法。

Just to elaborate a bit more on my comment: 只是详细说明我的评论:

As you are probably aware, App Engine spins up a new instance of your app whenever it reaches some traffic threshold. 您可能已经意识到,App Engine会在达到某个流量阈值时启动应用程序的新实例。 Given that new instances could be spun up on a completely different server, your static counter would be rendered invalid. 鉴于新实例可以在完全不同的服务器上运行,您的静态计数器将变为无效。

Now just to clarify, the correct way of implementing a counter in App Engine would be to use Sharding and split it across multiple entites. 现在只是为了澄清,在App Engine中实现计数器的正确方法是使用Sharding并将其拆分为多个entite。

Now assuming you wanted to minimize your datastore calls, you could instead use memcache to store your counter data and write it out to the datastore at a specified frequency (say via cron). 现在假设您希望最小化数据存储区调用,您可以使用memcache存储计数器数据并以指定的频率将其写入数据存储区(例如通过cron)。 Your memcache data will be consistent across all instances of your app. 您的memcache数据将在您应用的所有实例中保持一致。

You of course run the risk of losing your memcache counter in the event memcache goes down, but that's what writing it out to the datastore takes care of. 在memcache发生故障的情况下,你当然会冒失去 memcache计数器的风险,但这就是把它写到数据存储区的工作。 Again, this isn't a 100% foolproof solution, sharding is; 同样,这不是一个100%万无一失的解决方案,分片是; but it's one way of minimizing your datastore calls. 但这是最小化数据存储区调用的一种方法。

Guido van Rossum talks about this in an article on his blog. Guido van Rossum在他博客上的一篇文章中谈到了这一点。 As I understand, you're in a race condition problem. 据我了解,你处于竞争状态问题。 I don't know anything about Java. 我对Java一无所知。 But guido links to an API of Memcache service for Java in appengine. 但是guido链接到了一个用于Java的Memcache服务的API Maybe this could help you to find a solution. 也许这可以帮助您找到解决方案。

If you're counting something that's 'mission critical', don't assume that the same instance will be handling the next request, or any subsequent request. 如果您正在计算“关键任务”的内容,请不要假设同一个实例将处理下一个请求或任何后续请求。 The flip side of App Engine being able to scale quickly to handle spikes in demand is that instances go away when the spike passes. App Engine能够快速扩展以处理需求高峰的另一面是,当尖峰通过时,实例会消失。 Instances can go away for other reasons, too. 实例也可能因其他原因而消失。 Sharded counters are the way to go when the count has be to right. 当计数到右时,分片计数器是要走的路。

It's also generally a mistake to count on memcache as anything other than a cache that can have an arbitrarily shortened lifetime. 将memcache视为可以具有任意缩短的生命周期的缓存以外的其他任何东西通常也是错误的。

If an approximate count will do, then you have a few options. 如果大概数量可以做,那么你有几个选择。 You can do something like accumulate counts in memcache, sweeping the count off to the datastore every Nth hit, or you can do the same using lock-protected globals. 你可以做一些事情,比如在memcache中累积计数,每隔N次点击一次将数据清除到数据存储区,或者你可以使用受锁保护的全局变量做同样的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM