scala - 使跨多个服务器的弱 HashMap 无效

标签 scala caching playframework amazon-ec2 redis

我们有一个运行在几个 EC2 实例上的 Scala Play Framework 应用程序,它在 redis 中缓存了很多案例类:如果对象在缓存中,则返回缓存的对象,否则从数据库中检索对象,放入缓存,并返回。但是,有一些对象经常被引用(例如,许多对象包含一个或多个 Location,并且大约 20% 的 Location 只是用于美国作为一个整体),因此如果我们在 Redis 缓存之上引入一个弱 HashMap ,我们就可以减少内存消耗。

object GetKey {
  def getKey(id: Int, clazz: Class[_]) = clazz.getSimpleName + ":" + id
}

abstract class Record(implicit manifest: Manifest[Record]) {
  val id: Int
  final val key = GetKey.getKey(id, manifest.getClass)
}

object LocalCache {
  private val map = new mutable.WeakHashMap[String, Record]
  def fetch[T](key: String, value: => T) = {
    map.get(key) match {
      case Some(t) => t.asInstanceOf[T]
      case _ => {
        val temp = value
        if(temp.key != key) throw new IllegalArgumentException("key mismatch")
        map.put(temp.key, temp)
        temp
}}}}

object Redis {
  def fetch[T](key: String, value: => T) = {
    this.get(key) match {
      case Some(t) => t.asInstanceOf[T]
      case _ => {
        val temp = value
        this.put(key, value)
        temp
}}}}

object RecordDAO {
  val recordClass: Class[_] // same as Record's manifest.getClass
  def getById(id: Int): Record = {
    def getFromDb(id): Record = { ... }
    def getFromRedis(key: String): Record = Redis.fetch(key, getFromDb(id))
    def getFromLocalCache(key: String): Record = LocalCache.fetch(key, getFromRedis(key))
    getFromLocalCache(GetKey.getKey(id, recordClass))  
  }
}

Redis 代码已经到位,LocalCache 代码是我们要添加的代码。所有记录类型都继承自 Record,因此 RedisLocalCache 检索 Records,然后将它们转换为适当的类型。应用首先在LocalCache中寻找一个对象;如果存在,则返回对象,否则应用程序在 Redis 中查找该对象;如果存在则返回对象,否则应用程序从数据库中检索对象。如果 Redis 和/或 LocalCache 中缺少该对象,则会添加该对象; LocalCache 使用 temp.key 将对象添加到弱 HashMap 中,这样它将保存对哈希键的字符串引用(但是,如果对象不小心被 GC那么早,这是次优的,但不会破坏任何东西。

问题是我们没有使 LocalCache 无效的好方法 - 目前如果例如美国的名称发生变化,那么我们会清除 Location来自 Redis(我们不必担心已经在内存中的 Location 对象,例如,如果 UserLocation 是美国,我们将 Location 名称更改为 USA,那么 User 仍然会看到他们在美国,直到他们得到一个新的浏览器 session ),但我们需要一种方法将缓存失效传达给所有 EC2 实例,以便它们可以从它们的 LocalCache 中删除 Location。我们可以做一些事情,比如向 Redis 中的对象添加版本号或时间戳,如果对象的版本号/时间戳不匹配,则让 LocalCache 使对象无效在 Redis 中,但这意味着我们将执行两个 Redis get 调用而不是一个。

理想情况下,我们希望在每个 EC2 实例上设置一个邮箱,我们可以将缓存失效消息传递到该邮箱。我们已经有一个用于将消息发送到 ElasticSearch 实例的 RabbitMQ 实例,但我不确定 EC2 中是否已经有用于此类事情的实用程序 - 我是 EC2 的完全新手。

让分布在多个 EC2 实例中的弱 HashMap 中的 key 失效的最佳方法是什么?

最佳答案

由于您已经在使用 RabbitMQ,我建议您使用它来尽量减少堆栈中的技术数量。

Amazon 确实有一个消息服务,简单队列服务 (SQS),但您还需要使用另一个 Amazon 服务,Simple Notification Service (SNS),以获得发布/订阅功能。请参阅常见问题解答“问:如何将相同的消息扇出到多个 SQS 队列?”在 http://aws.amazon.com/sqs/faqs/ .

关于scala - 使跨多个服务器的弱 HashMap 无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22394915/

相关文章:

linux - 在 Scala Shell 脚本中对命令使用引号

caching - 加速谷歌缓存

java - 无法从本地主机访问在 docker 内运行的 Play 框架

mongodb - Play框架中Mongo Scala Driver和Reactive-Mongo Driver有什么区别?

javascript - 设置要在 Play 中编译的 React 类

scala - (Play 2.0) 设置 AnyContent 的最大 POST 大小

scala - Zeppelin SqlContext registerTempTable 问题

scala - 如何将两个元组与兼容的类型结合起来?

c++ - C++开源缓存推荐

PHP PDO 准备语句缓存