SlideShare a Scribd company logo
a million bots can't be wrong
               @remeniuk, Viaden Media
                   #ScalaSBP, 18-05-2012
In Viaden our aim is to make the best poker ever
we know that
performance tests should be
   the first-class citizens
and kill 2 birds with one stone,
     using bots for testing
 
#1 we can emulate 50k
players using just one
medium EC2 instance
 
#2 bots are interactive,
so client teams can use
them in development,
and QA for testing
everyone knows Akka, huh?
why Scala and Akka is a perfect
   choice for making bots?


actors are !(interactive)
straightforward remoting
simple scalability/clustering
~30 minutes to make a DSL and CLI
with Scala and SBT
..., but, I have to warn you ...
4 dead simple tips
     for keeping your sanity
when you do asynch with Akka 2.0
tip #1: live fast, die young
typical approach in Akka 1.x


                      lobby

                                desk
login
              l ink
        bot




                                  tourney
Akka 1.x: actors have a long lifecycle


                              lobby

                                        desk
            l ink        nk
      bot             li
                    un
                                l ink
play game
            bot
                                          tourney
Akka 1.x: actors have a long lifecycle


                        lobby

                                         desk
      bot




                                     k
                                 lin
                  bot

                                un
                                           tourney
play tournament                  link
                        bot
in Akka 2.0 the world has changed


               props
     paths
                          new
                       supervision
             actors
now, you're forced to do "the right thing" (c)



                     lobby
                                        desk
        tournament

                                       DeskBot
           desk

          DeskBot

                             IdleBot
all actors are supervised




       lobby

                              login
desk
easy come




       lobby

desk
                         play game
               IdleBot
easy go (when supervisor to be changed)




             lobby


      desk
                     IdleBot   dies
    DeskBot


     borns
class Lobby extends Actor {

    case Login(username, password) =>
          context.actorOf(Props(new IdlePokerBot(...)))

    case JoinAnyDesk(props) => findDesk ! JoinDesk(props)

}

class Desk extends Actor {

    case JoinDesk(botProps)=>
         context.actorOf(Props(new DeskPokerBot(botProps)))

}

class IdlePokerBot(props: BotProps) extends Actor {

    case PlayNow =>
       context.parent ! JoinAnyDesk(props); context.stop(self)

}
Props Pattern - "the soul" of an actor

                         IdleBot

                         BotProps
Props remains alive
between actor
"reincarnations"

                         DeskBot

                         BotProps
case class BotProperties(id: Long,
                         login: String,
                         script: Seq[BotEvent],
                         aggressiveness: Int,
                         sessionId: Protocol.SessionId)



class IdlePokerBot(val botProperties: BotProperties)
                                            extends Bot[Poker]


class DeskPokerBot(val botProperties: BotProperties)
                                            extends Bot[Poker]
tip #2: think beyond
when you know, who's supervising, life's
simple

 akka://gpdev/user/lobby/player1234



 akka://gpdev/user/lobby/desk1/player1234



 akka://gpdev/user/lobby/tournament1/desk1/
 player1234
Bad news
ActorRegistry, actor UUID
        were removed from Akka




but what should I do, now,
when I don't know, where
to look for my bot?
you can make your own registry
(using Extensions, backed with a
distributed data structure)...
or, use the full power of location transparency


                                Projection
         lobby                   Manager

                                Projection
          desk                   var location:
                                  ActorPath

         DeskBot


                           /projection/player123
         IdleBot         /lobby/desk123/player123
class Projection(var container: ActorPath) extends Actor {

  def receive = {
    case newContainer: ActorPath => container = newContainer
    case msg =>
          context.actorFor(container.child(self.path.name)) !
msg
  }

}

class ProjectionManager extends Actor {

    def receive = {
      case Add(actor) => context.actorOf(Props(new
                Projection(actor.path.parent)), actor.path.name)
      case Forward(msg, path) => context.actorFor(path) ! msg
    }

}


projectionManager ! Add(actorRef)
projectionManager ! Forward("ping", "actor1")
a million bots can't be wrong
class Projection(var container: ActorPath) extends Actor {

    def receive = {
      case newContainer: ActorPath => container = newContainer
      case msg =>
            context.actorFor(container.child(self.path.name)) ! msg
    }

}

