캐싱의 올바른 방법: Go에서의 구현
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
DevOps
대상자
Go 백엔드 개발자, DevOps 엔지니어, 분산 시스템 설계자
난이도: 중급~고급 (캐싱 전략, LRU 구현, 분산 시스템 고려사항 포함)
핵심 요약
- 메모리 사용량 추정과 핫/콜드 데이터 분류는 캐싱 설계의 핵심
- LRU 캐시는
hashicorp/golang-lru
라이브러리에서 구현,Add
,Get
,removeOldest
메서드를 통해 관리 - 분산 캐싱은 Redis 사용 권장, 로컬 캐싱은 상태유지 시스템으로 인해 복잡성 증가
- 캐시 업데이트 전략 (cache-aside, write-through, write-back)에 따른 데이터 일관성 문제 고려
섹션별 세부 요약
1. 메모리 추정과 데이터 분류
- OOM(메모리 부족)을 방지하기 위해 캐싱 대상 데이터의 핫/콜드 데이터 분류 필요
- 콜드 데이터는 경제적인 저장소(예: 파일 시스템)로 이관 및 압축
- 분산 시스템에서 로컬 캐싱 시, Pod 간 데이터 불일치 발생 가능
2. 캐싱 전략 비교
- Redis 사용: 중앙 집중형 저장소로 모든 Pod 공유 가능
- Pod 고정 라우팅: 사용자 ID(uid)를 기반으로 요청 전달, 메모리 소비 증가
- 모든 Pod에 캐싱: 상태유지 시스템으로 인해 메모리 사용량 증가, 캐시 페니케이션 확률 감소
3. LRU 캐시 구현 (Go 기반)
- LRU 캐시는
hashicorp/golang-lru
라이브러리에서 제공 Add
메서드: 키가 존재하면 리스트 앞단으로 이동, 없으면 리스트 끝에 삽입removeOldest
메서드: 가장 오래된 요소 제거- 테스트 예시: 128개 키 제한 시, 200번 키는 캐시 유지, 1번 키는 제거
4. 분산 시스템의 캐시 업데이트 전략
- Cache-aside: 캐시 삭제 후 DB 업데이트, 일관성 문제 가능성
- Write-through: 캐시와 DB 동기 업데이트, 데이터 손실 위험 증가
- Write-back: 캐시 먼저 업데이트 후 DB 병렬 처리, ETCD 버전 번호 사용으로 데이터 오버라이드 방지
5. 고급 시나리오 및 고려사항
- ETCD 사용: 캐시 업데이트 신호 브로드캐스트, 버전 번호로 충돌 방지
- 로컬 캐싱은 일관성 요구가 낮은 경우 적합, 모든 Pod 업데이트 시 복잡성 증가
- Redis 대체: 고성능 요구 시 앱 변수 직접 캐싱 가능
결론
- LRU 캐시는
hashicorp/golang-lru
를 활용하여 메모리 제한 관리 - 분산 시스템에서는 ETCD + 버전 번호로 캐시 업데이트 충돌 방지
- 핫 데이터는 로컬 캐싱, 콜드 데이터는 경제적 저장소 활용
- 캐시 전략 선택 시 성능, 일관성, 비용을 종합적으로 고려해야 함