Введение в Akka

2,944 views

Published on

Published in: Technology

Введение в Akka

  1. 1. Ресурсы • Оф. сайт – http://akka.io • Документация – http://doc.akka.io/docs/akka/snapshot/ • ScalaDoc – http://doc.akka.io/api/akka/snapshot/ • Введение (30 минут) – Typesafe Activator template “Hello Akka!” • Курс (8 часов) – Principles of Reactive Programming (Weeks 5,6,7) • Реактивный манифест – http://habrahabr.ru/post/195562/ • Книга (не введение) – Effective Akka: Patterns and Best Practices by Jamie Allen
  2. 2. Модули Akka akka-actor – Classic Actors, Typed Actors, IO Actor etc. akka-agent – Agents, integrated with Scala STM akka-camel – Apache Camel integration akka-cluster – Cluster membership management, elastic routers. akka-kernel – Akka microkernel for running a bare-bones mini application server akka-osgi – base bundle for using Akka in OSGi containers, containing the akka-actor classes akka-osgi-aries – Aries blueprint for provisioning actor systems akka-remote – Remote Actors akka-slf4j – SLF4J Logger (event bus listener) akka-testkit – Toolkit for testing Actor systems akka-zeromq – ZeroMQ integration
  3. 3. Примеры • spray – веб-сервер и фреймворк для написания HTTP/REST приложений • xitrum – веб-фреймворк • Klout – сервис анализ социальных связей • Amazon • Blizzard • Autodesk • ...
  4. 4. Проблема Блокирующие вызовы: • Blocking IO • Примитивы синхронизации (мьютексы, семафоры, CountDownLatch, …) • Thread.sleep() • Future.get() Итог: • Простаивание ресурсов • Дедлоки • Сильная связанность компонентов • Ухудшается отзывчивость системы • Теряется возможность масштабирования
  5. 5. Решение Решение – акторы, взаимодействующие между собой асинхронно посредством сообщений (и только сообщений). Акторы похожи на людей в комнате, говорящих друг с другом.
  6. 6. Решение Решение – акторы, взаимодействующие между собой асинхронно посредством сообщений (и только сообщений). Акторы похожи на людей в комнате, говорящих друг с другом.
  7. 7. Actor trait type Receive = PartialFunction[Any, Unit] trait Actor { def receive: Receive = ??? ... }
  8. 8. Пример Actor’а class Time extends Actor { def receive = { case "What is the time?" => sender ! "12:43" } }
  9. 9. Пример stateful Actor’а class Counter extends Actor { var count = 0 def receive = { case "incr" => count += 1 case ("get", customer: ActorRef) => customer ! count } }
  10. 10. Демонстрация Parent BankAccount
  11. 11. Демонстрация Parent BankAccount akka://Main/user/app#-1327529947 akka://Main/user/app/acc1#1803679474
  12. 12. Stopping Actors context.stop(actor) actor ! PoisonPill или В обоих случаях посылается сообщение. В первом случае все сообщения в очереди выбрасываются. Во втором – сообщение кладется в конец очереди.
  13. 13. Закрепим знания • Все акторы инкапсулированы и независимы (больше инкапсуляции, чем в традиционном ООП). Нету способа взаимодействия с акторами кроме отправки сообщений. • Сообщения должны быть иммутабельными. • Избегать блокировок в акторах. Нужно использовать асинхронное API для работы с файлами, БД, … • Отправка сообщений не является надёжной. • Порядок отправки и принятия сообщений неопределён (кроме случая, когда актор посылает другому актору подряд сообщения).
  14. 14. Иерархии акторов Большая корпорация Отдел маркетинга Бухгалтерия Отдел разработки Проект1 БД UI Напоминают иерархию большой корпорации
  15. 15. Supervision Большая корпорация Отдел маркетинга Бухгалтерия Отдел разработки Проект1 БД UI Напоминают иерархию большой корпорации
  16. 16. Supervision Большая корпорация Отдел маркетинга Бухгалтерия Отдел разработки Проект1 БД UI Напоминают иерархию большой корпорации
  17. 17. Supervision Большая корпорация Отдел маркетинга Бухгалтерия Отдел разработки Проект1 БД UI Напоминают иерархию большой корпорации Принимает решение
  18. 18. Supervision class Manager extends Actor { override val supervisorStrategy = OneForOneStrategy() { case _: DBException => Restart // reconnect to DB case _: NullPointerException => Stop case _: ServiceDownException => Escalate } def receive = ??? }
  19. 19. Жизненный цикл Actor’а • start • (restart)* • stop
  20. 20. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…)
  21. 21. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor
  22. 22. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart
  23. 23. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart
  24. 24. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart
  25. 25. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart
  26. 26. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart new Actor
  27. 27. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart new Actor postRestart
  28. 28. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart new Actor postRestart stop
  29. 29. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart new Actor postRestart stop Stop postStop
  30. 30. Жизненный цикл Actor’а • start • (restart)* • stop context.actorOf(…) new Actor preStart Restart preRestart new Actor postRestart stop Stop postStop Может произойти *0, ∞) раз
  31. 31. Закрепим знания • Акторы организуются в иерархии. • Акторы обязаны обрабатывать ошибки своих дочерних акторов. Тем самым достигается отказоустойчивость системы. • Рестарты акторов не наблюдаемы из внешнего мира. • При рестарте актора рестартуется всё его поддерево. • Рестарты в листьях дерева иерархии происходят чаще. • Рискованные задачи желательно делегировать дочерним акторам, если родительский актор имеет важное состояние.
  32. 32. Поиск акторов class MyActor extends Actor { val path = "/user/app/b" context.actorSelection(path) ! Identify(42) def receive = { case ActorIdentity(42, Some(actorRef)) => { println(s"Actor with $path found: $actorRef") } case ActorIdentity(42, None) => { println(s"Actor with $path not found") } } }
  33. 33. Поиск акторов context.actorSelection("/user/app/b") context.actorSelection("child") context.actorSelection("../sibling") context.actorSelection("akka.tcp://Main@host:port/user/app/b") context.actorSelection("/user/app/*") Поиск по абсолютному пути: Поиск дочернего актора: Поиск соседнего актора: Поиск удалённого актора: Поиск по wildcard’ам:
  34. 34. Маршрутизация Router Routee1 Routee2 Routee3 ? ? ?
  35. 35. Round Robin Router Routee1 Routee2 Routee3
  36. 36. Round Robin Router Routee1 Routee2 Routee3
  37. 37. Round Robin Router Routee1 Routee2 Routee3
  38. 38. Round Robin Router Routee1 Routee2 Routee3
  39. 39. Round Robin Router Routee1 Routee2 Routee3
  40. 40. Round Robin • Сообщения должны быть равнозначными. • Воркеры должны быть равнозначными.
  41. 41. Random Router Routee1 Routee2 Routee3
  42. 42. Random Router Routee1 Routee2 Routee3
  43. 43. Random Router Routee1 Routee2 Routee3
  44. 44. Random Router Routee1 Routee2 Routee3
  45. 45. Random Router Routee1 Routee2 Routee3
  46. 46. Random • Может вызвать разбалансировку. • Применимо, когда bottleneck в самом маршрутизаторе. • Применимо, когда есть несколько маршрутизаторов. • Воркеры должны быть равнозначными. • Сообщения должны быть равнозначными.
  47. 47. Smallest mailbox Router Routee1 Routee2 Routee3
  48. 48. Smallest mailbox Router Routee1 Routee2 Routee3
  49. 49. Smallest mailbox • Равномерная балансировка. • Сообщения должны быть равнозначными. • Неприменимо для удалённых воркеров. • Относительно высокая цена маршрутизации – нужно каждый раз считать размер очереди.
  50. 50. Broadcast Router Routee1 Routee2 Routee3
  51. 51. Broadcast Router Routee1 Routee2 Routee3
  52. 52. Broadcast Router Routee1 Routee2 Routee3
  53. 53. Broadcast • Можно назначать различные задачи. • Повышается надежность (некоторые воркеры могут упасть при выполнении задач). • Требуется в n раз больше ресурсов, где n – количество воркеров.
  54. 54. ScatterGatherFirstCompletedOf Router Routee1 Routee2 Routee3
  55. 55. ScatterGatherFirstCompletedOf Router Routee1 Routee2 Routee3 Самый быстрый ответ (остальные отвергаются)
  56. 56. ScatterGatherFirstCompletedOf • Применимо, когда нужно получить ответ как можно скорее. • Требуется в n раз больше ресурсов, где n – количество воркеров.
  57. 57. Consistent Hash Router Routee1 Routee2 Routee3
  58. 58. Consistent Hash Router Routee1 Routee2 Routee3
  59. 59. Consistent Hash Router Routee1 Routee2 Routee3
  60. 60. Consistent Hash Router Routee1 Routee2 Routee3
  61. 61. Consistent Hash Router Routee1 Routee2 Routee3
  62. 62. Consistent Hash • Задачи одного и того же типа отправляются одним и тем же воркерам. • Позволяет избежать разделяемого состояния между воркерами. Например, сообщения, относящиеся к одному и тому же пользователю, всегда будут обработаны одним и тем же актором. • Не гарантирует равномерность нагрузки.
  63. 63. Закрепим знания • Асинхронная передача сообщений обеспечивает вертикальное масштабирование: обрабатывая сообщение, актор не блокирует его, а уступает поток для обработки следующего сообщения. • Прозрачность местонахождения акторов (location transparency) обеспечивает горизонтальное масштабирование.
  64. 64. Нетронутые темы • Кластеризация • Персистентность • Мониторинг жизненного цикла акторов • Конечные автоматы (FSM) • Spray – фреймворк для разработки HTTP/REST приложений • Тестирование акторов • Работа с TCP/UDP • Агенты • Интеграция с Apache Camel • ...
  65. 65. Спасибо за внимание!

×