我正在使用Hibernate二级缓存(使用spring配置)使用Hazelcast,而第一台服务器将驱逐邮件发送到第二台服务器。第二台服务器上的驱逐时间戳包括实际驱逐时间+ 1小时。
这会导致第二台服务器丢失其缓存并在下一个小时内向DB运行查询,或者直到本地缓存(来自第二台服务器)被驱逐。
在查看版本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实际上被添加到逐出消息时间戳,导致有问题的缓存时间戳
我错过了什么或者实际的逻辑是非常有问题的吗? 有没有人真正拥有使用hibernate第二级实现按预期工作的分布式服务器的工作配置?
答案 0 :(得分: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设置为的错误状态(未来时间+缓存超时设置) ,导致受影响的空间上的所有查询在达到该时间之前不是最新的。