Akka -- Scalability in Scala and Java

13,522 views

Published on

Akka, an actor framework written in Scala (that also supports Java) provides you with all the benefits commonly found in actor frameworks, but without the kinks. This presentation will explore actor based concurrency using Akka, and dwell on some of Akka's stregths, culminating in the equation "Transactional Memory + Actors = Transactors".

Published in: Technology
3 Comments
33 Likes
Statistics
Notes
No Downloads
Views
Total views
13,522
On SlideShare
0
From Embeds
0
Number of Embeds
679
Actions
Shares
0
Downloads
365
Comments
3
Likes
33
Embeds 0
No embeds

No notes for slide

Akka -- Scalability in Scala and Java

  1. Scalability in Scala and Java Nadav Wiener
  2. About me• Nadav Wiener (@nadavwr)• Senior Consultant & Architect @ AlphaCSP• Following Scala since 2007
  3. AgendaAkkaThe problem with locksActors & message passingHigh availability & remotingSTM & Transactors
  4. What is Akka?• A actor-based concurrency framework • Provides solutions for non blocking concurrency• Written in Scala, also works in Java• Open source (APL)• Now releasing 1.0 after 2 years in development• Lead developer and founder: Jonas Boner • JRockit, AspectWerkz, AspectJ, Terracotta
  5. “Queen of Lapland” 5
  6. You may also remember… 6
  7. The Problem
  8. Ignorance Is a Bliss If (account1.getBalance() > amount) { account1.withdraw(amount) account2.deposit(amount) }Sewing on a button © Dvortygirl, 17 February 2008. 8
  9. Not an optionif you plan onhaving business
  10. So You Use ThreadsColoured Thread © Philippa Willitts, 24 April 2008. 10
  11. But Without SynchronizationYou Get Unpredictable Behavior 11
  12. Lock based concurrency requiresus to constantly second guess ourcode 12
  13. “The definition of insanity isdoing the same thing over andover again and expecting differentresults. “– Albert Einstein 13
  14. People Are Bad At Thinking Parallel 14
  15. So you synchronize With locks? 15
  16. locking 16
  17. Blocking 17
  18. Lock too little Lock too much 18
  19. Lock recklessly? 19
  20. Using locks recklessly 20
  21. Must Think Globally: Lock ordering Contention Everybody’s code 22
  22. Knowing shared-stateconcurrency != confidence 23
  23. Keep those cores busy!Cores aren’t getting fasterDefault thread stack size on AMD64 = 1MB!Context switching hurts throughput
  24. 25
  25. Actors
  26. Shakespeare Programming Language
  27. Excerpt from "Hello World" in SPLRomeo, a young man with a remarkable patience.Juliet, a likewise young woman of remarkable grace. Scene II: The praising of Juliet.[Enter Juliet] Romeo: Thou art as sweet as the sum of the sum of Hamlet and his horse and his black cat! Speak thy mind! [Exit Juliet]
  28. Actors have nothing to do with theShakespeare Programming Language
  29. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  30. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  31. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  32. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  33. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  34. Actors• Each actor has a message queue• Actors accept and choose what to do with messages• Lightweight & asynchronous
  35. Actors ~4 threads 4 cores• Actors tend to remain bound to a single thread• Actors rarely block, thread can remain active for a Actors long duration • Minimizes context switches – throughput X millions• Akka actors occupy 650 bytes
  36. Benchmark• Several actor implementations for Scala – Akka is considered the fastest
  37. Akka Actors// Java // Scalapublic class GreetingActor extends class GreetingActor extends Actor { UntypedActor { private var counter = 0 private int counter = 0; def receive = { public void onReceive(Object message) throws Exception { case message => { counter++; counter += 1 // 1) Hello, Juliet // 1) Hello, Juliet log.info( log.info( counter + ") Hello, " + message); counter + ") Hello, " + message) } }} } }
  38. Akka Actors// Java // ScalaActorRef Romeo = val greetingActor = actorOf(GreetingActor.class).start(); actorOf[GreetingActor].startgreetingActor.sendOneWay("Juliet"); greetingActor ! "Juliet“// 1) Hello, Juliet // 1) Hello, Juliet
  39. Akka Actors• Once instantiated, actors can be retrieved by id or uuid • uuid - generated by runtime, immutable, unique • id - user assigned, by default thats the class nameclass Romeo extend GreetingActor { self.id = "Romeo"}actorOf[Romeo].startval romeo = actorsFor("Romeo").headromeo ! "Juliet"
  40. Message Passing
  41. Message Passing• Lets build a bank with one actor per account, We’ll be able to : • Check our balance • Deposit money • Withdraw money, but only if we have it (balance remains >= 0)• Well start by defining immutable message types:case class CheckBalance()case class Deposit(amount: Int)case class Withdraw(amount: Int)
  42. Message Passingclass BankAccount(private var balance: Int = 0) extends Actor { def receive = { // … case CheckBalance => self.reply_?(balance) // … }}
  43. Message Passingclass BankAccount(private var balance: Int = 0) extends Actor { def receive = { // … case Deposit(amount) => balance += amount // … }}
  44. Message Passingclass BankAccount(private var balance: Int = 0) extends Actor { def receive = { // … case Withdraw(amount) => balance = (balance - amount) ensuring (_ >= 0) // … }}
  45. Message Passing• Now let’s make a deposit:val account = actorOf[BankAccount].startaccount ! Deposit(100)• But how do we check the account balance?
  46. Bang! Bang Bang!• actorRef ! message - fire and forget• actorRef !! message - send and block (optional timeout) for response• actorRef !!! message - send, reply using future...Jones Boner promised to stop at "!!!"Java equivalents:• ! = sendOneWay• !! = sendRequestReply• !!! = sendRequestReplyFuture
  47. Getting Account Balanceval balance = (account !! CheckBalance) match { // do stuff with result}// or:val balanceFuture = account !!! CheckBalance // does not block// ... go do some other stuff ... later:val balance = balanceFuture.await.result match { // do stuff with result}
  48. Fault Tolerance
  49. Too Big to Fail 51
  50. Jenga Architecture 52
  51. The harder they fall 53
  52. 54
  53. Self Healing,Graceful Recovery 55
  54. Supervision HierarchiesSupervisors: Kind of actorsFault Handling Strategy: One for One or All for OneLifecycle: Permanent or Temporary
  55. Fault Handling Strategy:One For One
  56. One for One All for One, Permanent One for One, Chat Room, Temporary Permanent Romeo, Juliet, Permanent Permanent 59
  57. One for One All for One, Permanent One for One, Chat Room, Temporary Permanent Romeo, Juliet, Permanent Permanent 60
  58. One for One All for One, Permanent One for One, Chat Room, Temporary Permanent Romeo, Juliet, Permanent Permanent 61
  59. One for One All for One, Permanent One for One, Chat Room, Temporary Permanent Romeo, Juliet, Permanent Permanent 62
  60. One for One All for One, Permanent One for One, Chat Room, Temporary Permanent Romeo, Juliet, Permanent Permanent 63
  61. Fault Handling Strategy:All For One
  62. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 67
  63. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 68
  64. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 69
  65. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 70
  66. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 71
  67. All for One All For One, Permanent One for One, Chat Room, Permanent Permanent Romeo, Juliet, Temporary Temporary 72
  68. Supervision, Remoting & HAval supervisor = Supervisor(SupervisorConfig( AllForOneStrategy( List(classOf[Exception]), 3, 1000), List(Supervise(actorOf[ChatServer], Permanent), Supervise(actorOf[ChatServer], Permanent, RemoteAddess("host1", 9000)) )))
  69. High Availability• You can’t have a highly available system on a single computer• Luckily Akka supports near-seamless remote actors
  70. High Availability• Server managed remote actors:// on host1RemoteNode.start("host1", 9000)// register an actorRemoteNode.register(“romeo", actorOf[GreetingActor])// on host2val romeo = RemoteClient.actorFor(“romeo", "host1", 9000)romero ! “juliet"• RemoteClient handles the connection lifecycle for us• Clients can also manage server actors, but enabling this might pose a security risk
  71. Actor model – a life choice?
  72. High scalability Assumes state travelsHgh availability along the messageFast flowEtc… Hostile towards shared state. Minds not easily rewired for this!
  73. Brain Transplant
  74. Software Transactional Memory
  75. Rich Hickey(Clojure) Persistent Data Structures
  76. Persistent Data Structures• Share common immutable structure and data• Copy-on-write semantics: val prices = TransactionalMap[String, Double] atomic { prices += ("hamburger" -> 20.0) }• When “modified”, minimal changes to structure are made to accommodate new data © Rich Hickey 2009
  77. How many people seated in theaudience?
  78. If I started counting, by the time Ifinished… 1, 2, 3, 4, 5, …
  79. …the room would be empty
  80. Jonas Boner
  81. Transactorsclass BankAccount extends Transactor { private val balanceRef = Ref(0) def atomically = { // ... case CheckBalance => self reply_? balance.get // ... }}
  82. Transactorsclass BankAccount extends Transactor { private val balanceRef = Ref(0) def atomically = { // ... case Deposit(amount) => balance alter (_ + amount) // ... }}
  83. Transactorsclass BankAccount extends Transactor { private val balanceRef = Ref(0) def atomically = { // ... case Withdraw(amount) => balance alter (_ - amount) ensuring (_.get >= 0) // ... }}
  84. TransactorsPerforming a money transfer transactionally:val tx = Coordinated()val fromBalance = (from !! tx(CheckBalance())) match { balance: Int => balance}if (fromBalance >= 50) { from ! tx(Withdraw(50)) to ! tx(Deposit(50))}
  85. Coordinated Transactionsclass Bank extends Actor { private val accounts = TransactionalVector[BankAccount] def receive = { // ... case tx @ Coordinated(Join) => { tx atomic { accounts += self.sender.get } } // ...}
  86. Coordinated Transactionsclass Bank extends Actor { private val accounts = TransactionalVector[BankAccount] def receive = { // ... case tx @ Coordinated(Sum) => { val futures = for (account <- accounts) yield account !!! tx(CheckBalance) val allTheMoney = futures map (_.await.result) sum self reply_? allTheMoney } // ...} …and then: println (myBank !! Coordinated(Sum))
  87. Takeaways
  88. Knowing shared-stateconcurrency != confidence 94
  89. References
  90. http://akkasource.org 96
  91. http://scalablesolutions.se 97
  92. http://alphacsp.com
  93. Questions?
  94. Typed Actors in Java• In Java we will usually avoid “untyped” actors, and use POJOs instead:interface BankAccount { Future<Integer> balance(); void deposit(int amount); void withdraw(int amount);}class BankAccountImpl extends TypedActor implements BankAccount { // Almost a regular POJO public Future<Integer> balance() { return future(balance); } // ...}

×