elevne's Study Note

Cache 에 대하여 본문

Backend/Java

Cache 에 대하여

elevne 2023. 3. 27. 12:37

Cache 란, 간단히 설명하자면 자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리키는 것이다. 또는 잠시 저장해둔다는 의미로 사용하기도 한다. 캐시는 저장 공간이 작고 비용이 비싸지만, 빠른 성능을 보장한다. 조금 더 구체적으로는, Cache Memory 는 메인 메모리와 CPU 간의 데이터 속도 향상을 위한 중간 버퍼 역할을 하는 CPU 내 또는 외에 존재하는 메모리이다. 

 

 

 

Cache 의 원리를 이용한 Cache 서버를 활용하여 CDN 같은 서비스에 응용해볼 수도 있다고 한다. CDN 은 컨텐츠를 딜리버리 해주는 서비스인데, 먼 곳에 있는 파일을 매번 불러오는 것은 네트워크 구간이 멀어 실패할 수도 있고 오래 걸릴 수도 있다. 여기에서, 자주 쓰는 파일들을 가까운 지역의 서버에 올려놓음으로써 빠른 접근을 가능하게끔 할 수 있는 것이다.

 

 

 

 

 

 

Cache 를 사용함으로써 DBMS 에 부하를 줄이고 메모리에 접근하여 데이터를 가져올 수 있다. 원하는 데이터가 캐시에 존재할 경우 해당 데이터를 반환하며 이러한 상황을 Cache Hit 라고 하고, 원하는 데이터가 캐시에 존재하지 않을 경우 DBMS 또는 서버에 요청을 하여 그 결과값을 반환하는데 이러한 상황을 Cache Miss 라고 한다. 또한, Cache 는 영구적인 메모리 공간에 올리는 것이 아니기에 언제든 지워질 수 있음을 염두에 두어야 한다.

 

 

 

Spring 에서는 ehcache 라는 Java 기반 오픈소스 캐시 라이브러리를 사용해볼 수 있다. redis 와 같은 캐시 엔진들도 있지만, 이와 다리 ehcache 는 데몬을 가지지 않고 Spring 내부적으로 동작하여 캐싱 처리를 한다. Redis 처럼 별도의 서버를 사용하여 생길 수 있는 네트워크 지연 등으로부터 자유롭고 사용하기 간편하다는 장점이 있다. Spring 에서 사용하기 위해 Dependency 를 pom.xml 파일에 아래와 같이 추가해준다.

 

 

 

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.9.4</version>
</dependency>

 

 

 

추가해준 뒤, 캐시를 사용하는 CacheManager 클래스를 사용할 수 있다고 한다. 아래와 같은 예제 코드로 시험해볼 수 있다.

 

 

 

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;

public class CacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
        cacheManager.init();

        Cache<String, String> myCache = cacheManager.createCache("myCache",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class,
                        ResourcePoolsBuilder.heap(100)));
    }
}

 

 

 

위 코드는 myCache 라는 이름의 캐시를 만들어 사용하며, 이는 100 개의 entry 까지 Store 할 수 있다. 이를 만들어준 뒤에는 여기에 데이터를 더하거나, 데이터를 가져오는 것이 가능해진다. 아래와 같이 사용할 수 있다.

 

 

 

myCache.put("key1", "value1");
myCache.put("key2", "value2");

String value1 = myCache.get("key1"); // returns "value1"
String value2 = myCache.get("key2"); // returns "value2"

 

 

 

위에서는 String 으로 key, value 를 세팅했지만, 직접 작성한 클래스를 아래와 같이 사용해볼 수 있다.

 

 

 

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;

public class CacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
        cacheManager.init();

        Cache<Long, User> userCache = cacheManager.createCache("userCache",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, User.class,
                        ResourcePoolsBuilder.heap(100).offheap(1, MemoryUnit.MB)));
        
        // Add users to cache
        userCache.put(1L, new User(1L, "John Doe", "john.doe@example.com"));
        userCache.put(2L, new User(2L, "Jane Doe", "jane.doe@example.com"));

        // Retrieve users from cache
        User user1 = userCache.get(1L);
        User user2 = userCache.get(2L);
    }
}

class User {
    private Long id;
    private String name;
    private String email;

    public User(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // getters and setters omitted for brevity
}

 

 

 

또, 자주 사용되는 쿼리의 결과값을 Cache 에 담아서 아래와 같이 사용해볼 수도 있다.

 

 

 

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;

public class CacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
        cacheManager.init();

        Cache<String, List<User>> queryCache = cacheManager.createCache("queryCache",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, List.class,
                        ResourcePoolsBuilder.heap(100).offheap(10, MemoryUnit.MB)));

        // Execute query and cache results
        List<User> result = executeQuery("SELECT * FROM users WHERE age > 30");
        queryCache.put("SELECT * FROM users WHERE age > 30", result);

        // Retrieve results from cache
        List<User> cachedResult = queryCache.get("SELECT * FROM users WHERE age > 30");
    }

    private static List<User> executeQuery(String query) {
        // Execute query and return result
    }
}

class User {
    private Long id;
    private String name;
    private String email;

    public User(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // getters and setters omitted for brevity
}

'Backend > Java' 카테고리의 다른 글

Thread, Future, ScheduledFuture, Runnable  (0) 2023.04.13
Java Keywords ...  (0) 2023.04.12
Java HttpServer 사용해보기  (0) 2023.02.23
Java 공부 (File 다운로드)  (0) 2023.02.16
Java의정석 공부 - (10: I/O, File)  (0) 2023.02.15