Ehcache, 제대로 알고 적용해보자 - 1

JUHYUN·2024년 11월 13일
1
post-thumbnail

🪃 Intro

프로젝트를 하면서 캐싱을 사용할 일이 있었습니다. OIDC 인증 과정에서 IdToken을 검증하는데 필요한 Public Key를 Oauth Provider에 요청을 자주 보내지 않도록 캐싱해야 했습니다. 이 때 Ehcache를 사용하기 위해 Ehcache의 공식문서를 읽어보았지만 생각보다 이해가 가지 않는 부분이 많았습니다. 그 이유는 제가 cache를 활용하는 전체적인 환경에서 이해해보려는 관점이 부족했기 때문입니다. 그래서 이러한 '전체적인 관점'에 대해서 이야기를 나눠볼까 합니다.

들어가기 앞서 해당 글은 Ehcache 3.X에 관하여 쓴 글임을 알려드립니다! Ehcache 2.X 이하 에서는 일부 맞지 않을 수 있습니다.

📗 Ehcache란?

Ehcache는 Java 기반의 오픈소스 캐시 라이브러리입니다. heap 뿐만 아니라 off-heap, disk 캐싱을 지원하고 TTL, TTI 등 다양한 캐시 만료 정책을 지원합니다.
Ehcache에는 이외에도 다양한 기능들을 지원하고 있는데, 이번에 제가 집중한 곳은 아래와 같습니다.

Checkout recently released Ehcache 3. It natively complies with JSR107 (JCache spec), supports offheap storage, and has many other additions and improvements.

바로 Ehcache가 JSR-107 표준을 지원한다는 것인데요. 이 부분이 어떤 의미를 가질까요? 처음에는 단순히 '아 이런 표준을 준수하나보다' 정도로 넘겼지만 구현을 하며 공부를 하다보니 훨씬 더 큰 의미가 있다는 것을 깨닫게 되었습니다.

📘 JSR-107와 JCache

JSR-107은 Java의 Cache 기능을 위한 표준 스펙입니다. 이는 Java Caching API에 대한 스펙으로 좀 더 공식적인 명칭으로 JCache 라고 불립니다. 즉 Java 의 Caching API인 JCache의 스펙을 나열한 정의한 것이 JSR-107라고 볼 수 있습니다. 표현하는 방식이 조금 다를 뿐 JSR-107과 JCache는 사실 Java Caching API 하나를 말한다고도 생각할 수 있을 것 같네요.
JCache는 캐싱을 위한 여러 인터페이스와 클래스를 표준화하여 제공합니다. JCache 자체만으로는 캐시 구현체의 역할을 하지 못하지만, Java에서 여러 캐시 구현체를 일관되게 다룰 수 있는 큰 범주의 인터페이스입니다.

💫 Core Concept

The Java Caching API defines five core interfaces: CachingProvider, CacheManager, Cache, Entry and Expiry.

JSR107 Specification 에서는 JCache의 Core Concept으로 위와 같은 5가지의 핵심 개념에 대해 설명하고 있습니다.

  • CachingProvider
    CacheProviderCacheManager에 대한 생성, 설정, 관리를 담당합니다. CacheProvider는 JSR-107을 지원하는 구현체에 따라 달라집니다. (ex.Ehcache, Hazelcast)

  • CacheManager
    CacheManagerCache에 대한 생성, 설정, 관리를 담당합니다. CacheManager는 하나의 CacheProvider에 의해서만 소유될 수 있습니다.

  • Cache
    Map과 같은 Key-based Value를 저장하는 자료구조입니다. 하나의 Cache는 하나의 CacheManager에 의해서만 소유될 수 있습니다. Cache의 이름은 CacheManager 안에서 고유해야 합니다.

  • Entry
    EntryCache에 저장되는 key-value pair 입니다.

  • Expiry
    Cache에 저장되는 Entry는 캐시의 유효기간을 뜻하는 Expiry Duration 이 정의되어 있습니다. Expiry Policy를 통해서 expiry duration을 정의할 수 있습니다.

위의 5개의 개념은 JSR-107을 지원하는 모든 캐싱 구현체에서 사용하게 될 것입니다.

🔌 Ehcache는 어떻게 JSR-107을 지원할까?

Ehcache는 JSR-107을 지원합니다. 이는 하나의 코드베이스로 다양한 캐시 구현체를 바꿔서 사용할 수 있다는 것을 뜻합니다. Hazelcast, Infinispan 등의 캐시 또한 JSR-107을 지원하기 때문에 JCache 를 사용하여 코드를 짠다면 최소한의 수정으로 캐시 교체를 해볼 수 있을 것입니다.
Ehcache는 어떠한 방식으로 JSR-107 지원을 가능하게 하는지 알아보겠습니다.

✅ CacheProvider와 CacheManager 제공

Ehcache는 JSR-107의 핵심 개념인 CachingProvider와 CacheManager의 구현체를 제공함으로써 JCache를 활용한 코드를 짤 수 있게 해줍니다. 위의 둘을 제공하기 때문에 이들이 사용하는 메서드의 파라미터 관련 인터페이스 또는 클래스에 대한 지원도 포함됩니다.

