- Notifications
You must be signed in to change notification settings - Fork75
Clone of golang/groupcache with TTL and Item Removal support
License
mailgun/groupcache
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A modified version ofgroup cache withsupport forcontext.Context
,go modules,and explicit key removal and expiration. See theCHANGELOG
for a complete list ofmodifications.
groupcache is a caching and cache-filling library, intended as areplacement for memcached in many cases.
For API docs and examples, seehttp://godoc.org/github.com/mailgun/groupcache/v2
Support for explicit key removal from a group.
Remove()
requests arefirst sent to the peer who owns the key, then the remove request isforwarded to every peer in the groupcache. NOTE: This is a best case designsince it is possible a temporary network disruption could occur resultingin remove requests never making it their peers. In practice this scenariois very rare and the system remains very consistent. In case of aninconsistency placing a expiration time on your values will ensure thecluster eventually becomes consistent again.Support for expired values.
SetBytes()
,SetProto()
andSetString()
nowaccept an optionaltime.Time
which represents a time in the future when thevalue will expire. If you don't want expiration, pass the zero value fortime.Time
(for instance,time.Time{}
). Expiration is handled by the LRU Cachewhen aGet()
on a key is requested. This means no network coordination ofexpired values is needed. However this does require that time on all nodes in thecluster is synchronized for consistent expiration of values.Now always populating the hotcache. A more complex algorithm is unnecessarywhen the LRU cache will ensure the most used values remain in the cache. Theevict code ensures the hotcache never overcrowds the maincache.
- shards by key to select which peer is responsible for that key
does not require running a separate set of servers, thus massivelyreducing deployment/configuration pain. groupcache is a clientlibrary as well as a server. It connects to its own peers.
comes with a cache filling mechanism. Whereas memcached just says"Sorry, cache miss", often resulting in a thundering herd ofdatabase (or whatever) loads from an unbounded number of clients(which has resulted in several fun outages), groupcache coordinatescache fills such that only one load in one process of an entirereplicated set of processes populates the cache, then multiplexesthe loaded value to all callers.
does not support versioned values. If key "foo" is value "bar",key "foo" must always be "bar".
In a nutshell, a groupcache lookup ofGet("foo") looks like:
(On machine #5 of a set of N machines running the same code)
Is the value of "foo" in local memory because it's super hot? If so, use it.
Is the value of "foo" in local memory because peer #5 (the currentpeer) is the owner of it? If so, use it.
Amongst all the peers in my set of N, am I the owner of the key"foo"? (e.g. does it consistent hash to 5?) If so, load it. Ifother callers come in, via the same process or via RPC requestsfrom peers, they block waiting for the load to finish and get thesame answer. If not, RPC to the peer that's the owner and getthe answer. If the RPC fails, just load it locally (still withlocal dup suppression).
import ("context""fmt""log""time""github.com/mailgun/groupcache/v2")funcExampleUsage() {// NOTE: It is important to pass the same peer `http://192.168.1.1:8080` to `NewHTTPPoolOpts`// which is provided to `pool.Set()` so the pool can identify which of the peers is our instance.// The pool will not operate correctly if it can't identify which peer is our instance.// Pool keeps track of peers in our cluster and identifies which peer owns a key.pool:=groupcache.NewHTTPPoolOpts("http://192.168.1.1:8080",&groupcache.HTTPPoolOptions{})// Add more peers to the cluster You MUST Ensure our instance is included in this list else// determining who owns the key accross the cluster will not be consistent, and the pool won't// be able to determine if our instance owns the key.pool.Set("http://192.168.1.1:8080","http://192.168.1.2:8080","http://192.168.1.3:8080")server:= http.Server{Addr:"192.168.1.1:8080",Handler:pool, }// Start a HTTP server to listen for peer requests from the groupcachegofunc() {log.Printf("Serving....\n")iferr:=server.ListenAndServe();err!=nil {log.Fatal(err) } }()deferserver.Shutdown(context.Background())// Create a new group cache with a max cache size of 3MBgroup:=groupcache.NewGroup("users",3000000,groupcache.GetterFunc(func(ctx context.Context,idstring,dest groupcache.Sink)error {// Returns a protobuf struct `User`user,err:=fetchUserFromMongo(ctx,id)iferr!=nil {returnerr }// Set the user in the groupcache to expire after 5 minutesreturndest.SetProto(&user,time.Now().Add(time.Minute*5)) }, ))varuserUserctx,cancel:=context.WithTimeout(context.Background(),time.Millisecond*500)defercancel()iferr:=group.Get(ctx,"12345",groupcache.ProtoSink(&user));err!=nil {log.Fatal(err) }fmt.Printf("-- User --\n")fmt.Printf("Id: %s\n",user.Id)fmt.Printf("Name: %s\n",user.Name)fmt.Printf("Age: %d\n",user.Age)fmt.Printf("IsSuper: %t\n",user.IsSuper)// Remove the key from the groupcacheiferr:=group.Remove(ctx,"12345");err!=nil {log.Fatal(err) }}
The call togroupcache.NewHTTPPoolOpts()
is a bit misleading.NewHTTPPoolOpts()
creates a new pool internally within thegroupcache
package where it is uitilized by any groups created. Thepool
returned is only a pointer to the internallly registered pool so the caller can update the peers in the pool as needed.
About
Clone of golang/groupcache with TTL and Item Removal support