Slide 1

Slide 1 text

Database backed Coherence cache Tips, Tricks and Patterns Alexey Ragozin [email protected] May 2012

Slide 2

Slide 2 text

Power of read-write-backing-map • Fetching data as needed • Separation of concerns • Gracefully handling concurrency • Write-behind – removing DB from critical path • Database operation bundling

Slide 3

Slide 3 text

… and challenges  DB operations are order of magnitude slower • Less deterministic response time • Coherence thread pools issues  How verify persistence with write behind?  Data are written in DB in random order  read-write-backing-map and expiry

Slide 4

Slide 4 text

TIPS

Slide 5

Slide 5 text

BinaryEntryStore, did you know? BinaryEntryStore – an alternative to CacheLoader / CacheStore interface. Works with BinaryEntry instead of objects.  You can access binary key and value • Skip deserialization, if binary is enough  You can access previous version of value • Distinguish inserts vs. updates • Find which fields were cached  You cannot set entry TTL in cache loader 

Slide 6

Slide 6 text

When storeAll(…) is called?  cache.getAll(…) • loadAll(…) will be called with partition granularity (since Coherence 3.7)  cache.putAll(…) • write-behind scheme will use storeAll(…) • write-through scheme will use store(…) (this could be really slow)

Slide 7

Slide 7 text

When storeAll(…) is called?  cache.invokeAll(…)/aggregate(…) • calling get() on entry will invoke load(…) (if entry is not cached yet) • calling set() on entry will invoke put(…) (in case of write-through) • you can check entry.isPresent() to avoid needless read-through • Coherence will never use bulk cache store operations for aggregators and entry processors

Slide 8

Slide 8 text

Warming up aggregator public static void preloadValuesViaReadThrough(Set entries) { CacheMap backingMap = null; Set keys = new HashSet(); for (BinaryEntry entry : entries) { if (backingMap == null) { backingMap = (CacheMap) entry.getBackingMapContext().getBackingMap(); } if (!entry.isPresent()) { keys.add(entry.getBinaryKey()); } } backingMap.getAll(keys); } Code above will force all entries for working set to be preloaded using bulk loadAll(…). Call it before processing entries.

Slide 9

Slide 9 text

Why load(…) is called on write? Case: • Entry processor is called on set of entries which is not in cache and assigns values to them Question: • Why read-through is triggered? Answer: • BinaryEntry.setValue(Object) returns old value • Use BinaryEntry.setValue(Object, boolean)

Slide 10

Slide 10 text

Bulk put with write through You can use same trick for updates. 1. Pack your values in entry processor. 2. In entry processor obtain backing map reference. 3. Call putAll(…) on backing map. Be careful !!! • You should only put key for partition entry processor was called for. • Backing map accepts serialized objects.

Slide 11

Slide 11 text

Using operation bundling Worker thread1 Worker thread2 Req 1 Req 2 Worker thread3 storeAll() RWBM Cache Store Waiting Req 3 Worker thread 3 Req 1 Req 2 Req 3 Worker thread1 Worker thread2 Worker thread3 RWBM Cache Store

Slide 12

Slide 12 text

Using operation bundling storeAll(…) with N keys could be called if  You have at least N concurrent operations  You have at least N threads in worker pool store 5 4

Slide 13

Slide 13 text