class ProjectionManager extends Actor {

    def receive = {
      case Add(actor) => context.actorOf(Props(new
                Projection(actor.path.parent)), actor.path.name)
      case Forward(msg, path) => context.actorFor(path) ! msg
    }

}


projectionManager ! Add(actorRef)
system.actorFor(projectionManager.path.child("actor" + i)) !
"ping"
a million bots can't be wrong
class ProjectionManager extends Actor {

    def receive = {
      case Add(actor) => context.actorOf(Props(new
                Projection(actor.path.parent)), actor.path.name)
      case Forward(msg, path) =>
                    context.actorSelection("../*/" + path) ! msg
    }

}


val projectionManager = system.actorOf(Props
[ProjectionManagerRoutee]
        .withRouter(RoundRobinRouter(resizer = Some
    (DefaultResizer(lowerBound = 10, upperBound = 20)))),
    "projection")


projectionManager ! Add(actorRef)
projectionManager ! Forward("ping", "actor1")
a million bots can't be wrong
case class CustomRouter(n: Int, routerDispatcher: String =
DefaultDispatcherId, supervisorStrategy: SupervisorStrategy =
defaultStrategy) extends RouterConfig {

    def createRoute(props: Props, provider: RouteeProvider) = {

    provider.registerRoutees((1 to n).map(i =>
   provider.context.actorOf(Props[ProjectionManager], i.
toString)))

    def destination(sender: ActorRef, path: String) =
      List(Destination(sender,
                        provider.routees(abs(path.hashCode) %
n)))

        {
            case m@(sender, Add(actor)) ⇒
                                 destination(sender, actor.path.name)
            case m@(sender, Forward(_, name)) ⇒
                                 destination(sender, name)
        }
    }

}
a million bots can't be wrong
tip #3: don't do anything stupid
you've tried all the options, system load is fine,
only 1/10 of the heap is used, but you still can
start not more than 1k bots!?
ulimit -n <proper value>
your actor is lacking of throughput?
 
 
 
 
 
 
 
wait before adding pools
share responsibility!
one fine-grained actor is enough in 99% of the cases
100-300 threads are serving 300 bots!?
spawn futures, backed with standalone
[bounded] pools, for blocking operations

 class ThirdPartyWrapper extends Actor {

     case F(x) => sender ! thirdPartyService.f(x)
 // call to a function that takes a lot of time to
 // complete

 }



class ThirdPartyWrapper extends Actor {

     case F(x) => val _sender = sender
         Future(thirdPartyService.f(x)).map(_sender ! _)
         // ugly, but safe, and perfectly right
}
use separate dispatchers
lobby-dispatcher                       projection-manager-dispatcher
PinnedDispatcher                       BalancingDispatcher




               lobby                             Projection
                                                  Manager
                   desk
                                                 Projection
                                                         
               DeskBot

                                                projection-dispatcher
container-dispatcher      desk-bot-dispatcher Dispatcher
Dispatcher                Dispatcher
GOTCHA: Akka successfully bootstraps, even if your
dispatcher is not configured, or the config is wrong
 
