SlideShare a Scribd company logo
1 of 50
Download to read offline
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")
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"
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")
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)
        }
    }

}
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

What's hot

Run commands listed below in alphabetical order
Run commands listed below in alphabetical orderRun commands listed below in alphabetical order
Run commands listed below in alphabetical order
Kondareddy Settipalli
 
Oral presentation v2
Oral presentation v2Oral presentation v2
Oral presentation v2
Yeqi He
 
2013 gr8 conf_grails_code_from_the_trenches
2013 gr8 conf_grails_code_from_the_trenches2013 gr8 conf_grails_code_from_the_trenches
2013 gr8 conf_grails_code_from_the_trenches
Edwin van Nes
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script Programming
Lin Yo-An
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琦 潘
 
The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012
Martin Schuhfuß
 

What's hot (20)

ReUse Your (Puppet) Modules!
ReUse Your (Puppet) Modules!ReUse Your (Puppet) Modules!
ReUse Your (Puppet) Modules!
 
Puppet @ Seat
Puppet @ SeatPuppet @ Seat
Puppet @ Seat
 
Run commands listed below in alphabetical order
Run commands listed below in alphabetical orderRun commands listed below in alphabetical order
Run commands listed below in alphabetical order
 
6202942
62029426202942
6202942
 
Puppet modules for Fun and Profit
Puppet modules for Fun and ProfitPuppet modules for Fun and Profit
Puppet modules for Fun and Profit
 
Oral presentation v2
Oral presentation v2Oral presentation v2
Oral presentation v2
 
2013 gr8 conf_grails_code_from_the_trenches
2013 gr8 conf_grails_code_from_the_trenches2013 gr8 conf_grails_code_from_the_trenches
2013 gr8 conf_grails_code_from_the_trenches
 
libGDX: Screens, Fonts and Preferences
libGDX: Screens, Fonts and PreferenceslibGDX: Screens, Fonts and Preferences
libGDX: Screens, Fonts and Preferences
 
Troubleshooting Puppet
Troubleshooting PuppetTroubleshooting Puppet
Troubleshooting Puppet
 
Vim Script Programming
Vim Script ProgrammingVim Script Programming
Vim Script Programming
 
Rapid prototyping with ScriptableObjects
Rapid prototyping with ScriptableObjectsRapid prototyping with ScriptableObjects
Rapid prototyping with ScriptableObjects
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
Game programming with Groovy
Game programming with GroovyGame programming with Groovy
Game programming with Groovy
 
Expression Language 3.0
Expression Language 3.0Expression Language 3.0
Expression Language 3.0
 
Emacs presentation
Emacs presentationEmacs presentation
Emacs presentation
 
Happy Go Programming
Happy Go ProgrammingHappy Go Programming
Happy Go Programming
 
Power of Puppet 4
Power of Puppet 4Power of Puppet 4
Power of Puppet 4
 
Durian: a PHP 5.5 microframework with generator-style middleware
Durian: a PHP 5.5 microframework with generator-style middlewareDurian: a PHP 5.5 microframework with generator-style middleware
Durian: a PHP 5.5 microframework with generator-style middleware
 
Kotlin intro
Kotlin introKotlin intro
Kotlin intro
 
The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012The event-driven nature of javascript – IPC2012
The event-driven nature of javascript – IPC2012
 

Similar to Василий Ременюк «Курс молодого подрывника»

GR8Conf 2011: GPars
GR8Conf 2011: GParsGR8Conf 2011: GPars
GR8Conf 2011: GPars
GR8Conf
 
Akka: Distributed by Design
Akka: Distributed by DesignAkka: Distributed by Design
Akka: Distributed by Design
patriknw
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
David Padbury
 

Similar to Василий Ременюк «Курс молодого подрывника» (20)

Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
 
First glance at Akka 2.0
First glance at Akka 2.0First glance at Akka 2.0
First glance at Akka 2.0
 
GR8Conf 2011: GPars
GR8Conf 2011: GParsGR8Conf 2011: GPars
GR8Conf 2011: GPars
 
XRobots
XRobotsXRobots
XRobots
 
Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"Let'swift "Concurrency in swift"
Let'swift "Concurrency in swift"
 
Current State of Coroutines
Current State of CoroutinesCurrent State of Coroutines
Current State of Coroutines
 
Akka JUGL 2012
Akka JUGL 2012Akka JUGL 2012
Akka JUGL 2012
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
Online game server on Akka.NET (NDC2016)
Online game server on Akka.NET (NDC2016)Online game server on Akka.NET (NDC2016)
Online game server on Akka.NET (NDC2016)
 
The dark side of Akka and the remedy - bp.scala meetup
The dark side of Akka and the remedy - bp.scala meetupThe dark side of Akka and the remedy - bp.scala meetup
The dark side of Akka and the remedy - bp.scala meetup
 
ruby2600 - an Atari 2600 emulator written in Ruby
ruby2600 - an Atari 2600 emulator written in Rubyruby2600 - an Atari 2600 emulator written in Ruby
ruby2600 - an Atari 2600 emulator written in Ruby
 
Golang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war storyGolang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war story
 
Akka (BeJUG)
Akka (BeJUG)Akka (BeJUG)
Akka (BeJUG)
 
Clojure 1.1 And Beyond
Clojure 1.1 And BeyondClojure 1.1 And Beyond
Clojure 1.1 And Beyond
 
Akka Actors: an Introduction
Akka Actors: an IntroductionAkka Actors: an Introduction
Akka Actors: an Introduction
 
From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017From Elixir to Akka (and back) - ElixirConf Mx 2017
From Elixir to Akka (and back) - ElixirConf Mx 2017
 
Akka: Distributed by Design
Akka: Distributed by DesignAkka: Distributed by Design
Akka: Distributed by Design
 
RxJS101 - What you need to know to get started with RxJS tomorrow
RxJS101 - What you need to know to get started with RxJS tomorrowRxJS101 - What you need to know to get started with RxJS tomorrow
RxJS101 - What you need to know to get started with RxJS tomorrow
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and ScalaFunctional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
 

More from e-Legion

More from e-Legion (20)

MBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, PureMBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, Pure
 
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricaMBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetrica
 
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba MobileMBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba Mobile
 
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha RestoranyMBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha Restorany
 
MBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500StartupsMBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500Startups
 
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, AviasalesMBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, Aviasales
 
MBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank OnlineMBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank Online
 
Rx Java architecture
Rx Java architectureRx Java architecture
Rx Java architecture
 
Rx java
Rx javaRx java
Rx java
 
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, SpotifyMBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, Spotify
 
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, WunderlistMBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, Wunderlist
 
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, SoundcloudMBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, Soundcloud
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, PostforpostMBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, Postforpost
 
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, ParallelsMBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, Parallels
 
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITMBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DIT
 
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, LitresMBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, Litres
 
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box
 
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, MicrosoftMBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, Microsoft
 
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
 

Recently uploaded

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Recently uploaded (20)

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 

Василий Ременюк «Курс молодого подрывника»

  • 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")
  • 28.
  • 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"
  • 30.
  • 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")
  • 32.
  • 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) } } }
  • 34.
  • 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)