TimeMachine 도메인 캐싱 전략
개요
이 문서는 TimeMachine 도메인에서 Redis를 활용한 캐싱 전략을 설명합니다. 전체 캐싱 아키텍처와 설계 원칙은 Redis 캐싱 설계 가이드를 참조하세요.
캐싱 대상
TimeMachine 도메인에서는 다음 데이터를 캐싱 대상으로 합니다:
- 사용자별 시간 오프셋: 사용자가 설정한 시간 조정값
- 시간 컨텍스트 설정: 사용자별 시간 관련 설정
- 시간 참조 데이터: 타임라인, 캘린더 등의 관련 데이터
캐싱 전략
1. 캐싱 패턴
TimeMachine 도메인은 Cache-Aside 패턴을 주로 사용합니다:
@Injectable()
export class TimeContextService {
constructor(
private readonly redisService: RedisService,
private readonly timeContextRepository: TimeContextRepository
) {}
async getTimeContext(userId: string): Promise<TimeContext | null> {
const cacheKey = `time:context:${userId}`;
// 캐시에서 시간 컨텍스트 조회
const cachedContext = await this.redisService.get<TimeContext>(cacheKey);
if (cachedContext) {
return cachedContext;
}
// DB에서 조회
const context = await this.timeContextRepository.findByUserId(userId);
if (!context) {
return null;
}
// 캐시에 저장 (24시간 유효)
await this.redisService.set(cacheKey, context, 86400);
return context;
}
async updateTimeContext(userId: string, context: TimeContext): Promise<void> {
// DB 업데이트
await this.timeContextRepository.save(context);
// 캐시 업데이트
const cacheKey = `time:context:${userId}`;
await this.redisService.set(cacheKey, context, 86400);
}
}
2. 키 구조
TimeMachine 도메인의 캐시 키는 다음 구조를 따릅니다:
time:context:{userId} - 사용자의 시간 컨텍스트 설정
time:offset:{userId} - 사용자의 시간 오프셋 값
time:references:{userId}:{refType} - 시간 참조 데이터
3. TTL 설정
| 데이터 유형 | TTL | 설명 |
|---|---|---|
| 시간 컨텍스트 | 86400초 (24시간) | 사용자의 시간 설정은 자주 변경되지 않음 |
| 시간 오프셋 | 43200초 (12시간) | 사용자의 시간 오프셋 값 |
| 참조 데이터 | 3600초 (1시간) | 타임라인, 캘린더 등의 참조 데이터 |
구현 예시
시간 오프셋 관리
@Injectable()
export class TimeOffsetService {
constructor(private readonly redisService: RedisService) {}
async getTimeOffset(userId: string): Promise<number> {
const cacheKey = `time:offset:${userId}`;
const offset = await this.redisService.get(cacheKey);
// 기본값은 0 (오프셋 없음)
return offset ? parseInt(offset, 10) : 0;
}
async setTimeOffset(userId: string, offset: number): Promise<void> {
const cacheKey = `time:offset:${userId}`;
await this.redisService.set(cacheKey, offset.toString(), 43200);
}
async resetTimeOffset(userId: string): Promise<void> {
const cacheKey = `time:offset:${userId}`;
await this.redisService.del(cacheKey);
}
}
타임라인 데이터 캐싱
@Injectable()
export class TimelineService {
constructor(
private readonly redisService: RedisService,
private readonly timelineRepository: TimelineRepository
) {}
async getUserTimeline(userId: string, refType: string): Promise<TimelineData> {
const cacheKey = `time:references:${userId}:${refType}`;
// 캐시에서 조회
const cachedData = await this.redisService.get<TimelineData>(cacheKey);
if (cachedData) {
return cachedData;
}
// DB에서 조회
const timelineData = await this.timelineRepository.findUserTimeline(userId, refType);
// 캐시에 저장 (1시간)
await this.redisService.set(cacheKey, timelineData, 3600);
return timelineData;
}
async updateTimeline(userId: string, refType: string, data: TimelineData): Promise<void> {
// DB 업데이트
await this.timelineRepository.saveTimeline(userId, refType, data);
// 캐시 업데이트
const cacheKey = `time:references:${userId}:${refType}`;
await this.redisService.set(cacheKey, data, 3600);
}
}
성능 최적화
- 최소 데이터 저장: 필요한 필드만 캐싱하여 메모리 사용량 최적화
- 압축 활용: 대용량 타임라인 데이터의 경우 압축 알고리즘 사용
- 느슨한 일관성: 시간 설정과 같이 자주 접근하지만 실시간성이 덜 중요한 데이터는 긴 TTL 설정
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-04-08 | bok@weltcorp.com | 최초 작성 |
| 0.1.1 | 2025-04-08 | bok@weltcorp.com | 문서 위치 변경 (core-domains → supporting-domains) |