Always check the logs to make sure that dispatchers are used!

  [WARN][gpdev-akka.actor.default-dispatcher-1] [Dispatchers]
  Dispatcher [bot-system.container-dispatcher] not
  configured, using default-dispatcher
  [WARN][gpdev-bot-system.container-dispatcher-1]
  [PinnedDispatcherConfigurator] PinnedDispatcher [bot-
  system.lobby-dispatcher] not configured to use
  ThreadPoolExecutor, falling back to default config.

  [DEBUG][gpdev-akka.actor.default-dispatcher-24] [akka:
  //gpdev/user/poker/lobby] logged in
  [DEBUG][gpdev-akka.actor.default-dispatcher-14] [akka:
  //gpdev/user/poker/projeciton/$g/player20013] starting
  projection...
tip #4: analyze that
how to measure?
 
Metrics - pushes various collected metrics to Graphite
Carbon and Graphite - gather metrics, and expose them via web
interface
 
object BotMetrics {

1. val   loggedInCount = new Counter(Metrics.newCounter(classOf[Lobby
[_]],
                                       "logged-in-count"))

3. GraphiteReporter.enable(1,   TimeUnit.MINUTES, "localhost", 2003)

}

class Lobby extends Actor {

2. case   Login(username, pass) => BotMetrics.loggedInCount += 1

}


1. add logged-in user counter                                      4.
2. update it
3. enable reporting to
Graphite
4. build a graph in Grtaphite
what to measure?
     
    - mailbox size1
    - throughput
    - time, before the message is processed (both in
    actor and future)2
    - time to process a message
    - count of threads
    - actor pool size
    - heap size




1
    requires implementation of a custom mailbox that can expose mailbox size
2
    every message should be stuffed with a timestamp
how to tune dispatchers?
 
VisualVM - thread timeline shows, if thread polls behind dispatchers
are used effectively
 
don't neglect old good logging
 
[ERROR][05/06/2012 12:55:43.826] [gpdev-bot-system.
desk-bot-dispatcher-7]
[akka://gpdev/user/
poker/lobby/tournament5382577/desk109129/player2012
1]
unprocessed game event: GameEvent(CHAT,None,None)
thanks for listening
we're hiring!
viaden.com/careers/vacancies.html

More Related Content

PDF
libGDX: Scene2D
PDF
Active Support Core Extensions (1)
PDF
Beyond the Callback: Yield Control with Javascript Generators
PDF
Unreal Engine Basics 03 - Gameplay
PDF
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
PDF
st_launcher: Tonel-based Smalltalk shell Scripts
PPSX
Symfony2 meets propel 1.5
PDF
Anatomy of a reusable module
libGDX: Scene2D
Active Support Core Extensions (1)
Beyond the Callback: Yield Control with Javascript Generators
Unreal Engine Basics 03 - Gameplay
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
st_launcher: Tonel-based Smalltalk shell Scripts
Symfony2 meets propel 1.5
Anatomy of a reusable module

What's hot (20)

PDF
ReUse Your (Puppet) Modules!
PDF
Puppet @ Seat
DOC
Run commands listed below in alphabetical order
PDF
Puppet modules for Fun and Profit
ZIP
Oral presentation v2
PDF
2013 gr8 conf_grails_code_from_the_trenches
PDF
libGDX: Screens, Fonts and Preferences
PPTX
Troubleshooting Puppet
PDF
Vim Script Programming
PDF
Rapid prototyping with ScriptableObjects
KEY
A tour on ruby and friends
PPT
Game programming with Groovy
PPTX
Expression Language 3.0
PDF
Emacs presentation
PDF
Happy Go Programming
PDF
Power of Puppet 4
PDF
Durian: a PHP 5.5 microframework with generator-style middleware
PDF
Kotlin intro
PDF
The event-driven nature of javascript – IPC2012
ReUse Your (Puppet) Modules!
Puppet @ Seat
Run commands listed below in alphabetical order
Puppet modules for Fun and Profit
Oral presentation v2
2013 gr8 conf_grails_code_from_the_trenches
libGDX: Screens, Fonts and Preferences
Troubleshooting Puppet
Vim Script Programming
Rapid prototyping with ScriptableObjects
A tour on ruby and friends
Game programming with Groovy
Expression Language 3.0
Emacs presentation
Happy Go Programming
Power of Puppet 4
Durian: a PHP 5.5 microframework with generator-style middleware
Kotlin intro
The event-driven nature of javascript – IPC2012
Ad

Viewers also liked (10)

PPT
Advances in Game AI
PDF
Computationally Viable Handling of Beliefs in Arguments for Persuasion
KEY
The Strathclyde Poker Research Environment
PDF
Poker, packets, pipes and Python
PDF
"Bwin - P5 a future proof Poker platform"
PPTX
Poker maths
PPT
The Art Of War In Poker
PPTX
Poker in Numbers
PPTX
Minimax
PDF
AI Strategies for Solving Poker Texas Hold'em
Advances in Game AI
Computationally Viable Handling of Beliefs in Arguments for Persuasion
The Strathclyde Poker Research Environment
Poker, packets, pipes and Python
"Bwin - P5 a future proof Poker platform"
Poker maths
The Art Of War In Poker
Poker in Numbers
Minimax
AI Strategies for Solving Poker Texas Hold'em
Ad

Similar to a million bots can't be wrong (20)

PDF
KEY
Introduction to Actor Model and Akka
PDF
Building Massively Scalable application with Akka 2.0
PDF
Akka Actors: an Introduction
PDF
Networks and types - the future of Akka
PDF
A gentle introduction into AKKA and the actor model
PDF
Akka with Scala
PDF
Aglets
PDF
PDF
First glance at Akka 2.0
ODP
Meetup slides
PPTX
Akka Actors
PDF
Model with actors and implement with Akka
PDF
Akka and futures
PDF
Introduction to Actor Model and Akka
PPTX
Concurrency in Scala - the Akka way
PPTX
Scale up your thinking
PDF
Reactive programming with akka
PPTX
The dark side of Akka and the remedy - bp.scala meetup
ZIP
Above the clouds: introducing Akka
Introduction to Actor Model and Akka
Building Massively Scalable application with Akka 2.0
Akka Actors: an Introduction
Networks and types - the future of Akka
A gentle introduction into AKKA and the actor model
Akka with Scala
Aglets
First glance at Akka 2.0
Meetup slides
Akka Actors
Model with actors and implement with Akka
Akka and futures
Introduction to Actor Model and Akka
Concurrency in Scala - the Akka way
Scale up your thinking
Reactive programming with akka
The dark side of Akka and the remedy - bp.scala meetup
Above the clouds: introducing Akka

More from Vasil Remeniuk (20)

PPTX
Product Minsk - РТБ и Программатик
PDF
Работа с Akka Сluster, @afiskon, scalaby#14
PDF
Cake pattern. Presentation by Alex Famin at scalaby#14
PDF
Scala laboratory: Globus. iteration #3
PPTX
Testing in Scala by Adform research
PPTX
Spark Intro by Adform Research
PPTX
Types by Adform Research, Saulius Valatka
PPTX
Types by Adform Research
PPTX
Scalding by Adform Research, Alex Gryzlov
PPTX
Scalding by Adform Research, Alex Gryzlov
PPTX
Spark by Adform Research, Paulius
PPTX
Scala Style by Adform Research (Saulius Valatka)
PPTX
Spark intro by Adform Research
PPTX
SBT by Aform Research, Saulius Valatka
PDF
Scala laboratory: Globus. iteration #2
PPTX
Testing in Scala. Adform Research
PDF
Scala laboratory. Globus. iteration #1
PDF
Cassandra + Spark + Elk
PDF
Опыт использования Spark, Основано на реальных событиях
PDF
ETL со Spark
Product Minsk - РТБ и Программатик
Работа с Akka Сluster, @afiskon, scalaby#14
Cake pattern. Presentation by Alex Famin at scalaby#14
Scala laboratory: Globus. iteration #3
Testing in Scala by Adform research
Spark Intro by Adform Research
Types by Adform Research, Saulius Valatka
Types by Adform Research
Scalding by Adform Research, Alex Gryzlov
Scalding by Adform Research, Alex Gryzlov
Spark by Adform Research, Paulius
Scala Style by Adform Research (Saulius Valatka)
Spark intro by Adform Research
SBT by Aform Research, Saulius Valatka
Scala laboratory: Globus. iteration #2
Testing in Scala. Adform Research
Scala laboratory. Globus. iteration #1
Cassandra + Spark + Elk
Опыт использования Spark, Основано на реальных событиях
ETL со Spark

Recently uploaded (20)

PDF
Encapsulation theory and applications.pdf
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PPTX
Big Data Technologies - Introduction.pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
Encapsulation theory and applications.pdf
Encapsulation_ Review paper, used for researhc scholars
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
MYSQL Presentation for SQL database connectivity
Dropbox Q2 2025 Financial Results & Investor Presentation
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
Chapter 3 Spatial Domain Image Processing.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
“AI and Expert System Decision Support & Business Intelligence Systems”
NewMind AI Monthly Chronicles - July 2025
Mobile App Security Testing_ A Comprehensive Guide.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Big Data Technologies - Introduction.pptx
Network Security Unit 5.pdf for BCA BBA.
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Understanding_Digital_Forensics_Presentation.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Reach Out and Touch Someone: Haptics and Empathic Computing

a million bots can't be wrong

  • 1. a million bots can't be wrong @remeniuk, Viaden Media #ScalaSBP, 18-05-2012
  • 2. In Viaden our aim is to make the best poker ever
  • 3. we know that performance tests should be the first-class citizens
  • 4. and kill 2 birds with one stone, using bots for testing
  • 5.   #1 we can emulate 50k players using just one medium EC2 instance   #2 bots are interactive, so client teams can use them in development, and QA for testing
  • 7. why Scala and Akka is a perfect choice for making bots? actors are !(interactive) straightforward remoting simple scalability/clustering ~30 minutes to make a DSL and CLI with Scala and SBT
  • 8. ..., but, I have to warn you ...
  • 9. 4 dead simple tips for keeping your sanity when you do asynch with Akka 2.0
  • 10. tip #1: live fast, die young
  • 11. typical approach in Akka 1.x lobby desk login l ink bot tourney
  • 12. Akka 1.x: actors have a long lifecycle lobby desk l ink nk bot li un l ink play game bot tourney
  • 13. Akka 1.x: actors have a long lifecycle lobby desk bot k lin bot un tourney play tournament link bot
  • 14. in Akka 2.0 the world has changed props paths new supervision actors
  • 15. now, you're forced to do "the right thing" (c) lobby desk tournament DeskBot desk DeskBot IdleBot
  • 16. all actors are supervised lobby login desk
  • 17. easy come lobby desk play game IdleBot
  • 18. easy go (when supervisor to be changed) lobby desk IdleBot dies DeskBot borns
  • 19. class Lobby extends Actor { case Login(username, password) => context.actorOf(Props(new IdlePokerBot(...))) case JoinAnyDesk(props) => findDesk ! JoinDesk(props) } class Desk extends Actor { case JoinDesk(botProps)=> context.actorOf(Props(new DeskPokerBot(botProps))) } class IdlePokerBot(props: BotProps) extends Actor { case PlayNow => context.parent ! JoinAnyDesk(props); context.stop(self) }
  • 20. Props Pattern - "the soul" of an actor IdleBot BotProps Props remains alive between actor "reincarnations" DeskBot BotProps
  • 21. case class BotProperties(id: Long, login: String, script: Seq[BotEvent], aggressiveness: Int, sessionId: Protocol.SessionId) class IdlePokerBot(val botProperties: BotProperties) extends Bot[Poker] class DeskPokerBot(val botProperties: BotProperties) extends Bot[Poker]
  • 22. tip #2: think beyond
  • 23. when you know, who's supervising, life's simple akka://gpdev/user/lobby/player1234 akka://gpdev/user/lobby/desk1/player1234 akka://gpdev/user/lobby/tournament1/desk1/ player1234
  • 24. Bad news ActorRegistry, actor UUID were removed from Akka but what should I do, now, when I don't know, where to look for my bot?
  • 25. you can make your own registry (using Extensions, backed with a distributed data structure)...
  • 26. or, use the full power of location transparency Projection lobby Manager Projection desk var location: ActorPath DeskBot /projection/player123 IdleBot /lobby/desk123/player123
  • 27. class Projection(var container: ActorPath) extends Actor { def receive = { case newContainer: ActorPath => container = newContainer case msg => context.actorFor(container.child(self.path.name)) ! msg } } class ProjectionManager extends Actor { def receive = { case Add(actor) => context.actorOf(Props(new Projection(actor.path.parent)), actor.path.name) case Forward(msg, path) => context.actorFor(path) ! msg } } projectionManager ! Add(actorRef) projectionManager ! Forward("ping", "actor1")
  • 29. class Projection(var container: ActorPath) extends Actor { def receive = { case newContainer: ActorPath => container = newContainer case msg => context.actorFor(container.child(self.path.name)) ! msg } } class ProjectionManager extends Actor { def receive = { case Add(actor) => context.actorOf(Props(new Projection(actor.path.parent)), actor.path.name) case Forward(msg, path) => context.actorFor(path) ! msg } } projectionManager ! Add(actorRef) system.actorFor(projectionManager.path.child("actor" + i)) ! "ping"
  • 31. class ProjectionManager extends Actor { def receive = { case Add(actor) => context.actorOf(Props(new Projection(actor.path.parent)), actor.path.name) case Forward(msg, path) => context.actorSelection("../*/" + path) ! msg } } val projectionManager = system.actorOf(Props [ProjectionManagerRoutee] .withRouter(RoundRobinRouter(resizer = Some (DefaultResizer(lowerBound = 10, upperBound = 20)))), "projection") projectionManager ! Add(actorRef) projectionManager ! Forward("ping", "actor1")
  • 33. case class CustomRouter(n: Int, routerDispatcher: String = DefaultDispatcherId, supervisorStrategy: SupervisorStrategy = defaultStrategy) extends RouterConfig { def createRoute(props: Props, provider: RouteeProvider) = { provider.registerRoutees((1 to n).map(i => provider.context.actorOf(Props[ProjectionManager], i. toString))) def destination(sender: ActorRef, path: String) = List(Destination(sender, provider.routees(abs(path.hashCode) % n))) { case m@(sender, Add(actor)) ⇒ destination(sender, actor.path.name) case m@(sender, Forward(_, name)) ⇒ destination(sender, name) } } }
  • 35. tip #3: don't do anything stupid
  • 36. you've tried all the options, system load is fine, only 1/10 of the heap is used, but you still can start not more than 1k bots!?
  • 38. your actor is lacking of throughput?               wait before adding pools share responsibility! one fine-grained actor is enough in 99% of the cases
  • 39. 100-300 threads are serving 300 bots!?
  • 40. spawn futures, backed with standalone [bounded] pools, for blocking operations class ThirdPartyWrapper extends Actor { case F(x) => sender ! thirdPartyService.f(x) // call to a function that takes a lot of time to // complete } class ThirdPartyWrapper extends Actor { case F(x) => val _sender = sender Future(thirdPartyService.f(x)).map(_sender ! _) // ugly, but safe, and perfectly right }
  • 41. use separate dispatchers lobby-dispatcher projection-manager-dispatcher PinnedDispatcher BalancingDispatcher lobby Projection Manager desk Projection   DeskBot projection-dispatcher container-dispatcher desk-bot-dispatcher Dispatcher Dispatcher Dispatcher
  • 42. GOTCHA: Akka successfully bootstraps, even if your dispatcher is not configured, or the config is wrong   Always check the logs to make sure that dispatchers are used! [WARN][gpdev-akka.actor.default-dispatcher-1] [Dispatchers] Dispatcher [bot-system.container-dispatcher] not configured, using default-dispatcher [WARN][gpdev-bot-system.container-dispatcher-1] [PinnedDispatcherConfigurator] PinnedDispatcher [bot- system.lobby-dispatcher] not configured to use ThreadPoolExecutor, falling back to default config. [DEBUG][gpdev-akka.actor.default-dispatcher-24] [akka: //gpdev/user/poker/lobby] logged in [DEBUG][gpdev-akka.actor.default-dispatcher-14] [akka: //gpdev/user/poker/projeciton/$g/player20013] starting projection...
  • 44. how to measure?   Metrics - pushes various collected metrics to Graphite Carbon and Graphite - gather metrics, and expose them via web interface  
  • 45. object BotMetrics { 1. val loggedInCount = new Counter(Metrics.newCounter(classOf[Lobby [_]], "logged-in-count")) 3. GraphiteReporter.enable(1, TimeUnit.MINUTES, "localhost", 2003) } class Lobby extends Actor { 2. case Login(username, pass) => BotMetrics.loggedInCount += 1 } 1. add logged-in user counter 4. 2. update it 3. enable reporting to Graphite 4. build a graph in Grtaphite
  • 46. what to measure?   - mailbox size1 - throughput - time, before the message is processed (both in actor and future)2 - time to process a message - count of threads - actor pool size - heap size 1 requires implementation of a custom mailbox that can expose mailbox size 2 every message should be stuffed with a timestamp
  • 47. how to tune dispatchers?   VisualVM - thread timeline shows, if thread polls behind dispatchers are used effectively  
  • 48. don't neglect old good logging   [ERROR][05/06/2012 12:55:43.826] [gpdev-bot-system. desk-bot-dispatcher-7] [akka://gpdev/user/ poker/lobby/tournament5382577/desk109129/player2012 1] unprocessed game event: GameEvent(CHAT,None,None)