소개
이 프로젝트에서는 Go 의 singleflight 패키지를 기반으로 만료 시간을 지원하는 캐싱 라이브러리를 구현하는 방법을 배우게 됩니다. 이 캐싱 라이브러리는 분산 시스템에서 요청 실행 결과를 캐싱하여 애플리케이션의 성능을 향상시키는 데 사용할 수 있습니다.
👀 미리보기
$ /usr/local/go/bin/go test --race
PASS
ok cacheflight 1.263s
🎯 과제
이 프로젝트에서는 다음을 배우게 됩니다:
- Go 모듈을 초기화하고 필요한 패키지를 설치하는 방법
singleflight패키지를 사용하여 캐싱 라이브러리를 구현하는 방법- 캐싱 라이브러리가 예상대로 작동하는지 테스트하는 방법
🏆 성과
이 프로젝트를 완료하면 다음을 수행할 수 있습니다:
- 캐싱의 기본 개념과 Go 의
singleflight패키지를 이해합니다. - 만료 시간을 지원하는 캐싱 라이브러리를 구현합니다.
- 애플리케이션의 성능을 향상시키기 위해 캐싱 라이브러리를 분산 시스템에 통합합니다.
모듈 초기화 및 필수 패키지 설치
이 단계에서는 모듈을 초기화하고 프로젝트에 필요한 패키지를 설치하는 방법을 배우게 됩니다.
/home/labex/project디렉토리에서 터미널을 엽니다.다음 명령을 사용하여 모듈을 초기화합니다:
/usr/local/go/bin/go mod init cacheflight다음 명령을 사용하여 필수 패키지를 설치합니다:
/usr/local/go/bin/go get github.com/golang/groupcache/singleflight /usr/local/go/bin/go get github.com/stretchr/testify/assert
캐싱 라이브러리 구현
이 단계에서는 singleflight 패키지를 기반으로 캐싱 라이브러리를 구현합니다.
/home/labex/project디렉토리에서cacheflight.go파일을 엽니다.import에 필요한 내용을 추가합니다.import ( "sync" "time" "github.com/golang/groupcache/singleflight" )type Group및type 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 }지정된 캐시 만료 시간을 가진 새로운 캐싱 그룹을 반환하는
NewGroup함수를 구현합니다.func NewGroup(cacheExpiration time.Duration) (group *Group) { group = &Group{ sfg: &singleflight.Group{}, cache: make(map[string]cacheResult), cacheExpiration: cacheExpiration, } return }캐싱 로직을 처리하는
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 }) }do함수를 래핑하는Do함수를 구현합니다.func (g *Group) Do(key string, fn func() (interface{}, error)) (ret interface{}, err error) { return g.do(key, fn) }
캐싱 라이브러리 테스트
이 단계에서는 캐싱 라이브러리가 예상대로 작동하는지 확인하기 위해 테스트합니다.
/home/labex/project디렉토리에서 터미널을 엽니다.다음 명령을 실행하여 테스트를 실행합니다:
cd /home/labex/project /usr/local/go/bin/go test --race캐시 함수가 올바르게 구현되었다면 다음과 같은 출력을 볼 수 있습니다:
PASS ok cacheflight 1.263s타임아웃 오류가 발생하면 터미널에서 다음 명령을 실행한 다음, 다시 검사 버튼을 클릭하여 검사를 통과하십시오:
cd /home/labex/project /usr/local/go/bin/go test --race
축하합니다! singleflight 패키지를 기반으로 캐싱 라이브러리를 성공적으로 구현했습니다. 이제 이 라이브러리를 분산 시스템에서 사용하여 요청의 실행 결과를 캐싱하고 애플리케이션의 성능을 향상시킬 수 있습니다.
요약
축하합니다! 이 프로젝트를 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.



