Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
50
Help us understand the problem. What is going on with this article?

More than 5 years have passed since last update.

@yosisa

groupcache‎ で組み込み型分散キャッシュ

groupcache‎ は Go で書かれた分散キャッシュライブラリで、複数プロセスでキャッシュを共有するプログラムが簡単に書けます。多くの用途で memcached を置き換えることを目指していて、Google のプロダクション環境で使われているようです。

個人的に groupcache の魅力は、

  • キャッシュを複数のピアに分散する (sharding)
  • キャッシュに無いデータを同時に大量にリクエストしても、キャッシュ生成処理は1度だけ実行され、他のリクエストには生成されたキャッシュを返す(厳密では無いが、だいたいの場合1度きり)
  • 頻繁にリクエストされるデータがリモートにあった場合、ローカルにもキャッシュする

一方、注意しないといけない点はキャッシュのアップデートには対応していないことです。groupcache には expire や明示的な破棄は存在しません。あるキーに対する値は 常に同じ であることが要求されます。

サンプル

サンプルコードがほとんどなくて、groupcache の使い方が分かりにくかったのでサンプルを貼っておきます。このサンプルではピアと通信するのに http を使いますが、フロントとはポートを分けておきたかったので martini とは別で動かしています。

package main

import (
    "encoding/json"
    "github.com/codegangsta/martini"
    "github.com/golang/groupcache"
    "net/http"
    "os"
    "time"
)

func main() {
    addr := os.Getenv("GROUPCACHE_ADDR")
    peers := groupcache.NewHTTPPool("http://" + addr)
    peers.Set("http://127.0.0.1:8000", "http://127.0.0.1:8001")
    go http.ListenAndServe(addr, peers)
    heavy := groupcache.NewGroup("heavy", 64<<20, groupcache.GetterFunc(heavyTask))

    m := martini.Classic()
    m.Get("/_stats", func() []byte {
        v, err := json.Marshal(&heavy.Stats)
        if err != nil {
            panic(err)
        }
        return v
    })
    m.Get("/:key", func(params martini.Params) string {
        var result string
        if err := heavy.Get(nil, params["key"], groupcache.StringSink(&result)); err != nil {
            panic(err)
        }
        return result
    })
    m.Run()
}

func heavyTask(ctx groupcache.Context, key string, dst groupcache.Sink) error {
    time.Sleep(400 * time.Millisecond)
    dst.SetString("Value of " + key)
    return nil
}

実行

上記のコードを main.go というファイル名で保存したら、端末を2つ開いて以下のように実行します。

$ GROUPCACHE_ADDR=127.0.0.1:8000 go run main.go
$ GROUPCACHE_ADDR=127.0.0.1:8001 PORT=3001 go run main.go

3つ目を開いて curl で試すと、キャッシュされているのが分かると思います。

$ curl localhost:3000/foo  # 400ms
$ curl localhost:3001/foo  # <1ms

また、http://localhost:3000/_stats にアクセスすると統計情報が JSON で取れます。

課題

groupcache にはピアの自動更新機能はありません。そのため、うまく使うにはピアの管理がポイントになります。

orchestration ツールと組み合わせるか、memberlistetcd と組み合わせて使うとよさそうです。

参考

50
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
50
Help us understand the problem. What is going on with this article?