2016-05-16 108 views
1

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

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

在注视版本3.6.2实施1小时的间隔是起因由于 getTimeout作用下com.hazelcast.hibernate.HazelcastTimestamper

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实际上被添加到与有问题的缓存时间戳

所得驱逐消息时戳我错过了什么或者实际的逻辑是非常有问题的? 没有人真的有分布式服务器的工作配置使用hibernate第2级,实际上按预期工作?

回答

1

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

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

如果将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设置为(未来时间+高速缓存超时设置),导致受影响空间上的所有查询都不是最新的,直到达到此时间为止。