요청 실행 결과 캐싱

GolangBeginner
지금 연습하기

소개

이 프로젝트에서는 Go 의 singleflight 패키지를 기반으로 만료 시간을 지원하는 캐싱 라이브러리를 구현하는 방법을 배우게 됩니다. 이 캐싱 라이브러리는 분산 시스템에서 요청 실행 결과를 캐싱하여 애플리케이션의 성능을 향상시키는 데 사용할 수 있습니다.

👀 미리보기

$ /usr/local/go/bin/go test --race
PASS
ok      cacheflight     1.263s

🎯 과제

이 프로젝트에서는 다음을 배우게 됩니다:

  • Go 모듈을 초기화하고 필요한 패키지를 설치하는 방법
  • singleflight 패키지를 사용하여 캐싱 라이브러리를 구현하는 방법
  • 캐싱 라이브러리가 예상대로 작동하는지 테스트하는 방법

🏆 성과

이 프로젝트를 완료하면 다음을 수행할 수 있습니다:

  • 캐싱의 기본 개념과 Go 의 singleflight 패키지를 이해합니다.
  • 만료 시간을 지원하는 캐싱 라이브러리를 구현합니다.
  • 애플리케이션의 성능을 향상시키기 위해 캐싱 라이브러리를 분산 시스템에 통합합니다.

모듈 초기화 및 필수 패키지 설치

이 단계에서는 모듈을 초기화하고 프로젝트에 필요한 패키지를 설치하는 방법을 배우게 됩니다.

  1. /home/labex/project 디렉토리에서 터미널을 엽니다.

  2. 다음 명령을 사용하여 모듈을 초기화합니다:

    /usr/local/go/bin/go mod init cacheflight
    
  3. 다음 명령을 사용하여 필수 패키지를 설치합니다:

    /usr/local/go/bin/go get github.com/golang/groupcache/singleflight
    /usr/local/go/bin/go get github.com/stretchr/testify/assert
    

캐싱 라이브러리 구현

이 단계에서는 singleflight 패키지를 기반으로 캐싱 라이브러리를 구현합니다.

  1. /home/labex/project 디렉토리에서 cacheflight.go 파일을 엽니다.

  2. import에 필요한 내용을 추가합니다.

    import (
        "sync"
        "time"
    
        "github.com/golang/groupcache/singleflight"
    )
    
  3. type Grouptype cacheResult에 필요한 내용을 추가합니다.

    // cacheResult is cache result
    type cacheResult struct {
        data      interface{} // the cache data
        ctime     time.Time   // cache create time
        isRunning chan bool   // is the function running
    }
    
    // Group is core struct
    type Group struct {
        cacheExpiration time.Duration          // cache expiration
        sfg             *singleflight.Group    // singleflight group
        cache           map[string]cacheResult // cache result
        mu              sync.Mutex             // mutex
    }
    
  4. 지정된 캐시 만료 시간을 가진 새로운 캐싱 그룹을 반환하는 NewGroup 함수를 구현합니다.

    func NewGroup(cacheExpiration time.Duration) (group *Group) {
        group = &Group{
            sfg:             &singleflight.Group{},
            cache:           make(map[string]cacheResult),
            cacheExpiration: cacheExpiration,
        }
        return
    }
    
  5. 캐싱 로직을 처리하는 do 함수를 구현합니다.

    func (g *Group) do(key string, fn func() (interface{}, error)) (ret interface{}, err error) {
        return g.sfg.Do(key, func() (interface{}, error) {
            g.mu.Lock()
            result, ok := g.cache[key]
            if result.isRunning != nil {
                g.mu.Unlock()
                // wait for fn done
                <-result.isRunning
                return g.do(key, fn)
            } else if !ok || result.ctime.Add(g.cacheExpiration).Before(time.Now()) {
                // if the cache is not exist or expired
                var run = make(chan bool)
                result.isRunning = run
                g.cache[key] = result
                // when fn done and close run channel, let other goroutine can get the cache
                defer close(run)
            } else {
                // if the cache is exist and not expired
                g.mu.Unlock()
                return result.data, nil
            }
    
            g.mu.Unlock()
    
            // different key can run at the same time
            ret, err = fn()
            if err != nil {
                return ret, nil
            }
    
            result = cacheResult{
                data:  ret,
                ctime: time.Now(),
            }
            g.mu.Lock()
            g.cache[key] = result
            g.mu.Unlock()
    
            return ret, nil
        })
    }
    
  6. do 함수를 래핑하는 Do 함수를 구현합니다.

    func (g *Group) Do(key string, fn func() (interface{}, error)) (ret interface{}, err error) {
        return g.do(key, fn)
    }
    

캐싱 라이브러리 테스트

이 단계에서는 캐싱 라이브러리가 예상대로 작동하는지 확인하기 위해 테스트합니다.

  1. /home/labex/project 디렉토리에서 터미널을 엽니다.

  2. 다음 명령을 실행하여 테스트를 실행합니다:

    cd /home/labex/project
    /usr/local/go/bin/go test --race
    
  3. 캐시 함수가 올바르게 구현되었다면 다음과 같은 출력을 볼 수 있습니다:

    PASS
    ok      cacheflight     1.263s
    
  4. 타임아웃 오류가 발생하면 터미널에서 다음 명령을 실행한 다음, 다시 검사 버튼을 클릭하여 검사를 통과하십시오:

    cd /home/labex/project
    /usr/local/go/bin/go test --race
    

축하합니다! singleflight 패키지를 기반으로 캐싱 라이브러리를 성공적으로 구현했습니다. 이제 이 라이브러리를 분산 시스템에서 사용하여 요청의 실행 결과를 캐싱하고 애플리케이션의 성능을 향상시킬 수 있습니다.

요약

축하합니다! 이 프로젝트를 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.

✨ 솔루션 확인 및 연습✨ 솔루션 확인 및 연습✨ 솔루션 확인 및 연습