如何确保对 ext. 系统的并行查询只执行一次,然后缓存



服务器框架: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解决方案。

处理天气请求的控制器执行以下操作:

  1. 查询数据库以获取天气数据。如果没有数据过期的位置,请立即回复。否则继续:
  2. 开始收听一个主题(稍后解释)。
  3. 对于每个位置:检查该位置的天气是否未更新。
  4. 如果没有,则向队列发送天气更新请求消息。
    1. 一定数量的工人(50?)听这个队列。
    2. 工作人员首先将位置天气标记为正在更新
    3. 工作人员检索更新的天气并更新数据库。
    4. 工作人员向包含该位置的天气数据的主题发送消息。
  5. 当控制器收到(通过主题)所有过期位置的天气更新时,将其与最新位置合并并回复。

最新更新