Проектирование акторных систем
Научитесь проектировать и реализовывать иерархии акторов, определять их поведение и отправлять и получать сообщения.
«Проектирование акторных систем» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 2 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.
Проектирование систем акторов: введение
Добро пожаловать на урок 2! На предыдущем уроке мы изучили основы модели акторов Akka. Теперь давайте подробно рассмотрим проектирование систем акторов Akka.
Хорошо спроектированная система акторов надёжна, масштабируема и удобна в сопровождении. Мы рассмотрим, как структурировать акторы, определять их поведение и обеспечивать эффективный обмен данными между ними.
Устройство иерархий акторов
Акторы Akka организованы в древовидную иерархию, подобную файловой системе. У каждого актора, кроме «корневого» актора, есть родитель.
- Связь родитель—потомок: Актор, создающий другой актор, становится его родителем.
- Надзор: Эта иерархия крайне важна для отказоустойчивости Akka. Родители отвечают за надзор над своими потомками (подробнее об этом — в следующем уроке!).
- Адресация по пути: У каждого актора есть уникальный путь, отражающий его положение в иерархии, например
/user/parentActor/childActor.
Настройка ActorSystem
ActorSystem — точка входа для всех приложений Akka. Она управляет ресурсами, необходимыми акторам, включая пулы потоков и планировщики.
Вы создаёте её один раз для каждого приложения, а затем используете для создания акторов верхнего уровня. Это своего рода контейнер для всего приложения акторов.
Попробуйте запустить этот простой код для создания ActorSystem:
import akka.actor.ActorSystem
object AkkaSystemApp {
def main(args: Array[String]): Unit = {
// Create an ActorSystem with a unique name
val system = ActorSystem("MyFirstActorSystem")
println("ActorSystem created: " + system.name)
// Remember to terminate the system when done!
system.terminate()
}
}Определение поведения актора
Поведение актора определяет его реакцию на различные сообщения. В Scala оно определяется путём расширения трейта Actor и реализации метода receive.
- Метод
receive— это частичная функция, сопоставляющая входящие сообщения с определёнными действиями. - Каждый актор обрабатывает сообщения по одному, последовательно, что обеспечивает потокобезопасность его внутреннего состояния.
ActorRef: адрес актора
Вы не взаимодействуете с экземплярами акторов напрямую. Вместо этого Вы отправляете сообщения в ActorRef. Представляйте ActorRef как почтовый адрес актора.
- Это дескриптор, представляющий определённый актор внутри системы.
- Сообщения, отправленные в
ActorRef, помещаются в почтовый ящик актора. - Вы получаете
ActorRefпри создании актора с помощьюactorOf.
Отправка сообщений акторам
Основной способ взаимодействия акторов — отправка сообщений. Чаще всего сообщение отправляют с помощью метода ! (произносится «tell»).
receiverActorRef ! "Your message here"
Метод tell является асинхронным и работает по принципу «отправил и забыл». Он отправляет сообщение и не ждёт ответа.
Объединим создание актора и отправку ему сообщений:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
// 1. Define the actor's behavior
class GreeterActor extends Actor {
def receive = {
case "hello" => println(s"Greeter: Hello from ${self.path.name}!")
case msg: String => println(s"Greeter: Received message: '$msg'")
case _ => println("Greeter: Received something unexpected!")
}
}
object SimpleActorApp {
def main(args: Array[String]): Unit = {
// 2. Create the ActorSystem
val system = ActorSystem("GreeterSystem")
// 3. Create a top-level actor and get its ActorRef
val greeter: ActorRef = system.actorOf(Props[GreeterActor], "myGreeter")
// 4. Send messages to the actor using '!'
greeter ! "hello"
greeter ! "How are you doing today?"
greeter ! 123 // This will match the _ case
// Give actors time to process messages, then terminate
Thread.sleep(1000)
system.terminate()
}
}Создание дочерних акторов
Акторы могут создавать другие акторы, формируя рассмотренную нами иерархию. Родительский актор создаёт дочерние акторы с помощью context.actorOf.
context.actorOf: используется актором для создания потомков.system.actorOf: используется приложением для создания акторов верхнего уровня (стражей).
Создание дочерних акторов помогает организовать систему, делегировать задачи и изолировать сбои.
Взаимодействие родителя и потомка
Акторы взаимодействуют, отправляя сообщения в ActorRef друг друга. Дочерний актор может получить ActorRef родителя через context.parent. Чтобы ответить отправителю сообщения, актор может использовать sender().
Рассмотрим пример, в котором родитель создаёт потомка, поручает ему выполнить работу, а потомок сообщает о завершении:
import akka.actor.{Actor, ActorRef, Props, ActorSystem}
import scala.concurrent.ExecutionContext.Implicits.global
// Child Actor Definition: Does work and replies to sender
class ChildActor extends Actor {
def receive = {
case "work" =>
println(s"ChildActor (${self.path.name}): Doing work from ${sender().path.name}")
sender() ! "done" // Reply 'done' to the sender (parent)
}
}
// Parent Actor Definition: Creates child, sends work, receives reply
class ParentActor extends Actor {
// Create a child actor when the parent starts
val child: ActorRef = context.actorOf(Props[ChildActor], "myChild")
def receive = {
case "start" =>
println("ParentActor: Kicking off child's work.")
child ! "work" // Tell the child to do 'work'
case "done" =>
println(s"ParentActor: Child ${sender().path.name} reported 'done'.")
context.stop(child) // Stop the child actor
context.stop(self) // Stop the parent actor
}
}
object HierarchyApp {
def main(args: Array[String]): Unit = {
val system = ActorSystem("HierarchySystem")
val parent: ActorRef = system.actorOf(Props[ParentActor], "parentActor")
parent ! "start" // Start the interaction
// Wait for the system to terminate (actors will stop themselves)
system.whenTerminated.onComplete(_ => println("ActorSystem terminated."))
}
}Корректная остановка акторов
Акторы следует корректно останавливать, когда они больше не нужны, чтобы освободить ресурсы. Остановить актора можно несколькими способами:
context.stop(self): актор останавливает себя сам.context.stop(childRef): родитель останавливает одного из своих потомков.system.stop(actorRef): используется для акторов верхнего уровня, хотя обычно останавливают всю систему.
При остановке актор обрабатывает все сообщения в своём почтовом ящике перед завершением. Его потомки также останавливаются рекурсивно.
Быстрая проверка: проектирование акторов
Рассмотрите следующий фрагмент кода актора Akka. Как MyChildActor должен отправить сообщение обратно своему создавшему его родителю MyParentActor, если MyParentActor был отправителем исходного сообщения «request»?
Повторение: проектирование систем акторов
Отличная работа! В этом уроке мы рассмотрели ключевые аспекты проектирования систем акторов Akka:
- Акторы организованы в иерархии, которые необходимы для надзора и структурирования.
ActorSystem— точка входа приложения в Akka.- Вы определяете поведение актора с помощью метода
receive. ActorRef— адрес для отправки сообщений.- Акторы взаимодействуют асинхронно с помощью метода
!(tell). - Родители создают потомков с помощью
context.actorOf, а потомки могут отвечать с помощьюsender(). - Акторов можно корректно остановить с помощью
context.stop().
Далее мы подробнее рассмотрим мощные стратегии надзора Akka и способы корректной обработки сбоев!
Часто задаваемые вопросы
Урок «Проектирование акторных систем» бесплатный?
Да — полный текст урока «Проектирование акторных систем» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 3 уроков всего.
Чему я научусь в уроке «Проектирование акторных систем»?
Научитесь проектировать и реализовывать иерархии акторов, определять их поведение и отправлять и получать сообщения. Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?
Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 3.
Сколько времени занимает урок «Проектирование акторных систем»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?
Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы акторной модели Akka
- Проектирование акторных систем
- Супервизия и отказоустойчивость