dscache

package module
v0.0.0-...-0e93373 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 22, 2018 License: MIT Imports: 7 Imported by: 1

README

stability-stable

DSCache

An embeddable Key/Value (Strings) in memory store for golang (similar to Memcached but for a Local Machine).

Main Characteristics:
  • Size Limits to limit the ammount of memory usage.
  • Allows for concurrent access by different Goroutines.
  • General LRU Eviction Policy plus Time based expiration for items (Size based eviction and Time based eviction).
  • Strongly tested.
Motivation

A high number of services (micro or plain old SOA) just take data from a datastore (or various), transform it to json or xml and then send it through the network. It is common practice to use a key/value in memory store (like memcached or redis) to cache the results. Using this you can avoid the network roundtrip to the kv store, which might be suitable in some cases.

What's the Use Case of this?

In general the use of a cache is recommended when values are expensive to compute or to retrive, thus using the cache to store them for later use. The use of a cache makes sense when you are willing to spend some memory to improve speed if you are expecting keys will get queried more than once.

Use of DSCache is particularly well suited for when:

  • You can fit all of your items in memory and you need time based expiration for the items.
  • You have a small number of keys which are queried disproportionally more than the rest of the set and that you can fit into your box's memory. (Ie: 10% of keys get 50% of requests so it makes sense to cache them locally like you would with Memcached or Redis).
  • You are setting up a Hierarchy of Caches, again if your request distribution is very uneven, you could have the more requested keys on DSCache, and the rest on an external store like Memcached. This would make sense since a retrieval from DSCache is on the order of the nanoseconds where even on a local version of Memcached you will be considering access on the order or Milliseconds because of the time spent context switching by the OS and the cost of networking.

A Note on Memory Usage

Warning: appart from the size of Dscache, you must also consider the amount of memory used by your program, dscache goroutines and unused garbage. Don't set Dscache to use all of your system memory. It is suggested that when you set Dscache size, that you consider at least 30% to 40% more memory for all of this. (If you have 10GB free to use by Dscache, set maxsize to 6GB).

Please look at https://github.com/emluque/dscache/tree/master/simulation to see actual results of variations on this.

Usage

Create Cache
ds, err := dscache.New(Maxsize unit64)

Where Maxsize is the Size of the cache in bytes.

Examples
// Initialize a dscache with a size of 4 GB and default options

ds, err := dscache.New(4 * dscache.GB)

// Initialize a dscache with a size of 200 MB and default options

ds, err := dscache.New(200 * dscache.MB)
Set Item
ds.Set(key string, value string, expire time.Duration)
Examples
// Expiration in one day

ds.Set("item:17897", "Json string...", 24 * time.Hour)

// Expiration in 30 minutes

ds.Set("item:17897", "Json string...", 30 * time.Minute)
Get Item
item, ok := ds.Get(key string)
Example
// Get an item from cache and verify it exists on cache

item, ok := ds.Get("item:17897")

if !ok {

  // item was not found on cache

  // fetch item from external db

}
Purge Item
ds.Purge(key string)
Example
ds.Purge("item:17897")

Advanced (Custom) configuration

ds, err := dscache.Custom(maxsize uint64, numberOfLists int, gcWorkerSleep time.Duration, workerSleep time.Duration, getListNumber func(string) int)
  • maxsize

    Size of the cache in bytes.

  • numberOfBuckets

    Number of internal buckets used by Dscache. To prevent serialization with concurrent accesses, Dscache splits it's keys into buckets that can be accessed independently, so that when one routine is accessing one bucket, another one could access another bucket simultaneously. The recommended number of buckets should be 4 or 8 * number of cores in your CPU. the default number is 32.

  • gcWorkerSleep

    Since Golang is garbage collected it is not possible to control the exact amount of memory that a program is using. Also, when Golang allocates some system memory it does not immediately release it to the system when not in use.

    Consider the following scenario, Dscache is being used heavily and it has filled its capacity, new sets come in and Dscache frees up its space to save the new objects. Till the moment that the Golang runtime runs a GC event, the runtime will be storing in the Heap both the items on Dscache and the dereferenced old objects. This can create a situation where a lot of memory is allocated that is not actually used by Dscache.

    To prevent this, Dscache runs a worker goroutine that calls runtime.GC() and forces a Garbage collection event every gcWorkerSleep. This is done to minimize the ammount of uncollected garbage and the memory allocations that they imply.

    The default value is 1 Second. But it can be changed to fit your needs.

    If you don't wish to use the dscache garbage collector worker, set it to 0 and this behavior will not run. This is recommended if you are forcing a GC event in other parts of your program.

  • workerSleep

    Dscache runs a worker for every bucket that iterates through the elements starting from the last used and frees them if they have expired. This runs every workerSleep . To prevent this from happening (say you have very long expire times) use 0.

  • getBucketNumber

    You can create a custom function to decide which bucket to send your items to. This will be dependent of the type of keys you are using and the number of buckets. Set to nil to use default. Default hashing function is: http://www.partow.net/programming/hashfunctions/index.html#BKDRHashFunction

