1- # groupcache
21
3- groupcache is a caching and cache-filling library, intended as a
4- replacement for memcached in many cases.
2+ <h2 align =" center " >
3+ <img src =" docs/groupcache-logo.png " alt =" GroupCache Logo " width =" 800 " /><br />
4+ Distributed Cache Library
5+ </h2 >
56
6- For API docs and examples, see http://godoc.org/github.com/groupcache/groupcache-go/v3
7-
7+ ---
88
9- ## Comparing Groupcache to memcached
9+ [ ![ CI] ( https://github.com/groupcache/groupcache-go/workflows/CI/badge.svg )] ( https://github.com/groupcache/groupcache-go/actions?query=workflow:"CI" )
10+ [ ![ GitHub tag] ( https://img.shields.io/github/tag/groupcache/groupcache-go?include_prereleases=&sort=semver&color=blue )] ( https://github.com/groupcache/groupcache-go/releases/ )
11+ [ ![ License] ( https://img.shields.io/badge/License-Apache-blue )] ( #license )
1012
11- ### ** Like memcached** , groupcache:
12-
13- * shards by key to select which peer is responsible for that key
14-
15- ### ** Unlike memcached** , groupcache:
16-
17- * does not require running a separate set of servers, thus massively
18- reducing deployment/configuration pain. groupcache is a client
19- library as well as a server. It connects to its own peers.
20-
21- * comes with a cache filling mechanism. Whereas memcached just says
22- "Sorry, cache miss", often resulting in a thundering herd of
23- database (or whatever) loads from an unbounded number of clients
24- (which has resulted in several fun outages), groupcache coordinates
25- cache fills such that only one load in one process of an entire
26- replicated set of processes populates the cache, then multiplexes
27- the loaded value to all callers.
28-
29- * does not support versioned values. If key "foo" is value "bar",
30- key "foo" must always be "bar".
31-
32- ## Loading process
13+ Groupcache is a Go-based caching and cache-filling library designed to replace traditional caching solutions
14+ like MEMCACHED and REDIS in many scenarios.
3315
34- In a nutshell, a groupcache lookup of ** Get("foo")** looks like:
16+ ## Why Use Groupcache?
17+ - Cost Reduction: Eliminates the need for external system dependencies and additional server infrastructure
18+ - Increased efficiency: Minimizes network calls to external systems and data sources
19+ - Load Protection: Prevents the thundering herd problem through the use of ` singleflight ` synchronization
3520
36- (On machine #5 of a set of N machines running the same code)
21+ ## How It Works
22+ Groupcache functions as an in-memory read-through cache with the following workflow:
23+ - When your application requests data, Groupcache uses key sharding to determine key ownership
24+ - For locally-owned keys:
25+ - If the key exists in the local cache, data is returned immediately
26+ - If the key is missing, Groupcache retrieves it from the data source, caches it, and returns it
27+ - Future requests for the same key are served directly from the hot cache
28+ - For keys owned by other peers:
29+ - Groupcache forwards the request to the appropriate peer instance
30+ - The owning peer handles the cache lookup and retrieval process
3731
38- 1 . Is the value of "foo" in local memory because it's super hot? If so, use it.
32+ This architecture provides the following benefits:
33+ - Network efficiency by avoiding requests for locally-owned keys
34+ - Load protection by channeling identical key requests to a single Groupcache instance within the cluster
35+ - Avoid unnecessary network calls to external cache systems by using local memory for the cache
3936
40- 2 . Is the value of "foo" in local memory because peer # 5 (the current
41- peer) is the owner of it? If so, use it .
37+ Thanks to ` singleflight ` synchronization, even if your application makes millions of requests for a
38+ specific key (e.g., "FOO"), Groupcache will only query the underlying data source once .
4239
43- 3 . Amongst all the peers in my set of N, am I the owner of the key
44- "foo"? (e.g. does it consistent hash to 5?) If so, load it and
45- store in the local cache.. If other callers come in, via the same
46- process or via RPC requests from peers, they block waiting for the load
47- to finish and get the same answer. If not, RPC to the peer that's the
48- owner and get the answer. If the RPC fails, just load it locally (still with
49- local dup suppression).
40+ <div align =" center " >
41+ <img src =" docs/simplified-diagram.png " alt =" Simplified Diagram " width =" 500 " /><br />
42+ </div >
5043
51- ## Example
44+ ## Usage
5245
5346``` go
5447import (
@@ -138,8 +131,38 @@ func ExampleUsage() {
138131 d.Shutdown (ctx)
139132}
140133```
134+ # Concepts
135+ ### Groups
136+ GroupCache provides functionality to create multiple distinct "groups" through its ` NewGroup() ` function.
137+ Each group serves as a separate namespace or storage pool that is distributed across peers using consistent hashing.
138+ You should create a new group whenever you need to prevent key conflicts between similar or identical key spaces.
139+
140+ ### GetterFunc
141+ When creating a new group with ` NewGroup() ` , you must provide a ` groupcache.GetterFunc ` . This function serves as the
142+ read-through mechanism for retrieving cache values that aren't present in the local cache. The function works in
143+ conjunction with ` singleflight ` to ensure that only one request for a specific key is processed at a time. Any
144+ additional requests for the same key will wait until the initial ` groupcache.GetterFunc ` call completes. Given
145+ this behavior, it's crucial to utilize the provided ` context.Context ` to properly handle timeouts and cancellations.
146+
147+ ### The Cache Loading process
148+ In a nutshell, a groupcache lookup of ** Get("foo")** looks like:
149+
150+ (On machine #5 of a set of N machines running the same code)
151+
152+ 1 . Is the value of FOO in local cache because it's super hot? If so, use it.
153+ 2 . Is the value of FOO in local memory because peer #5 (the current
154+ peer) is the owner of it? If so, use it.
155+ 3 . Amongst all the peers in my set of N, am I the owner of the key
156+ FOO? (e.g. does it consistent hash to 5?) If so, load it and
157+ store in the local cache. If other callers come in, via the same
158+ process or via RPC requests from peers, they block waiting for the load
159+ to finish and get the same answer. If not, RPC to the peer that's the
160+ owner and get the answer. If the RPC fails, just load it locally (still with
161+ local dup suppression).
141162
142- # HTTP integration
163+ <img src =" docs/sequence-diagram.svg " alt =" Simplified Diagram " width =" 800 " /><br />
164+
165+ # Integrating GroupCache with HTTP Services
143166This is a quick guide on how to use groupcache in a service that is already listening for HTTP requests. In some
144167circumstances you may want to have groupcache respond using the same HTTP port that non groupcache requests are
145168received through. In this case you must explicitly create the ` transport.HttpTransport ` which can then be passed
@@ -198,9 +221,31 @@ func main() {
198221}
199222```
200223
201- ### Otter Cache
224+ # Comparing Groupcache to memcached
225+
226+ ### ** Like memcached** , groupcache:
227+ * shards by key to select which peer is responsible for that key
228+
229+ ### ** Unlike memcached** , groupcache:
230+ * does not require running a separate set of servers, thus massively
231+ reducing deployment/configuration pain. groupcache is a client
232+ library as well as a server. It connects to its own peers.
233+ * comes with a cache filling mechanism. Whereas memcached just says
234+ "Sorry, cache miss", often resulting in a thundering herd of
235+ database (or whatever) loads from an unbounded number of clients
236+ (which has resulted in several fun outages), groupcache coordinates
237+ cache fills such that only one load in one process of an entire
238+ replicated set of processes populates the cache, then multiplexes
239+ the loaded value to all callers.
240+ * does not support versioned values. If key "foo" is value "bar",
241+ key "foo" must always be "bar".
242+
243+ # Pluggable Internal Cache
244+ GroupCache supports replacing the default LRU cache implementation with alternative implementations.
245+
202246[ Otter] ( https://maypok86.github.io/otter/ ) is a high performance lockless cache suitable for high concurrency environments
203- where lock contention is an issue. Typically, servers with over 40 CPUs and lots of concurrent requests.
247+ where lock contention is an issue. Typically, servers with over 40 CPUs and lots of concurrent requests would benefit
248+ from using an alternate cache implementation like Otter.
204249
205250``` go
206251import " github.com/groupcache/groupcache-go/v3/contrib"
@@ -217,11 +262,11 @@ instance := groupcache.New(groupcache.Options{
217262})
218263```
219264
220- #### Cache Size Implications
265+ #### Cache Size Implications for Otter
221266Due to the algorithm Otter uses to evict and track cache item costs, it is recommended to
222267use a larger maximum byte size when creating Groups via ` Instance.NewGroup() ` if you expect
223- your cached items to be very large. This is because groupcache uses a "Main Cache" and a
224- "Hot Cache" system where the "Hot Cache" is 1/8th the size of the maximum bytes requested.
268+ your cached items to be very large. This is because groupcache uses a "Main Cache" and a
269+ "Hot Cache" system where the "Hot Cache" is 1/8th the size of the maximum bytes requested.
225270
226271Because Otter cache may reject items added to the cache which are larger than 1/10th of the
227272total capacity of the "Hot Cache" this may result in a lower hit rate for the "Hot Cache" when
@@ -236,10 +281,16 @@ bytes in a Group to accommodate the maximum cache item. If you have no estimate
236281of items in the groupcache, then you should monitor the ` Cache.Stats().Rejected ` stat for the cache
237282in production and adjust the size accordingly.
238283
284+
285+ # Source Code Internals
286+ If you are reading this, you are likely in front of a Github page and are interested in building a custom transport
287+ or creating a Pull Request. In which case, the following explains the most of the important structs and how they
288+ interact with each other.
289+
239290### Modifications from original library
240291The original author of groupcache is [ Brad Fitzpatrick] ( https://github.com/bradfitz ) who is also the
241- author of [ memcached] ( https://memcached.org/ ) . The original code repository for groupcache can be
242- found [ here] ( https://github.com/golang/groupcache ) and appears to be abandoned. We have taken the liberty
292+ author of [ memcached] ( https://memcached.org/ ) . The original code repository for groupcache can be
293+ found [ here] ( https://github.com/golang/groupcache ) and appears to be abandoned. We have taken the liberty
243294of modifying the library with additional features and fixing some deficiencies.
244295
245296* Support for explicit key removal from a group. ` Remove() ` requests are
@@ -266,11 +317,7 @@ of modifying the library with additional features and fixing some deficiencies.
266317 transports can be used without needing access to the internals of the library.
267318* Updated dependencies and use modern golang programming and documentation practices
268319* Added support for optional internal cache implementations.
269-
270- # Source Code Internals
271- If you are reading this, you are likely in front of a Github page and are interested in building a custom transport
272- or creating a Pull Request. In which case, the following explains the most of the important structs and how they
273- interact with each other.
320+ * Many other code improvements
274321
275322### groupcache.Instance
276323Represents an instance of groupcache. With the instance, you can create new groups and add other instances to your
@@ -346,4 +393,3 @@ defer cluster.Shutdown(context.Background())
346393
347394### Code Map
348395![ docs/code-diagram.png] ( docs/code-diagram.png )
349-
0 commit comments