75
RowKey design in HBase Akka Persistence Plugin Konrad 'ktoso' Malawski GeeCON 2014 @ Kraków, PL Konrad `@ktosopl` Malawski

HBase RowKey design for Akka Persistence

Embed Size (px)

DESCRIPTION

Short lightning talk about the HBase plugin for Akka Persistence and how it's how key design was specifically tuned for increasing numeric sequential idenfitiers, so that the cluster can be utilised properly. https://github.com/ktoso/akka-persistence-hbase

Citation preview

Page 1: HBase RowKey design for Akka Persistence

RowKey design in HBaseAkka Persistence Plugin

Konrad 'ktoso' Malawski GeeCON 2014 @ Kraków, PL

Konrad `@ktosopl` Malawski

Page 2: HBase RowKey design for Akka Persistence

Konrad `@ktosopl` Malawski

hAkker @

Page 3: HBase RowKey design for Akka Persistence

Konrad `@ktosopl` Malawski

typesafe.com geecon.org

Java.pl / KrakowScala.pl sckrk.com / meetup.com/Paper-Cup @ London

GDGKrakow.pl meetup.com/Lambda-Lounge-Krakow

hAkker @

Page 4: HBase RowKey design for Akka Persistence

PersistentActor

Akka  Persistence  ScalaDays  2014

Page 5: HBase RowKey design for Akka Persistence

PersistentActor

Page 6: HBase RowKey design for Akka Persistence

Compared to “Good ol’ CRUD Model”

state

“Mutable Record”

state =

apply(es)

“Series of Events”

Page 7: HBase RowKey design for Akka Persistence

super quick domain modelling!

sealed trait Command!case class GiveMe(geeCoins: Int) extends Command!case class TakeMy(geeCoins: Int) extends Command

Commands - what others “tell” us; not persisted

case class Wallet(geeCoins: Int) {! def updated(diff: Int) = State(geeCoins + diff)!}

State - reflection of a series of events

sealed trait Event!case class BalanceChangedBy(geeCoins: Int) extends Event!

Events - reflect effects, past tense; persisted

Page 8: HBase RowKey design for Akka Persistence

var state = S0 !

persistenceId = “a” !

PersistentActor

Command

!

!

Journal

Page 9: HBase RowKey design for Akka Persistence

PersistentActor

var state = S0 !

persistenceId = “a” !

!

!

Journal

Generate Events

Page 10: HBase RowKey design for Akka Persistence

PersistentActor

var state = S0 !

persistenceId = “a” !

!

!

Journal

Generate Events

E1

Page 11: HBase RowKey design for Akka Persistence

PersistentActor

ACK “persisted”

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

Page 12: HBase RowKey design for Akka Persistence

PersistentActor

“Apply” event

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Page 13: HBase RowKey design for Akka Persistence

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Okey!

Page 14: HBase RowKey design for Akka Persistence

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Okey!

Page 15: HBase RowKey design for Akka Persistence

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Ok, he got my $.

Page 16: HBase RowKey design for Akka Persistence

PersistentActor

