我正在尝试实施蒙德里安SegmentCache
。缓存将由运行Mondrian库的多个JVM共享。我们使用Redis作为后备存储,但是出于这个问题的目的,任何持久的键值存储都应该没问题。
stackoverflow社区是否有助于完成此实施?文档和Google搜索没有产生足够的细节。我们走了:
new SegmentCache {
private val logger = Logger("my-segment-cache")
import logger._
import com.redis.serialization.Parse
import Parse.Implicits.parseByteArray
private def redis = new RedisClient("localhost", 6379)
def get(header: SegmentHeader): SegmentBody = {
val result = redis.get[Array[Byte]](header.getUniqueID) map { bytes ⇒
val st = new ByteArrayInputStream(bytes)
val o = new ObjectInputStream(st)
o.readObject.asInstanceOf[SegmentBody]
}
info(s"cache get\nHEADER $header\nRESULT $result")
result.orNull
}
def getSegmentHeaders: util.List[SegmentHeader] = ???
def put(header: SegmentHeader, body: SegmentBody): Boolean = {
info(s"cache put\nHEADER $header\nBODY $body")
val s = new ByteArrayOutputStream
val o = new ObjectOutputStream(s)
o.writeObject(body)
redis.set(header.getUniqueID, s.toByteArray)
true
}
def remove(header: SegmentHeader): Boolean = ???
def tearDown() {}
def addListener(listener: SegmentCacheListener) {}
def removeListener(listener: SegmentCacheListener) {}
def supportsRichIndex(): Boolean = true
}
一些直接的问题:
SegmentHeader.getUniqueID
在缓存中使用的适当密钥吗?getSegmentHeaders
?上面的当前实现只会引发异常,并且似乎没有被Mondrian调用。我们如何让SegmentCache在启动时重用现有的缓存记录?addListener
和removeListener
?我假设它们与协调共享缓存的节点之间的缓存更改有关。但是怎么样?supportsRichIndex
应该返回什么?一般来说,实施SegmentCache
的人如何知道要返回什么值?我觉得这些是文档中应该涵盖的基本问题,但它们不是(据我所知)。也许我们可以在这里纠正缺乏可用信息。谢谢!
答案 0 :(得分:2)
是SegmentHeader.getUniqueID在缓存中使用的适当密钥吗?
是和否。 UUID在memcached等系统上非常方便,其中所有内容都归结为键/值匹配。如果使用UUID,则需要将supportsRichIndex()实现为false。原因是被排除的区域不是UUID的一部分。这是有充分理由的设计。
我们推荐的是一个序列化SegmentHeader的实现(它实现了Serializable和hashCode()& equals())并直接将它作为传播的二进制密钥使用,以便它保留无效区域并保留所有内容很好地同步。
您应该看看我们是如何在default memory cache中实现它的。
还有implementation using Hazelcast。
我们Pentaho也使用Infinispan取得了巨大的成功。
应该如何实现getSegmentHeaders?
再次,看一下默认的内存实现。您只需返回所有当前已知的SegmentHeader列表。如果由于某种原因无法提供该列表,或者因为您仅使用了UUID,或者因为您的存储后端不支持获取列表(如memcached),则返回一个空列表。 Mondrian将无法使用内存汇总,并且无法共享段,除非它在缓存中命中正确的UUID。
如何使用addListener和removeListener?
当新元素出现在缓存中时,需要通知Mondrian。这些可以由其他节点创建。 Mondrian维护了它应该知道的所有段的索引(从而启用了内存操作),因此这是一种传播更新的方法。您需要在此处与Mondrian实例桥接后端。看看how the Hazelcast implementation does it。
这背后的想法是Mondrian维护当前已知单元格的空间索引,并且只有在绝对需要的情况下才会查询SQL中必需/缺失的单元格。这对于实现更高的可伸缩性是必要的。与我们在内存数据网格中维护的对象相比,从SQL中获取单元格的速度非常慢。
我们如何让SegmentCache在启动时重用现有的缓存记录
这是一个警告。目前,这可以通过应用this patch来实现。它没有移植到主代码行,因为它是一个混乱,并与另一个案例的修复纠缠在一起。据报道它可以工作,但我们没有在内部进行测试。相关的code is about here。如果你开始测试这个,我们总是欢迎捐款。如果您对mailing list感兴趣,请告诉我们。有很多人乐意帮忙。
一种解决方法是在缓存实现开始时通过侦听器更新本地索引。