服务器框架:Scala,Play 2.2,ReactiveMongo,Heroku
我想我有相当有趣的脑筋急转弯给你:
在我的旅行计划应用程序中,我想在地图上显示天气预报(与此类似)。我正在使用付费的 REST 服务来查询天气数据。为了加快用户体验并降低成本,我计划将每个位置的天气数据缓存一小时。
有一些不太明显的事情需要考虑:
- 可能需要查询多达 100 个位置的天气才能显示一个天气图
- 天气必须并行查询,因为考虑到网络延迟,以串行方式查询天气需要很长时间
- 但是,为每个用户请求启动 100 个线程也不是一种选择(想象一下一次只有 5 个用户查看地图)
- 解决方案是让 50 名工作人员查询用户请求的天气
-
多个用户可能正在查看地图的同一部分
- 可能存在一个位置被多次查询的赛车情况。
- 但是,它只应查询一次,然后缓存。
- 应用程序在群集环境中运行,这意味着将有多个播放实例。
来自Java EE背景,我可以使用Java EE堆栈想出一个非常好的解决方案。
但是,我想知道如何使用更自然的Scala/Play堆栈来做到这一点:Akka。有一个类似问题的例子(谷歌"heroku scala akka"),但它不能解决一个问题:多个用户同时查询相同数据时的赛车条件。
您将如何实现这一点?
编辑:我决定确保天气数据只更新一次的要求是没有必要的。这种情况很少发生,不可能成为一个真正的问题,所有提议的解决方案都会给系统带来太多的开销和复杂性,而无法生存。
感谢大家的时间和努力。我希望这个问题的答案能帮助将来遇到类似问题的人。
在 Akka 中,您可以从多种路由策略中进行选择。 在这种情况下,ConsistentHashingRoutingLogic
可以很好地为您服务。由于Actor是单线程的,因此您可以轻松地在每个Actor中维护缓存。此路由逻辑将确保两个相等的消息始终命中同一参与者。
每个参与者都可以通过以下方式工作:
1. check local cache (for example apache commons LRUMap)
- if found, return
2. check global cache (distributed memcache or any other key-value store)
- if found, store the result in the local cache and return
3. query the REST service
4. store the result in the global and local caches
你可以看看这个问题,我的答案是基于这个问题。
我决定也发布我的JMS解决方案。
处理天气请求的控制器执行以下操作:
- 查询数据库以获取天气数据。如果没有数据过期的位置,请立即回复。否则继续:
- 开始收听一个主题(稍后解释)。
- 对于每个位置:检查该位置的天气是否未更新。
- 如果没有,则向队列发送天气更新请求消息。
- 一定数量的工人(50?)听这个队列。
- 工作人员首先将位置天气标记为正在更新
- 工作人员检索更新的天气并更新数据库。
- 工作人员向包含该位置的天气数据的主题发送消息。
- 当控制器收到(通过主题)所有过期位置的天气更新时,将其与最新位置合并并回复。