안녕하세요. 어제 비가와서 그런지 오늘은 추워서 반팔만 입기 너무 춥네요.
저번 시간에는 캐시와 CDN 캐시에 대해서 학습해봤습니다. 이번 시간에는 서버 사이드 캐시, 그 중 Redis에 대해서 자세히 학습해보도록 하겠습니다.
앞선 글에서는 CDN 캐시처럼 사용자와 가까운 위치에서 정적 리소스를 재사용하는 방식에 대해 알아보았습니다.
이번 글에서는 서버 내부 또는 서버와 가까운 캐시 저장소를 활용해 DB 조회 결과나 API 응답을 재사용하는 서버 사이드 캐시에 대해 정리해봅시다.
서버 사이드 캐시
서버 사이드 캐시(Server-side Caching)는 클라이언트가 아닌 서버 측에서 데이터를 임시로 저장해두고 재사용하는 캐시 방식입니다.
CDN 캐시가 이미지, CSS, JavaScript와 같은 정적 리소스를 사용자와 가까운 CDN 서버에 저장해두는 방식이었다면,
서버 사이드 캐시는 애플리케이션 서버나 Redis 같은 캐시 저장소에 DB 조회 결과, API 응답, 세션 정보 등을 저장해두는 방식입니다.
예를 들어, 사용자가 인기 게시글 목록을 요청할 때 마다 매번 DB를 조회하면 서버와 데이터베이스에 부하가 발생할 수 있습니다. 이때 인기 게시글 목록을 서버 사이드 캐시에 저장해두면, 이후 동일한 요청에서는 DB를 다시 조회하지 않고 캐시된 데이터를 반환할 수 있습니다.
서버 사이드 캐시는 언제 사용할까?
서버 사이드 캐시는 모든 데이터에 적용하는 것이 아닌 반복적으로 조회되지만 자주 변경되지 않는 데이터에 적용할 때 효과적입니다.
캐시는 데이터를 임시로 저장해두고 재사용하는 구조이기에 자주 변경되는 데이터나 항상 최신 상태가 유지되어야하는 데이터에는 신중하게 사용해야 합니다. 반대로 여러 사용자가 반복적으로 요청하고, 조회 비용이 크며, 일정 시간 동안 동일한 결과를 사용해도 괜찮은 데이터라면 서버 사이드 캐시를 적용하기 좋습니다.
대표적인 예로는 일기 게시글 목록, 상품 목록, 카테고리 정보, 랭킹 데이터, 공지사항, 메인 페이지에 노출되는 데이터 등이 있습니다. 이러한 데이터는 여러 사용자가 반복적으로 조회하는 경우가 많기 때문에 매번 DB를 조회하는 것보다 캐시에 저장해두고 재사용하는 것이 효율적입니다.
다만 사용자마다 결과가 달라지는 데이터에는 주의해야 합니다.
예를 들어 마이페이지 정보, 장바구니, 결제 내역, 주문 상태처럼 개인별로 다르거나 즉시 최신 상태가 중요한 데이터는 무조건 캐싱하기보다 데이터 특성에 맞게 신중하게 적용해야 합니다.
즉, 서버 사이드 캐시는 "자주 조회되지만 자주 변경되지 않는 데이터"와 "DB 조회 비용이 큰 데이터"에 적용할 때 효과적입니다.
그렇다면 서버 사이드 캐시를 구현할 때는 어떤 저장소를 사용할 수 있을까요?
서버 내부 메모리를 사용할 수도 있지만, 여러 서버 인스턴스에서 캐시를 공유하거나 만료 시간을 관리하기 위해 Redis와 같은 외부 캐시 저장소를 사용하는 경우가 많습니다.
Redis
Redis(REmote DIctionaty Server)는 메모리 기반의 Key-Value 저장소입니다.
일반적인 관계형 데이터베이스가 데이터를 디스크에 저장하고 테이블 구조를 중심으로 관리한다면, Redis는 데이터를 메모리에 저자하고 Key-Value 형태로 빠르게 조회할 수 있도록 제공합니다.
* Key-Value 구조란?
하나의 Key에 하나의 value를 연결해 저장하는 방식을 말합니다.
예를 들어 'popular:posts'라는 key에 인기 게시글 목록을 저장해두고, 이후 같은 key로 데이터를 빠르게 조회할 수 있습니다.
Redis는 메모리 기반으로 동작하기 때문에 디스크 기반 데이터베이스보다 빠른 읽기와 쓰기가 가능합니다. 이러한 특징 때문에 Redis는 캐시 저장소로 자주 사용됩니다.
또한 Redis는 단순히 문자열을 저장하는 것이 아니라 List, Set, Sorted Set, Hash와 같은 다양한 자료구조를 지원합니다.
그렇기에 단순 캐시뿐 아니라 세션 저장소, 랭킹 데이터, 실시간 카운터, 작업 큐 등 여러 용도로 활용될 수 있습니다.
다만 이번 글에서는 Redis를 깊게 다루기보다 서버 사이드 캐시 관점에서 Redis가 왜 자주 사용되는지에 초점을 맞춰 정리하겠습니다.
그렇다면 여러 저장소 중에서 Redis는 왜 서버 사이드 캐시로 자주 사용될까요?
Redis를 캐시로 사용하는 이유
Redis가 서버 사이드 캐시로 자주 사용되는 가장 큰 이유는 메모리 기반으로 동작하기 때문에 데이터 접근 속도가 빠르기 때문입니다.
일반적인 데이터베이스는 데이터를 디스크에 저장하고 조회합니다. 반면 Redis는 데이터를 메모리에 저장하기 때문에 반복적으로 조회되는 데이터를 빠르게 가져올 수 있습니다. 따라서 매번 DB를 조회하지 않고 Redis에 저장된 데이터를 먼저 확인하면 응답 시간을 줄일 수 있습니다.
또한 Redis는 Key-Value 구조를 사용하기 때문에 특정 key를 기준으로 데이터를 단순하고 빠르게 조회할 수 있습니다.
Redis는 TTL(Time To Live)을 설정할 수 있다는 점에서도 캐시 저장소로 적합합니다.
* TTL(Time To Live) : 캐시 데이터를 일정 시간이 지나면 자동으로 만료시키는 기능입니다.
캐시는 영구 저장이 목적이 아니라 일정 시간 동안 데이터를 재사용하기 위한 구조이기 때문에 만료 시간을 설정할 수 있는 기능이 중요합니다.
또한 Redis는 애플리케이션 서버 외부에 위치한 캐시 저장소로 사용할 수 있습니다. 서버 내부 메모리에 캐시를 저장하면 서버 인스턴스가 여러 개일 때 캐시 데이턱 서로 달라질 수 있습니다. 반면 Redis를 별도의 캐시 저장소로 두면 여러 서버가 같은 캐시 데이터를 공유할 수 있습니다.
예를 들어 서버가 2대 이상 운영되는 환경에서 A 서버가 캐시에 저장한 데이터를 B 서버도 사용할 수 있습니다. 이처럼 Redis는 여러 버서 인스턴스가 공통으로 접근할 수 있는 중앙 캐시 저장소 역할을 할 수 있습니다.
즉, Redis는 빠른 데이터 접근 속도, 단순한 Key-Value 구조, TTL 지원, 여러 서버 간 캐시 공유가 가능하다는 점 때문에 서버 사이드 캐시로 자주 사용됩니다.
그렇다면 Redis를 사용해 어떤 데이터를 캐싱할 수 있을까요?
서버 사이드 캐시에서 가장 흔하게 볼 수 있는 방식 중 하나는 DB 조회 결과를 Redis에 저장해두고 재사용하는 것입니다.
DB 조회 결과 캐싱
서버 사이드 캐시에서 자주 사용되는 방식 중 하나는 DB 조회 결과를 캐시에 저장해두고 재사용하는 것 입니다.
일반적으로 사용자의 요청이 들어오면 서버는 필요한 데이터를 가져오기 위해 DB를 조회합니다. 하지만 같은 데이터가 반복적으로 요청된다면 매번 DB를 조회하는 것은 비효율적일 수 있습니다.
이때 조회 결과 Redis에 저장해두면 이후 동일한 요청에서는 DB를 다시 조회하지 않고 Redis에 저장된 데이터를 반환할 수 있습니다.
예를 들어 인기 게시글 목록을 조회하는 기능을 생각해봅시다.
인기 게시글 목록은 여러 사용자가 요청할 가능성이 높습니다. 이 데이터를 요청할 때마다 DB에서 조회하면 트래픽이 많아질수록 DB 부하도 함께 증가합니다.
이때 처음 요청에서는 DB에서 인기 게시글 목록을 조회하고, 조회한 결과를 Redis에 저장합니다. 이후 같은 요청이 들어오면 서버는 먼저 Redis에 저장된 데이터가 있는지 확인하고
- 데이터가 있다면 → DB에 조회하지 않고 Redis의 데이터를 반환합니다.
- 데이터가 없으면 → DB를 조회한 다음 해당 데이터를 반환합니다.
즉, Redis를 활하여 DB 조회 결과를 캐싱하면 반복적인 DB 접근을 줄일 수 있고, 응답 속도도 개선할 수 있습니다.
특히 자주 변경되지 않는 데이터일수록 캐싱 효과가 더욱 커집니다.
예를 들어 인기 게시글 목록이 1분 동안 1,000번 요청된다고 가정해보겠습니다.
캐시를 사용하지 않는다면 1,000번의 요청마다 DB 조회가 발생합니다.
하지만 Redis에 조회 결과를 1분 동안 캐싱해둘 경우, 첫번째 요청에서만 DB를 조회하고 이후 999번의 요청은 Redis에서 데이터를 반환할 수 있습니다.
즉, 동일한 시간 동안 DB 조회 횟수를 1,000번에서 1번 수준으로 줄일 수 있습니다.
이처럼 DB 조회 결과 캐싱은 반복 조회가 많은 기능에서 DB 부하를 줄이는데 효과적입니다.
다만 DB 조회 결과를 캐싱할 때는 데이터가 변경되었을 때 Redis에 저장된 캐시를 어떻게 갱신하거나 삭제할지도 함께 고려해야 합니다.
TTL
DB 조회 결과를 Redis에 저장해두면 반복적인 DB 접근을 줄일 수 있습니다. 하지만 캐시 데이터가 계속 남아 있다면 원본 데이터가 변경되었을 때 오래된 데이터를 반환할 수 있습니다.
이러한 문제를 줄이기 위해 캐시 데이터에는 만료 시간을 설정할 수 있습니다. 이때 사용하는 개념이 TTL 입니다.
TTL(Time To Live)은 캐시 데이터가 얼마나 오래 유지될지를 정하는 시간입니다.
예를 들어 인기 게시글 목록을 Redis에 저장하면서 TTL 1분으로 설정하면 해당 데이터는 1분 동안만 캐시에 남아 있습니다. 1분이 지나면 Redis에서 자동 만료되고, 이후 같은 요청이 들어왔을 때는 다시 DB를 조회하여 새로운 데이터를 가져오게 됩니다.
다만 TTL을 너무 짧게 설정하면 캐시가 자주 만료되어 DB 조회가 다시 늘어날 수 있습니다. 반대로 TTL을 너무 길게 설정하면 오래된 데이터가 사용자에게 전달될 가능성이 커집니다.
따라서 TTL은 데이터의 변경 빈도와 최신성이 얼마나 중요한지에 따라 적절하게 설정해야 합니다.
하지만 TTL만으로 모든 문제를 해결할 수 있는 것은 아닙니다.
원본 데이터가 변경되었는데 TTL이 아직 남아 있다면, 캐시에는 여전히 이전 데이터가 남아 있을 수 있습니다.
이런 경우에는 캐시를 직접 삭제하거나 갱신하는 캐시 무효화가 필요합니다.
캐시 무효화
TTL을 설정하면 캐시 데이터가 일정 시간이 지난 뒤 자동으로 만료되도록 할 수 있습니다. 하지만 TTL만으로 모든 캐시 문제를 해결할 수 있는 것은 아닙니다.
예를 들어 인기 게시글 목록의 TTL을 10분으로 설정했습니다. 하지만 캐시가 저장된 지 2분 만에 게시글의 좋아요 수나 조회수가 크게 변경되었다면, 남은 8분 동안 사용자는 이전 데이터를 전달 받을 수 있습니다.
이처럼 원본 데이터가 변경되었는데 캐시에 이전 데이터가 남아 있을 경우에는 해당 캐시를 삭제하거나 갱신해야 합니다. 이를 캐시 무효화라고 합니다.
캐시 무효화는 더 이상 유효하지 않은 캐시 데이터를 제거하여 다음 요청에서 새로운 데이터를 다시 조회하도록 만드는 과정입니다.
예를 들어 게시글이 수정되었을 때 해당 게시글 상세 조회 캐시를 삭제할 수 있습니다. 그러면 다음 사용자가 같은 게시글을 요청했을 때 Redis에 기존 캐식 없기 때문에 DB를 다시 조회하고, 최신 데이터를 다시 캐시에 저장할 수 있습니다.
캐시 무효화는 보통 아래와 같은 상황에서 필요합니다.
- 원본 데이터가 수정되었을 때
- 게시글 제목이나 내용이 수정되었다면 기존 게시글 상세 조회 캐시는 더 이상 최신 데이터가 아닐 수 있기에 해당 게시글 캐시를 삭제하거나 갱신해야 합니다.
- 원본 데이터가 삭제되었을 때
- DB에서 데이터가 삭제되었는데 캐시에는 이전 데이터가 남아 있을 경우 사용자는 삭제된 데이터를 계속 볼 수 있습니다. 따라서 삭제 작업이 발생하면 관련 캐시도 함께 제거해야 합니다.
- 데이터가 자주 바뀌는 경우
- 좋아요 수, 재고 수량, 예약 가능 여부처럼 상태가 자주 바뀌는 데이터는 캐시를 오래 유지하면 실제 데이터와 차이가 커질 수 있습니다. 이런 데이터는 TTL을 짧게 설정하거나 변경 시점에서 캐시를 무효화하는 방식이 필요합니다.
즉, 캐시 무효화는 캐시 데이터와 원본 데이터 사이의 불일치를 줄이기 위한 중요한 과정입니다. 그렇기에 캐시를 저장하는 것보다 언제 삭제하고 갱신할지를 정하는 것이 더 어렵습니다.
그렇다면 실제 서비스에서는 캐시 조회, DB 조회, 캐시 저장 과정을 어떤 흐름으로 구성할 수 있을까요?
서버 사이드 캐시에서 자주 사용되는 방식 중 하나가 Cache Aside 패턴입니다.
캐시 데이터 패턴
cache Aside 패턴
Cache Aside 패턴은 애플리케이션이 캐시와 DB를 직접 제어하는 방식입니다.
요청이 들어오면 먼저 Redis오 같은 캐시 저장소를 확인하고,캐시에 데이터가 있으면 캐시 데이터를 반환합니다. 반대로 캐시에 데이터가 없다면 DB를 조회한 뒤, 조회 결과를 캐시에 저장하고 사용자에게 응답합니다.
즉, 캐시는 DB 옆에 두고 필요할 때 애플리케이션이 직접 확인하고 채워 넣는 구조입니다.
동작 흐름
- 사용자가 데이터를 요청합니다.
- 애플리케이션은 먼저 캐시를 확인합니다.
- 캐시에 데이터가 있으면 캐시 데이터를 반환합니다.
- 캐시에 데이터가 없으면 DB를 조회합니다.
- DB 조회 결과를 캐시에 저장합니다.
- 사용자에게 데이터를 응답합니다.
Cache Aside 패턴은 서버 사이드 캐시에서 가장 자주 사용되는 방식 중 하나입니다. 특히 인기 게시글 목록, 상품 목록, 카테고리 정보, 공지사항처럼 자주 조회되지만 자주 변경되지 않는 데이터를 캐싱할 때 많이 사용됩니다.
이 방식은 필요한 데이터만 캐시에 저장할 수 있습니다. 모든 데이터를 미리 캐싱하는 것이 아니라, 실제 요청이 들어온 데이터만 캐시에 저장하기 때문에 캐시 저자 공간을 비교적 효율적으로 사용할 수 있다는 장점이 존재합니다.
다만 캐시에 데이터가 없는 첫 요청에서는 무조건 DB 조회가 발생합니다. 또한 DB 데이터가 변경되었을 때 관련 캐시를 삭제하거나 갱신하지 않으면 오래된 데이터가 반환될 수 있기에 TTL과 캐시 무효화 전략을 함께 고려해야 합니다.
| 캐시 패턴 | 동작 방식 | 주로 사용하는 상황 | 장점 | 주의점 |
| Cache Aside | 애플리케이션이 먼저 캐시를 확인하고, 없으면 DB 조회 후 캐시에 저장 | 자주 조회되지만 자주 변경되지 않는 데이터 | 필요한 데이터만 캐싱할 수 있고 구조가 단순함 | 첫 요청은 DB 조회가 필요하며, 데이터 변경 시 캐시 무효화가 필요함 |
| Rea Through | 애플리케이션은 캐시에만 요청하고, 캐시가 DB 조회까지 대신 처리 | 캐시 계층이 데이터 로딩을 담당하는 구조 | 애플리케이션 로직이 단순해짐 | 캐시 시스템 의존도가 높아짐 |
| Write Through | 데이터를 쓸 때 캐시와 DB에 동시에 저장 | 쓰기 이후 바로 최신 캐시가 필요한 경우 | 캐시와 DB의 일관성을 비교적 유지하기 쉬움 | 쓰기 작업이 느려질 수 있음 |
| Write Back | 먼저 캐시를 쓰고, DB에는 나중에 반영 | 쓰기 성능이 중요한 경우 | 쓰기 응답 속도가 빠름 | 장애 발생 시 DB에 반영되지 않은 데이터 손실 위험이 있음 |
| Write Around | 데이터를 쓸 때 DB에만 저장하고, 캐시는 읽기 요청 시 채움 | 한 번 쓰이고 자주 읽히지 않는 데이터 | 불필요한 캐시 저장을 줄일 수 있음 | 첫 읽기 요청은 캐시 미스로 DB 조회가 필요함 |
이 중 일반적인 서버 사이드 캐시에서는 Cache Aside 패턴이 많이 사용됩니다.
애플리케이션 코드에서 캐시 조회, DB 조회, 캐시 저장 흐르믈 직접 제어할 수 있고, Redis와 함께 적용하기도 비교적 단순하기 때문입니다. 하지만 상황에 따라서 적절한 캐시 전략을 선택해야합니다.
Spring Boot에서 Redis 캐시 적용하기
1. 의존성 추가(build.gradle)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-cache' # 캐시 추상화를 사용('@Cacheable','@CacheEvict' 등)하기 위한 의존성
implementation 'org.springframework.boot:spring-boot-starter-data-redis' # Redis 연동을 위한 의존성
}
2. Redis 설정(apllication.yml)
spring:
data:
redis:
host: localhost
port: 6379
cache:
type: redis
3. 캐시 활성화(RedisApplication.java)
@SpringBootApplication
@EnableCaching
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
@EnableCaching을 통해 캐시를 활성화해준다.
4. Redis 관련 설정(RedisConfig.java)
package com.example.config;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.Map;
@Configuration
public class RedisConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
// Redis에 저장되는 key를 문자열 형태로 직렬화합니다.
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())
)
// Redis에 저장되는 value를 JSON 형태로 직렬화합니다.
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())
)
// 기본 캐시 TTL을 10분으로 설정합니다.
// 별도 설정이 없는 캐시는 10분 동안 유지됩니다.
.entryTtl(Duration.ofMinutes(10))
// 조회 결과가 null인 경우에는 캐시에 저장하지 않습니다.
.disableCachingNullValues();
Map<String, RedisCacheConfiguration> cacheConfigurations = Map.of(
// popularPosts 캐시는 1분 동안만 유지합니다.
"popularPosts", defaultConfig.entryTtl(Duration.ofMinutes(1)),
// categories 캐시는 1시간 동안 유지합니다.
"categories", defaultConfig.entryTtl(Duration.ofHours(1))
);
return RedisCacheManager.RedisCacheManagerBuilder
// RedisConnectionFactory를 기반으로 RedisCacheManager를 생성합니다.
.fromConnectionFactory(factory)
// 위에서 정의한 기본 캐시 설정을 적용합니다.
.cacheDefaults(defaultConfig)
// 캐시 이름별로 다른 설정을 적용합니다.
.withInitialCacheConfigurations(cacheConfigurations)
.build();
}
}
5. Service 로직
package com.example.post.service;
import com.example.demo.post.dto.PostResponse;
import com.example.demo.post.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PostService {
private final PostRepository postRepository;
@Cacheable(value = "popularPosts", key = "'main'")
public List<PostResponse> getPopularPosts() {
return postRepository.findPopularPosts()
.stream()
.map(PostResponse::from)
.toList();
}
@Transactional
@CacheEvict(value = "popularPosts", key = "'main'")
public void updatePost(Long postId, PostUpdateRequest request) {
// 게시글 수정 로직
// post.update(request.getTitle(), request.getContent());
}
}
'getPopularPosts()'가 처음 호출되면 Redis에 캐시 데이터가 없기 때문에 DB를 조회합니다. 그리고 조회 결과가 'popularPosts::main'과 같은 캐시 key로 저장됩니다.
이후 같은 key로 다시 요청이 들어오면 메서드 내부의 DB 조회 로직을 실행하지 않고 Redis에 저장된 캐시 데이터를 반환합니다.
반대로 게시글이 수정되어 인기 게시글 목록에 영향을 줄 수 있다면 @CacheEvict를 사용해 기존 캐시를 삭제할 수 있습니다.
이후 기존과 동일하게 Controller를 작성하고 API를 호출하면, Service 메서드에 @Cacheable로 인해 Spring은 메서드를 실행하기 전에 Redis 캐시에 데이터가 있는지 먼저 확인합니다.
캐시에 데이터가 없다면 DB를 조회하고 그 결과를 Redis에 저장합니다. 반대로 캐시로 데이터가 있다면 DB를 조회하지 않고 Redis에 저장된 데이터를 반환합니다.
따라서 사용자 API를 호출하는 방식은 동일하지만 서버 내부에서는 캐시 확인 → DB 조회 여부 → 캐시 저장 또는 반환의 흐름이 추가됩니다.
주의점 : 데이터 정합성, 캐시 스탬피드
Redis를 서버 사이드 캐시로 사용하면 반복적인 DB 조회를 줄이고 응답 속도를 개선할 수 있습니다. 하지만 캐시는 원본 데이터를 대신 임시로 저장해두는 구조이기에 몇 가지 주의할 점이 있습니다.
- 데이터 정합성 문제
- DB의 원본 데이터가 변경되었는데 Redis에 이전 데이터가 남아 있다면 사용자는 최신 데이터가 아닌 오래된 데이터를 전달 받을 수 있습니다.
- 예를 들어 게시글 내용이 수정되었는데 게시글 상세 조회 캐시가 그대로 남아 있다면 사용자는 수정 전 내용을 볼 수 있습니다.
- 해당 문제를 해결하기 위해 TTL을 설정하거나, 데이터 수정•삭제 시점에 관련 캐시를 함께 삭제해야 하는 캐시 무효화 전략이 필요합니다.
- 캐시 스탬피드(Cache Stampede)문제
- 캐시 스탬피드는 특정 캐시가 만료되는 순간 많은 요청이 동시에 DB로 몰리는 현상을 말합니다.
- 예를 들어 인기 게시글 목록 캐시가 만료된 직후 많은 사용자가 동시에 같은 API를 요청하면 Redis에는 데이터가 없기 때문에 여러 요청이 한꺼번에 DB를 조회하게 됩니다.
- 해당 문제를 줄이기 위해서는 TTL을 너무 동일한 시점에 몰리지 않게 설정하거나, 캐시 갱신 중에는 하나의 요청만 DB를 조회하도록 제어하는 방식 등을 고려할 수 있습니다.
오늘은 서버 사이드 캐시와 Redis에 대해서 학습해보았습니다. 그동안 성능 개선을 고민했던 경험은 N+1 문제 해결이나 동시성 제어처럼 주로 DB 조회 구조와 데이터 정합성에 가까운 부분이었습니다. 이번에 Redis를 학습하면서 반복적으로 조회되는 데이터를 캐싱하여 DB 부하를 줄이는 방식도 성능 개선의 중요한 방법일는 점을 알 수 있었습니다.
특히 추후 프로젝트를 리팩토링하는 과정에서 자주 조회되지만 자주 변경되지 않는 데이터에 Redis 캐시를 적용해본다면 좋은 트러블슈팅 경험이 될 것 같습니다.
다음 시간에는 클라이언트 사이드 캐시에 대해 알아보겠습니다. 수고하셨습니다.
'백엔드 공부' 카테고리의 다른 글
| 웹 보안 지식(1) - 웹 보안은 왜 필요한가? (0) | 2026.05.06 |
|---|---|
| 캐시(3) - 클라이언트 사이드 캐시 : 브라우저 캐시와 저장소 (0) | 2026.05.04 |
| 캐시(1) - 캐시와 CDN 캐시 (0) | 2026.04.27 |
| API(5) - 오픈 API 명세와 Swagger (0) | 2026.04.24 |
| API(4) - gRPC에 대하여 (1) | 2026.04.23 |