Examples
// Custom dscache

ds, err := dscache.New(8 * dscache.GB, 128, time.Second, time.Second, nil)

// Custom dscache with special function for numerical keys. ie: "item:187896"
var numericFormat = func (key string) {

 	index := strings.LastIndex(key, ":") + 1
	numericString := key[index:len(key)]
	num, _ := strconv.Atoi(numericString)

  return num % 256

}

ds, err := dscache.New(2 * dscache.GB, 256, time.Second, time.Second, numericFormat)

Statistics

// Number of Objects currently stored on the Cache
numObjects := ds.NumObjects()

// Current Hit Rate (Ratio of Hits to Requests)
hitRate := ds.HitRate()

//Number of Total Evictions
numEvictions := ds.NumEvictions()

// Number of Gets so far
numGets := ds.NumGets()

// Number of Sets so far
numSets := ds.NumSets()

// Number of Requests so far
numRequests := ds.NumRequests()


Alternatives

The following libraries seem to support similar base functionality as DSCache:

https://github.com/karlseguin/ccache

https://github.com/patrickmn/go-cache

However there are substantial differences in approach from DSCache.

Documentation

Index

Constants

View Source
const (
	B  uint64 = iota
	KB        = 1 << (10 * iota)
	MB
	GB
	TB
)

Byte Sizes Constants

Accesible through dscache.GB, dscache.MB, etc.

Variables

View Source
var ErrCreateGCWorkerSleep = errors.New("Building dscache with gcWorkerSleep < 1/5 of a Second")

ErrCreateGCWorkerSleep Returned when attemping to creat DSCache with a gcWorkerSleep lower than 1/5

View Source
var ErrCreateMaxsizeOfZero = errors.New("Building dscache with maxsize of 0")

ErrCreateMaxsizeOfZero Returned when attemping to creat DSCache with a maxsize of 0

View Source
var ErrMaxsize = errors.New("Value is Bigger than Allowed Maxsize")

ErrMaxsize Used when a key + payload is bigger than allowed LRU Cache size

Functions

This section is empty.

Types

type Dscache

type Dscache struct {
	// contains filtered or unexported fields
}

Dscache Base Structure

func Custom

func Custom(maxsize uint64, numberOfBuckets int, gcWorkerSleep time.Duration, workerSleep time.Duration, getBucketNumber func(string) uint32) (*Dscache, error)

Custom Constructor

@param maxsize Maxsize of cache in Bytes @param numberOfBuckets Number of Bucktets in Dscache

Suggested Use number of CPU Cores * 8
default: 32

@param gcWorkerSleep Time to sleep bettween calls to GC

0 to disable GC Worker
default: 1 Second

@param workerSleep Time to sleep for expiration workers

0 to disable Expiration Worker
default: 1 Second

@param getBucketNumber function to calculate the bucket number from a key

func New

func New(maxsize uint64) (*Dscache, error)

New DSCache with Default values

@param maxsize Maxsize of cache in Bytes

func (*Dscache) Get

func (ds *Dscache) Get(key string) (string, bool)

Get element

@param key element key

func (*Dscache) HitRate

func (ds *Dscache) HitRate() float64

HitRate Gets/Tries

func (*Dscache) NumEvictions

func (ds *Dscache) NumEvictions() uint64

NumEvictions Number of Evictions from Cache

func (*Dscache) NumGets

func (ds *Dscache) NumGets() uint64

NumGets Number of Gets the cache has had

func (*Dscache) NumObjects

func (ds *Dscache) NumObjects() uint32

NumObjects Number of Objects in Cache

func (*Dscache) NumRequests

func (ds *Dscache) NumRequests() uint64

NumRequests Number of Requests the cache has had

func (*Dscache) NumSets

func (ds *Dscache) NumSets() uint64

NumSets Number of Sets the cache has had

func (*Dscache) Purge

func (ds *Dscache) Purge(key string) bool

Purge (delete) element

@param key element key

func (*Dscache) Set

func (ds *Dscache) Set(key, payload string, expires time.Duration) error

Set element

@param key element key

@param payload element payload

@param expires Time.Duration ie: For how much time should it be valid

func (*Dscache) Verify

func (ds *Dscache) Verify()

Verify all of the lits on buckets for inconsistencies.

Used for testing

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL