【问题标题】:Distributed cache with hibernate 2nd level eviction具有休眠二级驱逐的分布式缓存
【发布时间】:2016-09-12 11:36:43
【问题描述】:

我正在使用休眠二级缓存(使用 spring 配置)使用 Hazelcast,而第一台服务器向第二台服务器发送驱逐消息。第二台服务器上的驱逐时间戳包括实际驱逐时间 + 1 小时。

这会导致第二台服务器丢失缓存并在接下来的一小时内或直到本地缓存(来自第二台服务器)被驱逐之前对数据库运行查询。

在查看版本 3.6.2 实现时,1 小时间隔是由于 com.hazelcast.hibernate.HazelcastTimestamper下的getTimeout函数

public static int getTimeout(HazelcastInstance instance, String regionName) {
        try {
            final MapConfig cfg = instance.getConfig().findMapConfig(regionName);
            if (cfg.getTimeToLiveSeconds() > 0) {
                // TTL in ms
                return cfg.getTimeToLiveSeconds() * SEC_TO_MS;
            }
        } catch (UnsupportedOperationException e) {
            // HazelcastInstance is instance of HazelcastClient.
            Logger.getLogger(HazelcastTimestamper.class).finest(e);
        }
        return CacheEnvironment.getDefaultCacheTimeoutInMillis();
    }

getDefaultCacheTimeoutInMillis 返回 360

而 mapConfig.getTimeToLiveSeconds() == 0

AbstractHazelcastRegion 获得超时时间

this.timeout = HazelcastTimestamper.getTimeout(instance, regionName);

在 org.hibernate.cache.spi.UpdateTimestampsCache

public void preInvalidate(Serializable[] spaces, SessionImplementor session) throws CacheException {
    final boolean stats = factory != null && factory.getStatistics().isStatisticsEnabled();

    **final Long ts = region.nextTimestamp() + region.getTimeout();**

    for ( Serializable space : spaces ) {
        if ( DEBUG_ENABLED ) {
            LOG.debugf( "Pre-invalidating space [%s], timestamp: %s", space, ts );
        }

        try {
            session.getEventListenerManager().cachePutStart();

            //put() has nowait semantics, is this really appropriate?
            //note that it needs to be async replication, never local or sync
            region.put( space, ts );
        }
        finally {
            session.getEventListenerManager().cachePutEnd();
        }

        if ( stats ) {
            factory.getStatisticsImplementor().updateTimestampsCachePut();
        }
    }
}

在驱逐消息期间,驱逐超时 = 360*1000 实际上被添加到驱逐消息时间戳中,导致缓存时间戳有问题

是我遗漏了什么还是实际逻辑非常有问题? 有没有人真正有一个使用休眠 2 级的分布式服务器的工作配置,它实际上按预期工作?

【问题讨论】:

    标签: hazelcast


    【解决方案1】:

    Hibernate 将在事务开始时调用 preInvalidate 以进行更新/插入,然后一旦事务完成,它将调用 UpdateTimestampsCache.invalidate(...)。这会将 lastUpdate 时间设置回当前时间。

    因此,在事务运行时,对受影响空间的任何查询都不会是最新的,但一旦事务结束,lastUpdate 时间将被设置,并且可以缓存未来的选择查询。

    如果您将 org.hibernate 的日志记录设置为 DEBUG,您可以在日志中观察到这一点。日志将如下所示:

    DEBUG [UpdateTimestampsCache] Pre-invalidating space [<affected query spaces>], timestamp: <approximate current time + timeout>
    ... your transaction here ...
    DEBUG [AbstractTransactionImpl] committing
    DEBUG [JdbcTransaction] committed JDBC Connection
    DEBUG [JdbcTransaction] re-enabling autocommit
    DEBUG [UpdateTimestampsCache] Invalidating space [<affected query spaces>], timestamp: <approximate current time>
    

    我观察到,如果事务未提交(可能的编码错误),有时第二个“无效空间”会失败,导致缓存处于设置 lastUpdate 的错误状态(未来时间 + 缓存超时设置) ,导致受影响空间上的所有查询在到达该时间之前都不是最新的。

    【讨论】:

      猜你喜欢
      • 2015-10-23
      • 2015-11-07
      • 2012-04-30
      • 1970-01-01
      • 2010-10-20
      • 2017-07-05
      • 2011-07-08
      • 1970-01-01
      相关资源
      最近更新 更多