[Cache] 1,2nd level Cache, Query Cache, Hazelcast 및 모니터링 설명

application.yaml 테스트 설정

spring:
  jpa:
    database-platform: org.hibernate.dialect.MySQL5Dialect
    generate-ddl: true
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
        cache:
          use_query_cache: true # Query Cache 테스트를 위한 설정
          use_minimal_puts: true
          # 2nd level cache 테스트를 위한 Hazelcast 설정
          use_second_level_cache: true
          region.factory_class: com.hazelcast.hibernate.HazelcastLocalCacheRegionFactory
          hazelcast:
            use_native_client: true
            native_client_address: 192.168.0.32:5701
            native_client_group: order
            user_code_packages: com.kmmoon
            
# Cache를 사용중인지 확인하기 위한 로깅 레벨 설정
# 기본 설정으로는 로그가 확인되지 않는다
logging:
  level:
    org.hibernate: trace
    hibernate.cache: trace

1nd level cache

@Cacheable Annotation이 달린 Entity 조회 시 Hibernate Session에 자동으로 저장된다.

사용 방법

@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Entity
public class PersonTest implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue
  private Integer id;
  private String firstName;
  private String lastName;
  private String pesel;
  private int age;
}

Query Cache

Hibernate Query Cache

사용 방법

@Repository
public interface PersonTestRepository extends CrudRepository<PersonTest, Integer> {
  @QueryHints(value = {
    @QueryHint(name = "org.hibernate.cacheable", value = "true"),
    @QueryHint(name = "org.hibernate.cacheRegion", value = "person-by-pesel")
  })
  List<PersonTest> findByPesel(String pesel);
}

Hibernate Session Factory에서 관리하며, HashMap으로 저장된다. org.hibernate.cache.internal.StandardQueryCache 완전 Local Cache로만 작동한다. (반환하지 않으면 Memory leak 발생하니 주의)

내부적으로 HQL을 사용해 조회하는 것을 확인할 수 있다.

Spring Cache Abstraction

사용 방법

@Repository
public interface PersonTestRepository extends CrudRepository<PersonTest, Integer> {
  @Cacheable("findByPesel")
  List<PersonTest> findByPesel(String pesel);
}

CacheManager에서 관리하는 Local Cache이며, ConcurrentHashMap으로 저장된다.

org.springframework.boot:spring-boot-starter-cache를 사용한 방식. Actuator를 통해 확인 가능하다는 것은 장점이다.

Hazelcast를 CacheManager로 사용하는 방식도 존재하지만 토글에선 해당 방식을 사용하진 않는다.

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast-all</artifactId>
    <version>4.0.2</version>
</dependency>
# hazelcast.yaml
hazelcast:
  network:
    join:
      multicast:
        enabled: true

spring-data-hazelcast를 사용한 Query Cache 방식도 있다.

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>spring-data-hazelcast</artifactId>
    <version>${version}</version>
</dependency>
@Query("firstname=James")
public List<Person> peoplewiththeirFirstNameIsJames();
@Query("firstname=%s")
public List<Person> peoplewiththeirFirstName(String firstName);
@Query("firstname=%s and lastname=%s")
public List<Person> peoplewithFirstAndLastName(String firstName,String lastName);

https://github.com/hazelcast/spring-data-hazelcast

모두 Query Cache지만 사용 방식, 아키텍처, 관리 주체가 모두 다르다.

2nd level cache

https://thoughts-on-java.org

위의 3가지 케이스는 전부 Local Cache로 관리되지만, 2nd level cache는 Local Cache, Remote Cache 두 방식으로 사용 가능하다.

여러 Application을 띄우고 로드벨런서를 앞에 두고 사용하는 경우, API Call 마다 각 Application에선 Entity를 각자 중복으로 조회하여 저장하는 형태이기 때문에, 각 Session 내부에서만 Cache를 공유하는 First Level Cache는 Hit율이 낮을 수 밖에 없다.

이 Cache를 클러스터링 하여 중앙에서 관리하는 것을 2nd Level Cache라고 한다. 방식은 Local Cache(IMDG) 방식과 Remote Cache 방식 2가지가 있다.

IMDG란?

IMDG 서비스 개념도

