2016-05-16 107 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設置爲(未來時間+高速緩存超時設置),導致受影響空間上的所有查詢都不是最新的,直到達到此時間爲止。