使多个服务器上的弱哈希映射无效

时间:2014-03-14 02:15:36

标签: scala caching playframework amazon-ec2 redis

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

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检索记录,然后将它们转换为适当的类型。应用程序首先在LocalCache中查找对象;如果它存在,则返回该对象,否则应用程序在Redis中查找该对象;如果它存在,则返回该对象,否则应用程序从数据库中检索该对象。如果RedisLocalCache中缺少该对象,则会添加该对象; LocalCache使用temp.key将对象添加到弱哈希映射中,以便它保存对哈希键的字符串引用(但是如果对象意外地获得了GC,那么这就是子最佳,但不会破坏任何东西)。

问题是我们没有办法让LocalCache失效 - 目前如果美国名称发生变化,我们会从{{1}清除Location (我们不担心已经在内存中的Redis个对象,例如,如果Location User是美国,我们将Location名称更改为美国,然后Location仍会看到他们在美国获得新的浏览器会话,但我们需要一种方法来传达缓存失效到所有EC2实例,以便他们可以从User中删除Location。我们可以做一些事情,例如在LocalCache中为对象添加版本号或时间戳,如果对象的版本号/时间戳与对象的版本号/时间戳不匹配,则Redis会使对象无效在Redis中,但这意味着我们将进行两次LocalCache次来电而不是一次。

理想情况下,我们希望在每个EC2实例上设置一个邮箱,我们可以向其传递缓存失效消息。我们已经有一个RabbitMQ实例用于向ElasticSearch实例发送消息,但是我不确定EC2中是否已经有这样的实用工具 - 我是EC2的完整新手。

在多个EC2实例中散布弱哈希映射中的密钥失效的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

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

亚马逊确实拥有消息服务,简单队列服务(SQS),但您还需要使用其他亚马逊服务简单通知服务(SNS)来获取发布/订阅功能。请参阅常见问题解答"问:如何将相同的消息扇出到多个SQS队列?"在http://aws.amazon.com/sqs/faqs/