✅ Eh107Configuration

Ehcache는 JCache에 비해 off-heap storage과 같은 세밀한 캐시 제어를 위한 설정을 제공합니다. 즉, JCache에는 없는 기능인 것이죠. 그러면 어떻게 JCache와 호환이 될 수 있을까요?
그것을 가능하게 해주는 대표적인 클래스가 Eh107Configuration 입니다. 해당 클래스는 Ehcache와 JCache간의 호환성을 제공해줍니다.

  • Ehcache configuration -> JCache configuration
    해당 클래스의 기능을 통해서 Ehcache의 자체 설정인 CacheConfiguration 을 wrapping 하여 JCache의 Configuration으로 전환할 수도 있습니다.
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
    ResourcePoolsBuilder.heap(10)).build(); 

Cache<Long, String> cache = cacheManager.createCache("myCache",
    Eh107Configuration.fromEhcacheCacheConfiguration(cacheConfiguration)); 
  • JCache configuration -> Ehcache configuration
    반대 방향 또한 가능합니다. 기존에 사용되고 있는 JCache 설정을 가져와서 CacheRuntimeConfiguration 로 unwrapping을 해서 런타임에 캐시 설정을 Ehcache의 방식으로 수정할 수 있습니다.
MutableConfiguration<Long, String> configuration = new MutableConfiguration<>();
configuration.setTypes(Long.class, String.class);
Cache<Long, String> cache = cacheManager.createCache("someCache", configuration); 

CompleteConfiguration<Long, String> completeConfiguration = cache.getConfiguration(CompleteConfiguration.class); 

Eh107Configuration<Long, String> eh107Configuration = cache.getConfiguration(Eh107Configuration.class); 

CacheRuntimeConfiguration<Long, String> runtimeConfiguration = eh107Configuration.unwrap(CacheRuntimeConfiguration.class); 

🚀 Spring에서의 Caching

Spring Framework에서 Caching을 사용할 때는 위에서 봤던 개념들이 어떻게 연결될까요? 바로 Spring의 Cache Abstraction 을 통해 JCache를 사용할 수 있습니다.

  • the caching abstraction allows consistent use of various caching solutions with minimal impact on the code.
  • In Spring Framework 4.1, the cache abstraction was significantly extended with support for JSR-107 annotations and more customization options.

공식문서에서는 Cache Abstraction이 코드에 미치는 영향을 최소화 하면서 JSR-107 annotations를 지원하는 방향으로 캐싱을 지원한다고 합니다.

🙋🏻 구현은 어떻게 하실건가요?

🖋️ 중간 정리

현재까지 나온 3개의 요소, Ehcache, JCache, Spring Cache Abstraction에 대해 다시 한번 리마인드해보겠습니다.

  • Ehcache
    • Java 기반의 오픈소스 캐시 라이브러리
    • JCache spec인 JSR-107을 지원
    • 캐시의 실질적인 동작이 구현되어 있는 구현체
  • JCache
    • Java Caching API으로 캐싱을 위한 여러 인터페이스와 클래스를 표준화하여 제공
    • 구체적인 스펙인 JSR-107에 정의
  • Spring Cache Abstraction
    • 코드에 영향을 최소화하면서 다양한 캐싱 솔루션을 사용할 수 있는 캐시 추상화 제공
    • JSR-107의 표준 Caching annotation을 지원

🤔 의문점

여기까지 파악한 뒤 다음과 같은 2가지 의문이 들었습니다.

1. Ehcache는 자체로 독립적인 캐시 구현체인데 JCache, Spring Cache Abstraction이 필요할까?

실제로 Ehcache는 2.X 버전까지만 해도 JCache를 지원하지 않는 독립적인 캐시 구현체였습니다. 3.X로 업데이트가 된 지금도 캐시 동작에 JCache 의존성은 갖고 있지 않습니다. 그렇기 때문에 Ehcache의 CacheManager를 활용하여 캐시를 구현할 수 있습니다. 하지만 왜 JCache, Spring Cache Abstraction을 함께한 코드를 만들까요?

2. 각 요소들을 함께 적용할 때 필요한 설정은 무엇이 있을까?

Ehcache, JCache, Spring Cache Abstraction은 서로 간의 구현 의존성이 없습니다. 즉, A는 B를 위해서만 만들어진 관계가 아닙니다. 그렇다면 이들을 같이 사용하기 위해서는 마치 Adapter와 비슷한 역할을 하는 기능이나 설정이 필요할 것입니다. 앞서 Ehcache, JCache를 호환시켜주는 Eh107Configuration 과 같이 말이죠. 그렇다면 Spring Cache Abstraction은 어떤 설정이 필요할까요?

이에 대해서 다음편의 글로 이어서 작성해보겠습니다. 물음에 대해 간단히 답을 해보시고 보셔도 좋을 것 같습니다!


🔗 Ref

JSR107 Specification
CacheManager(JSR-107)
Ehcache Docs
Spring Cache Abstraction
JCache(JSR-107) Annotations

profile
행복과 같은 속도를 찾는 개발자

0개의 댓글