IMDG(In-Memory Data Grid)는 고가용성과 확장성을 제공하는 분산 메모리 시스템이다. 메모리를 주 데이터 저장소로 활용하기 위해서는 대용량 데이터 관리를 위한 신뢰성이 보장되어야 한다. 이를 위해 IMDG는 분산 클러스터 기술을 활용하고 있다. 다수의 컴퓨터 메모리를 그리드로 연결하여 하나의 큰 메모리 저장소를 구축한다. 서버를 동적으로 추가하여 용량을 증설할 수 있으며, 장애 시 자동복구를 위한 데이터가 여러 서버에 분산 관리된다.

IMDG(In-Memory Data Grid)는 다음과 같은 특징을 가진다.

  • 다수의 컴퓨터 메모리(RAM)를 클러스터링 하여 하나의 큰 메모리 저장소로 구축

  • 데이터 유실방지 및 복구를 위해 여러 서버에 데이터를 분산, 복제 관리

  • 메모리(RAM) 클러스터의 수평적 확장이 가능하여 무제한 용량 지원

  • 데이터는 객체 지향 및 비 관계형 데이터 모델로 관리

  • 사용자의 데이터 요청은 다수의 컴퓨터에서 병렬로 처리

  • 메모리(RAM) 외 디스크, DBMS 등의 저장소에서 데이터 영구 보관 가능

이름

구분

저장소

기타

Hazelcast

IMDG

In Memory

IMDG로 Invalidation Message Propagation 기능 제공

Infinispan

IMDG

In Memory

상동

Redis

NON-IMDG

In Memory

NON-IMDG로 Invalidation Message Propagation 기능 미제공

Ehcache

NON-IMDG

In Memory

상동

Ehcache + Terracotta

NON-IMDG

In Memory

Terracotta 서버 추가 구성으로 인한 부담

Local Cache + Hazelcast(IMDG)

사용방법

spring:
  jpa:
    properties:
      hibernate:
        cache:
          use_second_level_cache: true
          region.factory_class: com.hazelcast.hibernate.HazelcastLocalCacheRegionFactory

Local Cache (Near Cache)를 각 Application에 저장하며, Topic (queue)를 통해 수정된 데이터 정보를 주고 받으며 데이터 일관성을 유지하는 방식이다. 데이터를 Application에 적재하고 있으므로, Remote Cache 방식에서 발생하는 Network 지연은 발생하지 않아 가장 성능이 좋은 방식이다.

ITopic을 통해 데이터가 전송되므로 Hazelcast Management Center에선 Topic이 생성되는걸 확인할 수 있다.

Hazelcast Local Cache 방식은 적재된 데이터를 확인하는 방법이 따로 없는 듯 하다.

Hazelcast Management Center를 사용하여 Topic의 Publishes, Receives Count는 확인 가능하지만, 중요한 hit율이나 데이터 저장 정보 등 그 이상의 정보는 확인할 수 없었다.

(최신버전을 사용하면 데이터 조회, 히트율을 확인 가능하다는 제보가 있)

Remote Cache + Hazelcast

사용방법

spring:
  jpa:
    properties:
      hibernate:
        cache:
          use_second_level_cache: true
          region.factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory

일반적인 Remote Cache를 사용한 방식.

Hazelcast Remote Cache 방식도 마찬가지로 적재된 데이터를 확인하는 방법이 따로 없었다.

IMap을 통해 데이터가 전송되므로 Hazelcast Management Center에선 Map이 생성되는걸 확인할 수 있다.

하지만, Hazelcast Management Center를 사용하여 중요한 Hit율, 데이터 수, 메모리 사용량 등 중요한 정보를 확인할 수 있다.

성능은 Local Cache가 좋다고 하지만, Metric 성능은 Remote Cache 방식이 좋은 것을 확인할 수 있다.

(최신버전에선 다를 수 있음.)

1, 2nd Level Cache가 언제 저장되는지 확인하는 방법

해당 로깅 설정으로 어느 시점에 Cache가 저장되는지 확인할 수 있다.

# Cache를 사용중인지 확인하기 위한 로깅 레벨 설정
# 기본 설정으로는 로그가 확인되지 않는다
logging:
  level:
    org.hibernate: trace
    hibernate.cache: trace

사용 방식은 1nd Level Cache가 저장되는 시점에 동일하게 저장된다.

Last updated

Was this helpful?