技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

Akka について勉強する。

終了まで随時更新
教科書はこれ
http://www.slideshare.net/scalaconfjp/scaling-software-with-akka

概要から読んでいく。
重要そうな箇所だけまずはメモ

Program at higher level

  • 共有するステータス、ステータスの可視性、スレッド、ロック、同期、スレッドの通知など等を考えない
  • 低レベルの並列動作*1はシンプルなワークフローに落ちる。プログラマはシステムのメッセージフローだけ考えればいい。
  • 高レベルなCOUユーティリティ、低レイテンシ、高スループットとスケーラビリティを簡単に得られる
  • エラーを検出し、回復するための実証済みの優れたモデルの提供

Distributable by Design

  • Actor はロケーション透過性と配布可能なデザインをしている
  • スケールアップ・ダウンが容易
  • クラウドにおける完璧な構造

これらをAkkaが実現すると。

What is an Actor?

  • コード構成を含むAkkaユニットをActorという
  • Actorでは、並列的、スケーラブルでフォールトトレラントなアプリケーションを作成するのに役立ちます
  • Java EE servlets と session beans のように、ビジネスロジックから様々な決定すべきポリシーを切り離す
  • Actor は多くのJavaコミュニティにとって新しいものかもしれない、だが、電気通信システムと9 nines *2によって、長年にわたって実証されてきたコンセプト(Hewitt 1973)です

What can I use Actors for?(何に使うの?)

  • a thread
  • an object instance or component
  • a callback or listener
  • a singleton or service
  • a router, load-balancer or pool
  • a Java EE Session Bean or Message-Driven Bean
  • an out-of-process service
  • a Finite State Machine (FSM)

4 core Actor operations

  1. DEFINE
  2. CREATE
  3. SEND
  4. BECOME
  5. SUPERVISE

昨日寝ちゃったので続き


CREATE

説明いらんよね。

import akka.actor.{ActorLogging, Props, Actor, ActorSystem}
import org.slf4j.LoggerFactory

case class Greeting(who: String)

class GreetingActor extends Actor with ActorLogging {
  def receive = {
    case Greeting(who) => log.info("Hello " + who)
  }
}

object Sample extends App {
  val logger = LoggerFactory.getLogger("timeLogging")

  val system = ActorSystem("SampleSystem")
  val greeter = system.actorOf(Props[GreetingActor], name = "greeter")
}

system.actorOf を使ってActorRef を得るが、階層構造を作る場合、Actor 内で context.actorOf で Actor を拾えばよい。
その階層構造はディレクトリ型の名前解決でアクセスできる。

SEND

Actor にメッセージを通知する。非同期かつブロックせずに動作可能だ。

greeter ! Greeting("White azalea")

ROUTERS

てかルータって何なのか説明がないのでどういうものなのか?
http://doc.akka.io/docs/akka/snapshot/java/routing.html

ルータは、メッセージを受信して、効率的にrouteesとして知られている他のアクターにルーティングするアクターである。
異なるルーティング戦略をアプリケーションのニーズに応じて使用することができる。
作ることもできるお。

デフォだとこんなんあるぜよ

akka.routing.RoundRobinRouter
akka.routing.RandomRouter
akka.routing.SmallestMailboxRouter
akka.routing.BroadcastRouter
akka.routing.ScatterGatherFirstCompletedRouter
akka.routing.ConsistentHashingRouter

とな。まぁ名前の通りで安心しました。

  val greeter = system.actorOf(
    Props[GreetingActor].withRouter(RoundRobinRouter(nrOfInstances = 5)),
    name = "greeter")

Router+Resizer

Resizer とは何ぞや?→さっきのURL

動的にサイズ変更可能なルータ
Dynamically Resizable Routers
rutouters はこ定数の routees やリサイズ戦略、routees数の調整を行うことができます。
All routers can be used with a fixed number of routees or with a resize strategy to adjust the number of routees dynamically.

  val system = ActorSystem("SampleSystem")
  val resizer = DefaultResizer(lowerBound=2, upperBound = 15)
  val greeter = system.actorOf(
    Props[GreetingActor].withRouter(RoundRobinRouter(resizer = Some(resizer))),
    name = "greeter")

