개발/Go

[Gin] GORM + Redis 캐싱 전략 - DB 부하 줄이는 실전 캐싱

devhooney 2025. 6. 16. 07:45
728x90

 

DB 부하를 Redis로 덜어주는 실전 패턴

 

 

 

✅ 왜 캐싱이 중요한가?


- 자주 조회되는 데이터를 매번 DB에서 가져오면 성능에 큰 부담
- GORM만 사용하면 매 요청마다 쿼리 발생
- Redis를 캐시로 두면 응답 속도 향상 + DB 부하 감소

 

 

 

 

 

🧱 기본 구조

 

Client → Gin → Service
                 ├── Redis 캐시 hit → 바로 응답
                 └── miss → GORM → DB → 캐시 저장 → 응답

 

 

 

🧪 실습 전제

 

- Gin + GORM + Redis 사용
- User 모델 조회 예시
- Redis는 go-redis 사용

 

 

1. Redis 설정

import (
    "github.com/redis/go-redis/v9"
    "context"
)

var ctx = context.Background()

var rdb = redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    Password: "", // no password set
    DB: 0,        // use default DB
})

 

 


 

 

2. GORM 모델

type User struct {
    ID    uint   `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

 

 

 

 


 

3. 캐싱 로직 추가

import (
    "encoding/json"
    "fmt"
    "time"
)

// 유저 ID로 조회 (캐시 우선)
func GetUserByID(id uint) (*User, error) {
    var user User
    cacheKey := fmt.Sprintf("user:%d", id)

    // 캐시에서 시도
    val, err := rdb.Get(ctx, cacheKey).Result()
    if err == nil {
        json.Unmarshal([]byte(val), &user)
        return &user, nil
    }

    // 캐시 miss → DB에서 조회
    result := db.First(&user, id)
    if result.Error != nil {
        return nil, result.Error
    }

    // 캐시에 저장
    jsonData, _ := json.Marshal(user)
    rdb.Set(ctx, cacheKey, jsonData, time.Minute*10)

    return &user, nil
}

 

 

 


 

 

4. 캐시 무효화 전략
데이터 변경 시, 관련 캐시는 지우는 것이 핵심

func UpdateUser(id uint, newName string) error {
    result := db.Model(&User{}).Where("id = ?", id).Update("name", newName)
    if result.Error != nil {
        return result.Error
    }

    // 캐시 삭제
    cacheKey := fmt.Sprintf("user:%d", id)
    rdb.Del(ctx, cacheKey)

    return nil
}

 

 

 

 


 

5. TTL 전략 (Time To Live)
- 일반적으로는 5~30분으로 설정
- 변하지 않는 데이터는 더 길게
- 로그인 유저 등 민감한 데이터는 짧게

rdb.Set(ctx, key, value, time.Minute*10) // 10분 캐시

 

 

 

 

 


 

6. 성능 최적화 팁

전략 설명
캐시 키 네이밍 user:123, post:456처럼 prefix로 영역 분리
직렬화 json.Marshal vs gob → 속도 & 크기 트레이드오프
대량 데이터 리스트 캐싱은 주의 (페이징 별도 캐싱 고려)
캐시 무효화 데이터 변경 시 무조건 Del 먼저!
fallback 캐시 실패 시 DB fallback 필수 구현

 

 

 

 

✅ 정리


- Redis 캐시를 도입하면 GORM 성능을 수직 상승시킬 수 있음
- 캐시 히트율을 높이기 위한 TTL, 키 설계, 무효화 전략이 핵심
- 캐시만 믿지 말고 DB fallback 로직 필수

 

 

 

 

 

 

728x90