Checking STORE decoration  Configure cache as “write-behind”  Put data  Wait until, STORE decoration become TRUE (actually it will switch from FALSE to null) public class StoreFlagExtractor extends AbstractExtractor implements PortableObject { // ... private Object extractInternal(Binary binValue, BinaryEntry entry) { if (ExternalizableHelper.isDecorated(binValue)) { Binary store = ExternalizableHelper.getDecoration(binValue, ExternalizableHelper.DECO_STORE); if (store != null) { Object st = ExternalizableHelper.fromBinary(store, entry.getSerializer()); return st; } } return Boolean.TRUE; } }

Slide 14

Slide 14 text

BEHIND SCENES

Slide 15

Slide 15 text

How it works? Distributed cache service read-write backing-map Cache store Internal map Miss cache

Slide 16

Slide 16 text

How it works? Distributed cache service read-write backing-map Cache store Internal map Miss cache Distribution and backup of data Storing cache data, expiry Interacting with persistent storage Caching cache loader misses Coordination

Slide 17

Slide 17 text

How it works? read-write backing-map Cache store Internal map Miss cache get(key) Distributed cache service #1 Cache service is receiving get(…) request.

Slide 18

Slide 18 text

How it works? read-write backing-map Cache store Internal map Miss cache get(key) Distributed cache service get(key) #2 Cache service is invoking get(…) on backing map. Partition transaction is open.

Slide 19

Slide 19 text

How it works? #3 read-write backing-map Cache store Internal map Miss cache Distributed cache service get(key) get(key) Backing map checks internal map and miss cache if present. Key is not found.

Slide 20

Slide 20 text

How it works? #4 read-write backing-map Cache store Internal map Miss cache load(key) Distributed cache service get(key) get(key) Backing map is invoking load(…) on cache loader.

Slide 21

Slide 21 text

How it works? #5 read-write backing-map Cache store Internal map Miss cache Distributed cache service query external data source get(key) get(key) load(key) Cache loader is retrieving value for external source

Slide 22

Slide 22 text

How it works? #6 read-write backing-map Cache store Internal map Miss cache Distributed cache service get(key) get(key) load(key) query external data source Value is loaded

Slide 23

Slide 23 text

How it works? #7 read-write backing-map Cache store Internal map Miss cache Distributed cache service get(key) get(key) load(key) query external data source Backing map is updating internal map

Slide 24

Slide 24 text

How it works? #8 read-write backing-map Cache store Internal map Miss cache map event Distributed cache service get(key) get(key) load(key) query external data source Internal map is observable and cache service is receiving event about new entry in internal map.

Slide 25

Slide 25 text

How it works? #9 read-write backing-map Cache store Internal map Miss cache map event Distributed cache service get(key) get(key) load(key) query external data source Call to backing map returns. Cache service is ready to commit partition transaction.

Slide 26

Slide 26 text

How it works? #10 read-write backing-map Cache store Internal map Miss cache update backup Distributed cache service get(key) get(key) load(key) map event query external data source Partition transaction is being committed. New value is being sent to backup node.

Slide 27

Slide 27 text

How it works? #11 read-write backing-map Cache store Internal map Miss cache Distributed cache service get(key) get(key) load(key) map event update backup query external data source Response for get(…) request is sent back as backup has confirmed update.

Slide 28

Slide 28 text

How it works? #1 put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service Cache service is receiving put(…) requiest.

Slide 29

Slide 29 text

How it works? #2 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service Cache service is invoking put(…) on backing map. Partition transaction is open.

Slide 30

Slide 30 text

How it works? #3 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service Value is immediately stored in internal map and put to write-behind queue.

Slide 31

Slide 31 text

How it works? #4 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service map event DECO_STORE=false Cache service is receiving event, but backing map is decorating value with DECO_STORE=false flag to mark that value is yet-to-stored.

Slide 32

Slide 32 text

How it works? #5 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service map event DECO_STORE=false Call to backing map return.

Slide 33

Slide 33 text

How it works? #6 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service update backup map event DECO_STORE=false Partition transaction is being committed. Backup will receive value decorated with DECO_STORE=false.

Slide 34

Slide 34 text

How it works? #7 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service map event DECO_STORE=false update backup Cache service is sending response back as soon as backup is confirmed.

Slide 35

Slide 35 text

How it works? #8 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service Eventually, cache store is called to persist value. It is done on separate thread.

Slide 36

Slide 36 text

How it works? #9 put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service store to external storage Value is stored in external storage by cache store.

Slide 37

Slide 37 text

How it works? #10 store to external storage put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service map event DECO_STORE=null Once call to cache store has returned successfully. Backing map is removing DECO_STORE decoration from value is internal map. Cache service is receiving map event

Slide 38

Slide 38 text

How it works? #11 store to external storage put(k,v) put(k,v) read-write backing-map Cache store Internal map Miss cache Distributed cache service update backup map event DECO_STORE=null Map event was received by cache service outside of service thread. It will be put to OOB queue and eventually processed. Update to backup will be sent once event is processed.

Slide 39

Slide 39 text

THREADING

Slide 40

Slide 40 text

Requests and jobs putAll(…) Client side: One method call

Slide 41

Slide 41 text

Requests and jobs putAll(…) PutRequest PutRequest PutRequest Network: One request for each member

Slide 42

Slide 42 text

Requests and jobs putAll(…) PutRequest PutRequest PutRequest Job Job Job Storage node: One job per partition

Slide 43

Slide 43 text

Requests and jobs Problem  Single API call may produce hundreds of jobs for worker threads in cluster (limited by partition count).  Write-through and read-through jobs could be time consuming.  While all threads are busy by time consuming jobs, cache is unresponsive.

Slide 44

Slide 44 text

Requests and jobs Workarounds  Huge thread pools  Request throttling  By member (one network request at time)  By partitions (one job at time)  Priorities  Applicable only to EP and aggregators

Slide 45

Slide 45 text

“UNBREAKABLE CACHE” PATTERN

Slide 46

Slide 46 text

“Canary” keys  Canary keys – special keys (one per partitions) ignored by all cache operations.  Canary key is inserted once “recovery” procedure have verified that partition data is complete.  If partition is not yet loaded or lost due to disaster, canary key will be missing.

Slide 47

Slide 47 text

Recovery procedure  Store object hash code in database  Using hash you can query database for all keys belonging to partition  Knowing all keys, can use read-through to pull data to a cache  Cache is writable during recovery!  Coherence internal concurrency control will ensure consistency

Slide 48

Slide 48 text

“Unbreakable cache” read/write-trough + canary keys + recovery  Key based operations rely on read-through  Filter based operations are checking “canary” keys (and activate recovery is needed)  Preloading = recovery  Cache is writable at all times

Slide 49

Slide 49 text

Checking “canary” keys  Option 1  check “canary” keys  perform query  Option 2  perform query  check “canary” keys

Slide 50

Slide 50 text

Checking “canary” keys  Option 1  check “canary” keys  perform query  Option 2  perform query  check “canary” keys  Right way  check “canaries” inside of query!

Slide 51

Slide 51 text

“Unbreakable cache” Motivation  Incomplete data set would invalidate hundred of hours of number crunching  100% complete data or exception  Persistent DB is requirement anyway Summary  Transparent recovery (+ preloading for free)  Always writable (i.e. feeds are not waiting for recovery)  Graceful degradation of service in case of “disastrous conditions”

Slide 52

Slide 52 text

Thank you Alexey Ragozin [email protected] http://blog.ragozin.info - my articles http://code.google.com/p/gridkit - my open source code