Skip to content

Latest commit

 

History

History
190 lines (142 loc) · 5.39 KB

akka.md

File metadata and controls

190 lines (142 loc) · 5.39 KB

簡介

Akka是一套用於構建彈性(scalable)、可擴展(resilient)、分佈式(distributed)系統的開源庫。 Akka讓用戶專注於業務需求(business needs),而非編寫底層代碼來提供可靠的行爲(reliable behavior)、容錯性(fault tolerance)、高性能(high performance)。

Akka Actor

Akka Actor提供了Actor模型在JVM上的實現。

Actor模型爲編寫高併發、分佈式系統提供了高級的抽象。 Actor模型緩解了併發編程中的鎖和線程管理等問題,讓開發者能夠簡單、正確地構建並行系統。

Actor模型最初由Carl Hewitt1973年的論文中提出,之後由Ericsson開發的Erlang實現, 在構建高併發、高可靠性的電信系統中有着成功的應用。 Akka Actor提供了與Erlang Actor類似的語法。

Akka Actor現在是Lightbend官方推薦的Actor實現,原先標準庫中提供的Scala ActorScala 2.10版本後已被廢棄。

配置 Akka Actor

在sbt項目的build.sbt中添加依賴:

"com.typesafe.akka" %% "akka-actor" % "版本號"

定義 Actor

在包路徑akka.actor下定義了Actor的相關類型。 自定義Actor應繼承/混入akk.actor.Actor特質,示例:

import akka.actor.Actor

class MyActor extends Actor {

  def receivce: Receive = {
    case ... => ...
    case _ => ...
  }

}

自定義Actor應重寫receive方法,在receive方法中提供消息處理邏輯。 receive方法爲無參方法,返回值類型爲akka.actor.Actor.Receive。 定義在Actor特質的伴生對象中:

object Actor {
  ...
  /**
   * Type alias representing a Receive-expression for Akka Actors.
   */
  //#receive
  type Receive = PartialFunction[Any, Unit]
  ...
}

Actor.Receive類型實際爲Any => Unit簽名的偏函數

創建 Actor

自定義的Actor類型子類並不能直接構造實例使用,而是需要通過ActorSystem管理、創建出對應的ActorRef引用進行操作。

使用ActorSystemProps創建ActorRef,基本代碼示例:

import akka.actor._

val actorSystem = ActorSystem()
val xxxActor = actorSystem.actorOf(Props[XxxActor])
...

ActorSystem類提供了對Actor的管理、調度。 創建ActorRef需要首先構建ActorSystem實例,ActorSystem類的伴生對象提供了apply()方法用於構建實例:

object ActorSystem {
  ...
  def apply(): ActorSystem = apply("default")
  def apply(name: String): ActorSystem
  def apply(name: String, setup: ActorSystemSetup): ActorSystem
  ...
}

不同的ActorSystem以名字作爲區分,不填寫名稱參數時,默認名稱爲default。 ActorSystem有較大系統開銷,不應反覆構造過多的ActorSystem實例。

Props類提供了Actor的配置。 無構造器參數的Actor可直接使用Props伴生對象中的空參apply()方法生成默認Actor配置, 構造器帶有參數的Actor應使用Props伴生對象中的其它apply()方法的重載形式, 顯式傳入構造器參數/Actor實例構造Props配置。 相關方法定義如下:

object Props extends AbstractProps {
  ...
  def apply[T <: Actor: ClassTag](): Props
  def apply[T <: Actor: ClassTag](creator:  T): Props
  def apply(clazz: Class[_], args: Any*): Props
  ...
}

構建Props實例:

class MyActor extends Actor {

  def this(xxx: String) {
    this
    ...
  }

}

val props = Props[MyActor] //使用無參構造器
val propsWithArgs = Props(classOf[MyActor], "xxxx") //使用參數有參構造器
val propsWithInstance = Props(new MyActor("xxxx")) //直接使用Actor實例

ActorSystem類繼承了ActorRefFactory特質,該特質提供了actorOf()方法, 可通過Props實例構建對應的ActorRef,相關方法定義如下:

abstract class ActorSystem extends ActorRefFactory {
  ...
}

trait ActorRefFactory {
  ...
  def actorOf(props: Props): ActorRef
  def actorOf(props: Props, name: String): ActorRef
  ...
}

除了直接通過ActorSystem創建頂層ActorRef外,亦可在Actor定義內部創建ActorRef。

Actor類型內定義了隱式成員content,通過content成員可以獲取當前Actor的ActorContent實例, 通過ActorContent實例的actorOf()方法可創建新的ActorRefActorContent特質繼承了ActorRefFactory特質,ActorRefFactory特質中同樣定義了actorOf()方法用於創建ActorRef。 相關源碼如下:

trait Actor {
  ...
  implicit val context: ActorContext //通過 context 成員獲取 ActorContent 實例
  ...
}

trait ActorContext extends ActorRefFactory {
  ...
}

trait ActorRefFactory {
  ...
  def actorOf(props: Props): ActorRef
  def actorOf(props: Props, name: String): ActorRef
  ...
}

問題註記

記錄一些Akka開發中遇到的問題。

Akka HTTP 文件緩存問題

問題描述:
使用Akka HTTP返回本地文件做爲請求響應時,Tomcat會在/tmp/tomcat...路徑下緩存該文件。 當本地文件內容更新後,Akka HTTP依舊返回Tomcat緩存路徑中的舊文件,請求端依舊得到舊文件。

解決方案:
刪除Tomcat緩存目錄/tmp/tomcat...