【发布时间】:2010-10-28 01:08:27
【问题描述】:
我们有一个缓慢的后端服务器,它被负载压垮了,我们希望中间层的 Scala 服务器对于每个独特的查找只有一个未完成的后端请求。
后端服务器只存储不可变的数据,但在添加新数据时,中间层服务器将代表客户端请求最新数据,后端服务器难以承受负载。不可变数据使用写入时生成的唯一键缓存在 memcached 中,但写入速率很高,因此我们得到的 memcached 命中率较低。
我的一个想法是使用 Google Guava 的 MapMaker#makeComputingMap() 来包装实际查找,在 ConcurrentMap#get() 返回后,中间层将保存结果并从 Map 中删除键。
这似乎有点浪费,虽然代码很容易写,看下面的例子我在想什么。
是否有更自然的数据结构、库或 Guava 的一部分可以解决这个问题?
import com.google.common.collect.MapMaker
object Test
{
val computer: com.google.common.base.Function[Int,Long] =
{
new com.google.common.base.Function[Int,Long] {
override
def apply(i: Int): Long =
{
val l = System.currentTimeMillis + i
System.err.println("For " + i + " returning " + l)
Thread.sleep(2000)
l
}
}
}
val map =
{
new MapMaker().makeComputingMap[Int,Long](computer)
}
def get(k: Int): Long =
{
val l = map.get(k)
map.remove(k)
l
}
def main(args: Array[String]): Unit =
{
val t1 = new Thread() {
override def run(): Unit =
{
System.err.println(get(123))
}
}
val t2 = new Thread() {
override def run(): Unit =
{
System.err.println(get(123))
}
}
t1.start()
t2.start()
t1.join()
t2.join()
System.err.println(get(123))
}
}
【问题讨论】:
-
在地图上调用#remove() 后,避免代码似乎不起作用。请参阅code.google.com/p/guava-libraries/issues/detail?id=462 获取同时显示计算函数中的多个线程的示例代码。接下来将尝试过期和/或弱密钥。
-
我使用 MapMaker#expiration(1, TimeUnit.NANOSECONDS) 让代码工作。我一次在计算函数中观察到的线程不超过一个。
标签: java scala concurrency rpc guava