class BitCoinWallet extends PersistentActor {!! var state = Wallet(coins = 0)!! def updateState(e: Event): State = {! case BalanceChangedBy(coins) => state.updatedWith(coins)! }! ! // API:!! def receiveCommand = ??? // TODO!! def receiveRecover = ??? // TODO!!}!

Page 17: HBase RowKey design for Akka Persistence

persist(e) { e => }

Page 18: HBase RowKey design for Akka Persistence

PersistentActor

def receiveCommand = {!! case TakeMy(coins) =>! persist(BalanceChangedBy(coins)) { changed =>! state = updateState(changed) ! }!!!!!!!}

async callback

Page 19: HBase RowKey design for Akka Persistence

persist(){} - Ordering guarantees

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

C1C2

C3

Page 20: HBase RowKey design for Akka Persistence

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

C1C2

C3

Commands get “stashed” until processing C1’s events are acted upon.

persist(){} - Ordering guarantees

Page 21: HBase RowKey design for Akka Persistence

!

!

Journal

var state = S0 !

persistenceId = “a” !

C1C2

C3 E1

E2

E2E1

events get applied in-order

persist(){} - Ordering guarantees

Page 22: HBase RowKey design for Akka Persistence

C2

!

!

Journal

var state = S0 !

persistenceId = “a” !

C3 E1 E2

E2E1

and the cycle repeats

persist(){} - Ordering guarantees

Page 23: HBase RowKey design for Akka Persistence

Recovery

Akka  Persistence  ScalaDays

Page 24: HBase RowKey design for Akka Persistence

Eventsourced, recovery

/** MUST NOT SIDE-EFFECT! */!def receiveRecover = {! case replayedEvent: Event => ! state = updateState(replayedEvent)!}

re-using updateState, as seen in receiveCommand

Akka  Persistence  ScalaDays

Page 25: HBase RowKey design for Akka Persistence

Snapshots

Page 26: HBase RowKey design for Akka Persistence

Snapshots (in SnapshotStore)

Page 27: HBase RowKey design for Akka Persistence

Eventsourced, snapshots

def receiveCommand = {! case command: Command =>! saveSnapshot(state) // async!!}

/** MUST NOT SIDE-EFFECT! */!def receiveRecover = {! case SnapshotOffer(meta, snapshot: State) => ! this.state = state!! case replayedEvent: Event => ! updateState(replayedEvent)!}

snapshot!? how?

Page 28: HBase RowKey design for Akka Persistence

…sum of states…

Snapshots

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

Page 29: HBase RowKey design for Akka Persistence

state until [E8]

Snapshots

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

!

!

Snapshot Store

snapshot!

Page 30: HBase RowKey design for Akka Persistence

state until [E8]

Snapshots

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

crash!

!

!

Snapshot Store

snapshot!

S8

Page 31: HBase RowKey design for Akka Persistence

Snapshots

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

crash!

!

!

Snapshot Store

S8

Page 32: HBase RowKey design for Akka Persistence

“bring me up-to-date!”

Snapshots

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

restart!replay!

!

!

Snapshot Store

S8

Page 33: HBase RowKey design for Akka Persistence

“bring me up-to-date!”

Snapshotsrestart!

replay!

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

!

!

Snapshot Store

S8

Page 34: HBase RowKey design for Akka Persistence

state until [E8]

Snapshotsrestart!

replay!

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

!

!

Snapshot Store

S8

Page 35: HBase RowKey design for Akka Persistence

state until [E8]

Snapshots

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

We could delete these!

!

!

Snapshot Store

S8

Page 36: HBase RowKey design for Akka Persistence

trait MySummer extends Processor {! var nums: List[Int]! var total: Int! ! def receive = {! case "snap" => saveSnapshot(total)! case SaveSnapshotSuccess(metadata) => // ...! case SaveSnapshotFailure(metadata, reason) => // ...! }!}!

Snapshots, save

Async!

Page 37: HBase RowKey design for Akka Persistence

Snapshot Recovery

class Counter extends Processor {! var total = 0! ! def receive = {! case SnapshotOffer(metadata, snap: Int) => ! total = snap!! case Persistent(payload, sequenceNr) => // ...! }!}

Page 38: HBase RowKey design for Akka Persistence

Persistence Plugins

Page 39: HBase RowKey design for Akka Persistence

Akka Persistence TCK

class JournalTCKSpec extends JournalSpec {! lazy val config = ConfigFactory.parseString(“").! withFallback(ConfigFactory.load())!}!!!!!class SnapshotStoreTCKSpec extends SnapshotStoreSpec {! lazy val config = ConfigFactory.parseString(“").!! ! ! ! ! ! ! ! ! ! withFallback(ConfigFactory.load())! }!

Page 40: HBase RowKey design for Akka Persistence

Journal Plugin API!def asyncWriteMessages(! messages: immutable.Seq[PersistentRepr]!): Future[Unit]!!def asyncDeleteMessagesTo(! persistenceId: String, ! toSequenceNr: Long, ! permanent: Boolean!): Future[Unit]!!@deprecated("writeConfirmations will be removed.", since = "2.3.4")!def asyncWriteConfirmations(! confirmations: immutable.Seq[PersistentConfirmation]!): Future[Unit]!!@deprecated("asyncDeleteMessages will be removed.", since = "2.3.4")!def asyncDeleteMessages(! messageIds: immutable.Seq[PersistentId], ! permanent: Boolean!): Future[Unit]!

Page 41: HBase RowKey design for Akka Persistence

Optimising writes

Page 42: HBase RowKey design for Akka Persistence

Hbase table data layout

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

Page 43: HBase RowKey design for Akka Persistence

Hbase table data layout

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

HBase regions

Page 44: HBase RowKey design for Akka Persistence

Hbase table data layout

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

HBase regions

(lexicographical order)

Page 45: HBase RowKey design for Akka Persistence

Optimising writes

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”id = “b”

Page 46: HBase RowKey design for Akka Persistence

Optimising writes

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”id = “b”

Page 47: HBase RowKey design for Akka Persistence

Optimising writes

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”id = “b”

HOT region

Page 48: HBase RowKey design for Akka Persistence

Optimising writes

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”id = “b”

HOT region

Page 49: HBase RowKey design for Akka Persistence

Optimising writes

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”id = “b”

impossible to spread load!

Page 50: HBase RowKey design for Akka Persistence

Optimising writes

hot-spotting

Page 51: HBase RowKey design for Akka Persistence

Optimising writes

hot-spotting

utilise entire cluster

Page 52: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-b-0001, 001-a-0051

id = “a”

002-a-0002, 002-b-0002, 002-a-00052

003-a-0003, 003-b-0003, 003-a-0053

049-a-0049, 049-b-0049, 049-a-0099

“partition” seeds

[HMaster]

Page 53: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-b-0001, 001-a-0051

id = “a”

002-a-0002, 002-b-0002, 002-a-00052

003-a-0003, 003-b-0003, 003-a-0053

049-a-0049, 049-b-0049, 049-a-0099

“partition” seeds

[HMaster]

Page 54: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

[HMaster]

Write load spread to cluster!

Page 55: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

Writes to different regions! [HMaster]

Page 56: HBase RowKey design for Akka Persistence

Optimising writes

Page 57: HBase RowKey design for Akka Persistence

Optimising reads

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”

replay!

Page 58: HBase RowKey design for Akka Persistence

Optimising reads

a-0001,a-0002,a-0003 b-0001,b-0002,b-0003

id = “a”

replay!

Ordered, batch read, super efficient!!!

Page 59: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 60: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 61: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 62: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 63: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 64: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 65: HBase RowKey design for Akka Persistence

Optimising writes

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

this is madness!

replay!

Page 66: HBase RowKey design for Akka Persistence

Optimising reads

Page 67: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!

Page 68: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

async!

replay!+ re-sequence

Page 69: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

async!

small batches

replay!+ re-sequence

Page 70: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!(to seqNr = 2)

Page 71: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

replay!(to seqNr = 2)

Page 72: HBase RowKey design for Akka Persistence

Optimising recovery

001-a-0001, 001-a-0051

id = “a”

002-a-0002, 002-a-00052

003-a-0003, 003-a-0053

049-a-0049, 049-a-0099…

for short recovery = no need to check all servers!

replay!(to seqNr = 2)

Page 73: HBase RowKey design for Akka Persistence

Akka  Persistence  ScalaDays  2014

Akka Persistence Plugins• Journals / Snapshot Stores (http://akka.io/community/) • Cassandra • HBase • Kafka • DynamoDB • MongoDB • shared LevelDB journal for testing

Page 74: HBase RowKey design for Akka Persistence

Akka  Persistence  ScalaDays  2014

Links• http://akka.io • https://groups.google.com/forum/#!forum/akka-user !

• https://github.com/ktoso/akka-persistence-hbase !

• http://www.slideshare.net/alexbaranau/intro-to-hbase-internals-schema-design-for-hbase-users

• http://blog.sematext.com/2012/04/09/hbasewd-avoid-regionserver-hotspotting-despite-writing-records-with-sequential-keys/

• https://github.com/OpenTSDB/asynchbase

Page 75: HBase RowKey design for Akka Persistence

©Typesafe 2014 – All Rights Reserved