https://github.com/iwanbk/bcache
  
  
    Eventually consistent distributed in-memory  cache Go library 
    https://github.com/iwanbk/bcache
  
cache crdt eventually-consistent golang gossip-protocol in-memory-caching lru-cache
        Last synced: 6 months ago 
        JSON representation
    
Eventually consistent distributed in-memory cache Go library
- Host: GitHub
 - URL: https://github.com/iwanbk/bcache
 - Owner: iwanbk
 - License: mit
 - Created: 2018-12-26T15:45:16.000Z (almost 7 years ago)
 - Default Branch: master
 - Last Pushed: 2023-01-13T09:48:31.000Z (almost 3 years ago)
 - Last Synced: 2025-03-21T21:44:58.211Z (8 months ago)
 - Topics: cache, crdt, eventually-consistent, golang, gossip-protocol, in-memory-caching, lru-cache
 - Language: Go
 - Homepage:
 - Size: 35.2 KB
 - Stars: 157
 - Watchers: 5
 - Forks: 20
 - Open Issues: 4
 - 
            Metadata Files:
            
- Readme: README.md
 - License: LICENSE
 
 
Awesome Lists containing this project
- awesome-go - bcache - Eventually consistent distributed in-memory cache Go library. (Database / Caches)
 - awesome-go-extra - bcache - memory cache Go library|90|13|4|2018-12-26T15:45:16Z|2019-05-01T02:01:34Z| (Generators / Caches)
 
README
          # bcache
[](http://godoc.org/github.com/iwanbk/bcache)
[](https://travis-ci.org/iwanbk/bcache)
[](https://codecov.io/gh/iwanbk/bcache)
[](https://goreportcard.com/report/github.com/iwanbk/bcache)
[](https://codeclimate.com/github/iwanbk/bcache/maintainability)
A Go Library to create distributed in-memory cache inside your app.
## Features
- LRU cache with configurable maximum keys
- Eventual Consistency synchronization between peers
- Data are replicated to all nodes
- cache filling mechanism. When the cache of the given key is not exist, bcache coordinates cache fills such that only one call populates the cache to avoid thundering herd or [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede)
## Why using it
- if extra network hops needed by external caches like `redis` or `memcached` is not acceptable for you
- you only need cache with simple `Set`, `Get`, and `Delete` operation
- you have enough RAM to hold the cache data
## How it Works
1. Nodes find each other using [Gossip Protocol](https://en.wikipedia.org/wiki/Gossip_protocol)
Only need to specify one or few nodes as bootstrap nodes, and all nodes will find each other using gossip protocol
2. When there is cache `Set` and `Delete`, the event will be propagated to all of the nodes.
So, all of the nodes will eventually have synced data.
## Cache filling
Cache filling mechanism is provided in [GetWithFiller](https://godoc.org/github.com/iwanbk/bcache#Bcache.GetWithFiller) func.
When the cache for the given key is not exists:
- it will call the provided `Filler`
- set the cache using value returned by the `Filler`
Even there are many goroutines which call `GetWithFiller`, the given `Filler` func
will only called once for each of the key.
Cache stampede could be avoided this way.
## Quick Start
In server 1
```go
bc, err := New(Config{
	// PeerID:     1, // leave it, will be set automatically based on mac addr
	ListenAddr: "192.168.0.1:12345",
	Peers:      nil, // it nil because we will use this node as bootstrap node
	MaxKeys:    1000,
	Logger:     logrus.New(),
})
if err != nil {
    log.Fatalf("failed to create cache: %v", err)
}
bc.Set("my_key", "my_val",86400)
```
In server 2
```go
bc, err := New(Config{
	// PeerID:     2, // leave it, will be set automatically based on mac addr
	ListenAddr: "192.168.0.2:12345",
	Peers:      []string{"192.168.0.1:12345"},
	MaxKeys:    1000,
	Logger:     logrus.New(),
})
if err != nil {
    log.Fatalf("failed to create cache: %v", err)
}
bc.Set("my_key2", "my_val2", 86400)
```
In server 3
```go
bc, err := New(Config{
	// PeerID:     3,// will be set automatically based on mac addr
	ListenAddr: "192.168.0.3:12345",
	Peers:      []string{"192.168.0.1:12345"},
	MaxKeys:    1000,
	Logger:     logrus.New(),
})
if err != nil {
    log.Fatalf("failed to create cache: %v", err)
}
val, exists := bc.Get("my_key2")
```
### GetWithFiller example
```go
c, err := New(Config{
	PeerID:     3,
	ListenAddr: "192.168.0.3:12345",
	Peers:      []string{"192.168.0.1:12345"},
	MaxKeys:    1000,
})
if err != nil {
    log.Fatalf("failed to create cache: %v", err)
}
val, exp,err  := bc.GetWithFiller("my_key2",func(key string) (string, error) {
        // get value from database
         .....
         //
		return value, 0, nil
}, 86400)
```
## Credits
- [weaveworks/mesh](https://github.com/weaveworks/mesh) for the gossip library
- [groupcache](https://github.com/golang/groupcache) for the inspiration