もしくは設定ファイルからいける。
これはやったはず。

akka.actor.deployment {
    /greeter {
        router = round-robin
        resizer {
            lower-bound = 8
            upper-bound = 15
        }
    }
}

実行してみる

[info] Compiling 1 Scala source to C:\common\projects\AkkaSample\target\scala-2.10\classes...
[info] Running Sample
[INFO] [04/07/2013 18:30:32.334] [SampleSystem-akka.actor.default-dispatcher-5] [akka://SampleSystem/user/greeter/$a] Hello alpha
[INFO] [04/07/2013 18:30:32.353] [SampleSystem-akka.actor.default-dispatcher-1] [akka://SampleSystem/user/greeter/$b] Hello bravo
[INFO] [04/07/2013 18:30:32.354] [SampleSystem-akka.actor.default-dispatcher-1] [akka://SampleSystem/user/greeter/$b] Hello delta
[INFO] [04/07/2013 18:30:32.354] [SampleSystem-akka.actor.default-dispatcher-5] [akka://SampleSystem/user/greeter/$a] Hello cherie
[INFO] [04/07/2013 18:30:32.355] [SampleSystem-akka.actor.default-dispatcher-1] [akka://SampleSystem/user/greeter/$b] Hello foxtrot
[INFO] [04/07/2013 18:30:32.355] [SampleSystem-akka.actor.default-dispatcher-5] [akka://SampleSystem/user/greeter/$a] Hello echo
[INFO] [04/07/2013 18:30:32.356] [SampleSystem-akka.actor.default-dispatcher-5] [akka://SampleSystem/user/greeter/$a] Hello golf

BECOME

  • BECOME - 動的なアクターの再定義
  • メッセージ受信による応答のトリガー
  • In a type system analogy it is as if the object changed type - changed interface, protocol & implementation*3
  • それらがメッセージに対して異なる反応を示します
  • これらは動作がスタックされ、これはプッシュ、ポップすることができる。

クラッシュ耐性

Akka に関していえば Java/C/C# やそれ以外の手続き+オブジェクト指向な防御的プログラミングなんてしない。
てーかそのスレッド落ちたら終わりとかそういう話になってしまう。

クラッシュさせよーぜ!

SUPERVISE

  • SUPERVISE はほかのアクターの落ちを管理する
  • エラーハンドリングはこのスーパバイザーに一任される
  • これが何を意味するかというと、Actorに何か問題が発生した場合、そのSupervisorに通知される
  • これでエラーハンドリングをきれいに分離できるわけだ

SUPERVISE Actor

ひとつひとつのアクターは、デフォルトのスーパーバイザ戦略を持っています。これは通常は十分です。しかし、それは上書きすることができます。

  import akka.actor.SupervisorStrategy._
  override def supervisorStrategy = AllForOneStrategy(maxNrOfRetries = 10, withinTimeRange = Duration(1, "minute")) {
    case _: NullPointerException => Restart
    case _:Exception => Escalate
  }

同様に、Actor の preRestart, postRestart もあるでな。

リモートにデプロイすることもできますねん。

akka.actor{
    provider = akka.remote.RemoteActorRefProvider
    deployment {
        /greeter {
            remote=akka://RemoteSystem@hostName:2552
        }
    }
}

デプロイはこれだけ。
使うほうは

val sample = system.actorFor("akka://SampleSystem@hostName:2552/path/to/actor")

クラスタリングも設定でいける

akka{
    actor{
        provider = "akka.cluster.ClusterActorRefProvider"
        deployment {
            /greeter {
                router = consistent-hashing
                nr-of-instances = 180

                cluster {
                    enabled=on
                    max-nr-of-instances-per-node=3
                    allow-local-routers=on
                }
            }
        }
    }

    cluster {
        seed-nodes = {
            "akka://ClusterSystem1@host:2552",
            "akka://ClusterSystem2@host:2552",
            "akka://ClusterSystem3@host:2552"
        }

        auto-down = on
    }
}

*1:どう訳していいのか分からない多分こんな感じ?

*2:? 誰か教えて

*3:すまん訳諦めた