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.togle
# 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

위의 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(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 방식은 적재된 데이터를 확인하는 방법이 따로 없는 듯 하다. (2022년 구버전 기준)
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가 저장되는 시점에 저장된다.
