はじめに
このプロジェクトでは、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 はキャッシュ結果です type cacheResult struct { data interface{} // キャッシュデータ ctime time.Time // キャッシュ作成日時 isRunning chan bool // 関数が実行中かどうか } // Group はコア構造体です type Group struct { cacheExpiration time.Duration // キャッシュの有効期限 sfg *singleflight.Group // singleflight グループ cache map[string]cacheResult // キャッシュ結果 mu sync.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() // fnが完了するまで待つ <-result.isRunning return g.do(key, fn) } else if!ok || result.ctime.Add(g.cacheExpiration).Before(time.Now()) { // キャッシュが存在しないか、期限切れの場合 var run = make(chan bool) result.isRunning = run g.cache[key] = result // fnが完了してrunチャネルをクローズしたとき、他のgoroutineがキャッシュを取得できるようにする defer close(run) } else { // キャッシュが存在し、期限切れでない場合 g.mu.Unlock() return result.data, nil } g.mu.Unlock() // 異なるキーは同時に実行できる 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 でさらに多くの実験を行って、スキルを向上させることができます。



