【问题标题】:Gemfire cache throwing PartionedRegionException: Object hashCode inconsistent between peersGemfire缓存抛出PartionedRegionException:对象hashCode在对等点之间不一致
【发布时间】:2019-11-28 15:30:20
【问题描述】:

当在 gemfire 中使用分区缓存并使用可缓存注释与 spring 数据集成时,它会将数据正确地放入缓存中,但是当从缓存中检索时,如果键在不同的分区上,它会抛出 PartionedRegionException 说缓存之间的 hashCode 不一致同行。我在对象是缓存键的类中重写了 equals 和 hashCode 方法。知道我哪里可能出错了吗?两个缓存对等点位于同一台机器上。并且定位器是从外部启动的。 我正在使用以下方法开始缓存。

@Bean
@Primary 
Cache getGemfireCache() {
Cache cache = new CacheFactory().create();
RegionFactory<Object,Object> regionFactory = cache.createRegionFactory(RegionShortcut.PARTITION);
allCacheNames.forEach(cacheName -> regionFactory.create(cacheName));
return cache;
} 

任何帮助将不胜感激。

谢谢!

【问题讨论】:

    标签: caching gemfire spring-data-gemfire


    【解决方案1】:

    嗯。

    首先,很难准确描述您遇到了什么问题,但我几乎可以肯定它与 Spring Data 或技术上的 Spring's Cache Abstraction 在这种情况下几乎没有关系(尤其是因为您使用 @Cacheable 注释提到“缓存”),而不是说 Pivotal GemFire 本身,或者更可能在您的应用程序域模型中。

    其次,您遇到的问题与上面显示的配置关系不大。本质上,在您的配置中,您正在为应用程序服务方法上声明的@Cacheable 注释中标识的每个缓存创建一个“对等”Cache 实例以及Regions,这在这种情况下并不是特别有趣。


    提示:关于配置,最好这样做:

    @SpringBootApplication
    @EnableCachingDefinedRegions
    public class MyCachingSpringBootApplication { ... }
    

    有关详细信息,请参阅 hereherehere

    注意:SBDG 默认创建 ClientCache 实例,不是“对等”Cache 实例。如果您确实希望您的 Spring 应用程序包含一个嵌入式对等点 Cache 实例并成为服务器集群的一部分,那么您还可以通过声明@PeerCacheApplication 注释。有关详细信息,请参阅here


    接下来,您提到您“覆盖”了 equalshashCode,这似乎表明您正在使用一些复杂的密钥。一般来说,使用 Pivotal GemFire 时最好保留简单的键类型,例如 LongIntegerString 等,原因类似于您遇到的情况。

    如果您需要影响整个集群的分区策略或数据组织(例如,可能是为了搭配),一个更好的选择是实施 GemFire 的 PartitionResolver 并将其注册到 PR。

    但是,您的可缓存服务方法如下所示并不少见:

    @Cacheable("CustomersByAccount")
    Account findBy(Customer customer) { ... }
    

    你可能很清楚,上面显示的@Cacheable“findBy”服务方法的“key”是Customer,这显然是一个复杂的对象,必须有一个有效的equalshashCode方法当用作 GemFire 缓存区域中的键,用于备份应用程序缓存“CustomersByAccount”。

    几个问题:

    1. 是否有可能 A) 您的复杂键的类定义(例如 Customer)已更改,例如通过添加/删除 [new] 字段或更改字段类型 (?) 和 B) 您的支持缓存的分区区域(例如“CustomersByAccount”)是持久的?

    2. 您的equalshashCode 方法是否一致?那就是他们声明并使用相同的字段来确定equalshashCode的结果?

    例如,这将是无效的:

    class Customer {
    
      private Long id;
    
      private String firstName;
      private String lastName;
    
      ...
    
      @Override
      public boolean equals(Object obj) {
    
        if (this == obj) {
          return true;
        }
    
        if (!(obj instanceof Customer)) {
          return false;
        }
    
        Customer that = (Customer) obj;
    
        return this.id.equals(that.id);
      }
    
      @Override
      public int hashCode() {
    
        int hashValue = 17;
    
        hashValue = 37 * hashValue + this.firstName.hashCode();
        hashValue = 37 * hashValue + this.lastName.hashCode();
    
        return hashValue;
      }
    
      ...
    }
    

    或任何其他组合,其中equals/hashCode 可能会根据先前存储在 GemFire 中的状态产生不同的结果。

    您也可以尝试清除缓存并重新补水(根据需要急切地或懒惰地),特别是如果您的类定义已更改,尤其是如果其中一些类类型用作键。

    另外,一般来说,如果无法严格遵守简单/标量类型(例如LongString),我会尽可能推荐不可变键。 也许,如果您可以在您的应用程序域模型类中分享更多细节,例如用作键的类型,以及您在服务方法上使用 Spring 的缓存抽象,这可能会有所帮助。

    此外,非常感谢任何重现该问题的示例或测试用例。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      • 1970-01-01
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多