캐시 분해 방지와 Go의 singleflight 사용
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
웹 개발
대상자
고성능 서비스 개발자, Go 언어 사용자, 고并发 환경에서 캐시 최적화를 고려하는 개발자
핵심 요약
- 캐시 분해(cache breakdown)는 고并发 시 핫키의 만료로 인해 데이터베이스 과부하를 유발하는 문제로,
singleflight
패키지가 이를 방지함 singleflight.Group.Do
메서드는 동일한 키에 대한 요청을 한 번만 실행하여 다중 요청을 하나로 통합Group
구조체는 요청을 관리하고,DoChan
은 비동기 결과 처리를 지원하며,Forget
은 캐시 결과를 강제로 삭제
섹션별 세부 요약
1. 캐시 분해 문제와 일반적인 해결 방법
- 캐시 분해는 핫키 만료 시 다수의 요청이 데이터베이스에 동시에 접근하여 발생
- 일반적인 해결 방법:
- 핫 데이터의 만료 시간을 무한으로 설정
- 뮤텍스 잠금을 통해 한 번에 하나의 요청만 처리
- 백그라운드에서 캐시 업데이트
2. `singleflight` 패키지 구성 요소
- Group: 동일한 키의 요청을 통합 관리하는 핵심 구조체
- Do 메서드: 동일한 키의 요청이 있을 경우 하나의 요청만 실행하고 나머지 요청은 결과를 공유
- 리턴 값:
(result, error, shared)
- DoChan: 비동기 결과 처리를 위한 채널 리턴
- Forget: 특정 키의 요청 기록을 삭제하여 새 요청을 강제로 생성
3. `singleflight` 예제 사용
Do
메서드를 사용하여 캐시 미스 시 데이터베이스 조회 수행- 5개의 goroutine이 동일한 키를 요청해도 한 번만 실행되고 결과가 공유됨
- 예제 코드:
```go
v, err, shared := sg.Do("key", fetchData)
```
- 결과:
shared: true
로 모든 요청이 동일한 결과를 공유
4. 키 설계와 타임아웃 처리
- 키의 유니크성과 일관성 보장:
{type}:{identifier}
형식 사용 (예:user:1234
) - 타임아웃 관리:
DoChan
과select
문을 통해 시간 초과 시 대체 전략 실행
```go
select {
case <-doChan:
fmt.Println("done")
case <-time.After(2 * time.Second):
fmt.Println("timeout")
}
```
결론
singleflight
는 고并发 환경에서 캐시 분해를 효과적으로 방지하여 데이터베이스 부하를 줄이고 성능을 개선합니다. 키의 일관성 유지와 타임아웃 처리 전략을 적용하여 시스템의 반응성을 높이는 것이 중요합니다.