Нестабильность кэша второго уровня в Hibernate

В нашем проекте мы используем hazelcast 3.6.5 в качестве второго (lvl) кэша hibernate (4.3.11).

Вот тест, который описывает проблему, с которой мы сталкиваемся:

@Test
public void cacheTest() {

    // Step 1: create account with someValue=111
    Account account = account().withName("test hz account").withSomeValue(111).build();
    account = restClient.upsertAccount(account);

    //Step 2: create user with ref to account
    User user = user().withAccount(account).build();
    restClient.upsertUser(user);

    //Step 3: update account someValue to 222
    account.setSomeValue(222);
    restClient.upsertAccount(account);

    //search users by account id
    List<User> users = restClient.searchUsersByAccountId(BRAND, account.getId());

    assertThat(users.size(), is(1));
    //assertion below fails, user.account.someValue=111
    assertThat(users.get(0).getAccount().getSomeValue(), is(222));
}

Тест запускается на приложении с двумя узлами. Вот как запросы сбалансированы для разных узлов:

узел1:

172.20.0.1 - - [12:30:46 +0200] "POST /accounts/BRAND/ HTTP/1.1" 200 321
172.20.0.1 - - [12:30:47 +0200] "POST /accounts/BRAND/ HTTP/1.1" 200 321

узел2:

172.20.0.1 - - [12:30:47 +0200] "POST /users/BRAND/ HTTP/1.1" 200 542
172.20.0.1 - - [12:30:48 +0200] "POST /users/BRAND/search?start=0&limit=1 HTTP/1.1" 200 617

Я обнаружил, что в кэше Hazelcast 2-го уровня содержатся два экземпляра одного аккаунта Один со старым значением поля 111 и один со новым 222.

Первый экземпляр добавляется в кэш при первой вставке учетной записи, а второй - при вставке пользователя (у нас есть учетная запись get call при вставке пользователя). Как я понимаю, эти два экземпляра учетной записи в кеше вызывают несогласованность.

Любые идеи, почему это могло произойти и как отладить эту проблему?

Вот модель данных:

@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "accounts")
@Cache(usage = READ_WRITE)
public class Account extends BrandIdEntity {
     @Column(name = "name")
     private String name;

     @Column(name = "some_value")
     private Integer someValue;
}

@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "users")
@Cache(usage = READ_WRITE)
public class User extends BrandIdEntity {

    @Column(name = "account_id")
    private String accountId;

    @ManyToOne(cascade = ALL)
    @JoinColumns({
        @JoinColumn(name = "brand", nullable = false, insertable = false, updatable = false),
        @JoinColumn(name = "account_id", nullable = false, insertable = false, updatable = false) })
    private Account account;
}

@EqualsAndHashCode(of = "pk", callSuper = false)
@MappedSuperclass
public abstract class BrandIdEntity extends AuditedEntity<BrandIdPK> {

    @EmbeddedId
    private final BrandIdPK pk;

    public BrandIdEntity() {
        super();
        pk = new BrandIdPK();
    }

    public BrandIdEntity(BrandType brand, String id, IdGenType idGenType) {
        super();
        pk = new BrandIdPK(brand, id, idGenType);
    }
}

@Embeddable
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class BrandIdPK extends BaseObject {

    @Column(name = "id")
    private String id;

    @Column(name = "brand")
    private String brand;

    public BrandIdPK(BrandType brand, String id, IdGenType idGenType) {
        this.brand = brand.name();
        if (id != null) {
            this.id = id;
        }
        else {
            this.id = next(idGenType);
        }
    }
}

и вот конфиг карты фундука:

{
   name='com.project.data.Account',
   inMemoryFormat='BINARY',
   backupCount=1,
   asyncBackupCount=0,
   timeToLiveSeconds=300,
   maxIdleSeconds=0,
   evictionPolicy='LRU',
   evictionPercentage=25,
   minEvictionCheckMillis=100,
   maxSizeConfig=MaxSizeConfig{maxSizePolicy='PER_NODE',size=100000},
   readBackupData=true,
   hotRestart=HotRestartConfig{enabled=false,fsync=false},
   nearCacheConfig=null,
   mapStoreConfig=MapStoreConfig{
      enabled=false,className='null',factoryClassName='null',writeDelaySeconds=0,writeBatchSize=1,
      implementation=null,factoryImplementation=null,properties={},
      readOnly=null,initialLoadMode=LAZY,writeCoalescing=true
   },
   mergePolicyConfig='com.hazelcast.map.merge.PutIfAbsentMapMergePolicy',
   wanReplicationRef=null,
   entryListenerConfigs=[],
   mapIndexConfigs=[],
   mapAttributeConfigs=[],
   quorumName=null,
   queryCacheConfigs=[],
   cacheDeserializedValues=INDEX_ONLY
}

0 ответов

Другие вопросы по тегам