实现Mondrian共享SegmentCache

时间:2013-07-08 18:33:11

标签: scala mondrian

我正在尝试实施蒙德里安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在启动时重用现有的缓存记录?
  • 如何使用addListenerremoveListener?我假设它们与协调共享缓存的节点之间的缓存更改有关。但是怎么样?
  • supportsRichIndex应该返回什么?一般来说,实施SegmentCache的人如何知道要返回什么值?

我觉得这些是文档中应该涵盖的基本问题,但它们不是(据我所知)。也许我们可以在这里纠正缺乏可用信息。谢谢!

1 个答案:

答案 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感兴趣,请告诉我们。有很多人乐意帮忙。

一种解决方法是在缓存实现开始时通过侦听器更新本地索引。