70
Actor とエラーハンドリング Erlang 時々 ScalaM.Ikuta(@cooldaemon) Sep.4,2011 1

Error handling in Erlang and Scala

Embed Size (px)

Citation preview

Page 1: Error handling in Erlang and Scala

Actor とエラーハンドリング~Erlang 時々 Scala~

M.Ikuta(@cooldaemon)Sep.4,2011

1

Page 2: Error handling in Erlang and Scala

自己紹介

決済代行会社のプログラマ

某大手クーポンサイトの決済システム

iPhone + ScanJacket 

Erlang 基礎勉強会や分散処理勉強会の主催

2

Page 3: Error handling in Erlang and Scala

モチベーション何故、エラーハンドリングの知識が必要か?

堅牢なシステムを構築したい

休日に家族サービスができる

3

Page 4: Error handling in Erlang and Scala

モチベーション何故、エラーハンドリングの知識が必要か?

堅牢なシステムを構築したい

休日に家族サービスができる

3DS の稟議が通る

3

Page 5: Error handling in Erlang and Scala

モチベーション

並行や分散を取り入れるとシステムが複雑に?

並行や分散だからこそ堅牢なシステムを作れる!

4

Page 6: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

5

Page 7: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

6

Page 8: Error handling in Erlang and Scala

Erlang と Scala の紹介

何故、Actor モデルの話をするために Erlang と Scala を選んだのか?

私が他の Actor モデルを実装したライブラリや言語を知らない

本日、話す予定のリンクによる相互監視が、他の Actor 実装に採用されているか不明

7

Page 9: Error handling in Erlang and Scala

Erlang と Scala の紹介Erlang 

ネットワークサーバを作るための DSL

並行と分散が得意

高い耐障害性

稼働率 99.9999999% も夢ではない

8

Page 10: Error handling in Erlang and Scala

Erlang と Scala の紹介Erlang 

Yaws, Mochiweb, RabbitMQ, CouchDB, Hibari, Riak, Kai, Scalaris, Ejabberd, etc..Tsung や BashoBench のような負荷試験ツールも作りやすい

モジュールや関数を物理的に離れたノードに転送できるので MapReduce なども得意

9

Page 11: Error handling in Erlang and Scala

Erlang と Scala の紹介Scala 

様々な言語の長所を集めた次世代言語

夢と希望が詰ってる

並行処理に関連するキーワードだけでも…

Thread, Actor, 部分継続, 並列コレクション, 非同期IO, CAS, STM, etc..

10

Page 12: Error handling in Erlang and Scala

Erlang と Scala の紹介Scala 

選択肢が多く、組み合わせも自由

Actor + STM 

Actor + 継続

Actor + 非同期IO

継続 + 非同期IO

11

Page 13: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

12

Page 14: Error handling in Erlang and Scala

Actor モデル

13

Page 15: Error handling in Erlang and Scala

Actor モデル並行に動作する計算実体

13

Page 16: Error handling in Erlang and Scala

Actor モデル並行に動作する計算実体

もう少し詳しい話をこれからするので、知ってる人は寝てて OK

13

Page 17: Error handling in Erlang and Scala

Actor モデル世の中の全ては Actor である

全ての Actor は並行に動作する

Actor は、個々にローカルメモリを持ち、Actor 間でメモリ共有を行わない

Actor は、自分自身や他の Actor とメッセージを送受信しながら処理を行う

14

Page 18: Error handling in Erlang and Scala

Actor モデルActor は、メッセージを受信するためにメールアドレスとメールボックスを持つ

メッセージは、メールアドレス宛に送信される

メッセージは、メールボックスに格納される

メッセージは必ず届いて処理される

15

Page 19: Error handling in Erlang and Scala

Actor モデルメッセージの送信は非同期に行われる

メッセージ受信の順番は保証されていない

メールボックスから任意のメッセージを取り出せる

Actor は、新たな Actor を作成できる

16

Page 20: Error handling in Erlang and Scala

Actor モデルErlang と Scala には実装されていないが…

Actor はノードを越えて移動できる

暇なノードへ働きに行ったり

壊れたノードから逃げたり

17

Page 21: Error handling in Erlang and Scala

Actor モデル

Mailbox ActorReceiveMessage Message

Mailbox Actorreceivemessage messageSend

Mailbox ActorCreate

18

Page 22: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

19

Page 23: Error handling in Erlang and Scala

リンクのよる相互監視リンク

二つの Actor 間のエラー伝播経路を定義

二つの Actor がリンクされている場合、一方の Actor が停止すると、もう一方に EXIT シグナルが送られる

20

Page 24: Error handling in Erlang and Scala

リンクのよる相互監視EXIT シグナル

Actor が停止する際に自動的に生成される(故意に生成する事もできる)

停止する Actor とリンクしている全ての Actor へブロードキャストされる

EXIT シグナルには停止理由が含まれる

21

Page 25: Error handling in Erlang and Scala

リンクのよる相互監視

EXIT

LinkA B

A B

A B

A

22

Page 26: Error handling in Erlang and Scala

リンクのよる相互監視

EXITEXIT

A B C

A B C

A C

23

Page 27: Error handling in Erlang and Scala

リンクのよる相互監視

EXIT

EXIT

A B C

A B C

A B

A

24

Page 28: Error handling in Erlang and Scala

リンクのよる相互監視EXIT シグナル

EXIT シグナルを受信した Actor は、trap_exit が true か否かで動作が異なる

Erlang では、trap_exit が true の Actor をシステムプロセスと呼ぶ

25

Page 29: Error handling in Erlang and Scala

リンクのよる相互監視システムプロセス(Erlang)

trap_exit 停止理由 動作

TRUE kill 停止:killed をブロードキャスト

TRUE X {'EXIT', Pid, X} をメールボックスに追加

FALSE normal 無視

FALSE kill 停止:killed をブロードキャスト

FALSE X 停止:X をブロードキャスト

26

Page 30: Error handling in Erlang and Scala

リンクのよる相互監視システムプロセス(Scala)

trap_exit 停止理由 動作

TRUE X Exit(Actor, X) をメールボックスに追加

FALSE 'normal 無視

FALSE X 停止:X をブロードキャスト

27

Page 31: Error handling in Erlang and Scala

リンクのよる相互監視リンクの利点

故障箇所を Actor (やノード)に隔離できる

大怪我ではなく、擦り傷で済む

依存関係がある Actor をまとめて停止できる

一方がシステムプロセスであれば、停止を検知してエラー処理を行える

28

Page 32: Error handling in Erlang and Scala

リンクのよる相互監視リンクの利点

リンクはノードを越えて行える

監視 Actor と Worker Actor を、それぞれ、物理的に離れた別ノードに配置できる

障害が発生した信頼できない Actor(やノード)にエラー処理を任せない

29

Page 33: Error handling in Erlang and Scala

リンクのよる相互監視エラー処理は…

監視している Actor が処理を引き継ぐ

停止した Actor を再起動

処理を引き継ぐ Actor を別ノードに作る

社内監視システムにエラー通知を行う

etc…

30

Page 34: Error handling in Erlang and Scala

リンクのよる相互監視リンクの利点

コードがスッキリする

31

Page 35: Error handling in Erlang and Scala

リンクのよる相互監視JavaScript

if (is_success()) { do_samething();} else { throw "Exception";}

32

Page 36: Error handling in Erlang and Scala

リンクのよる相互監視Erlang

ok = is_success(),do_samething().

ok 以外で例外 {badmatch, 戻り値} が発生

33

Page 37: Error handling in Erlang and Scala

リンクのよる相互監視JavaScript

var num = get_number();switch (num) { case 1: do_samething1(); break; case 2: do_samething2(); break; default: throw "Exception: " + num; break;}

34

Page 38: Error handling in Erlang and Scala

リンクのよる相互監視Erlang

case get_numer() of 1 -> do_samething1(); 2 -> do_samething2()end.

1, 2 以外で例外 {case_clause, 戻り値} が発生

35

Page 39: Error handling in Erlang and Scala

リンクのよる相互監視Erlang

do_samething(get_number()).do_samething(1) -> do_samething1();do_samething(2) -> do_samething2().

1, 2 以外で例外 {function_clause, 戻り値} が発生

36

Page 40: Error handling in Erlang and Scala

リンクのよる相互監視Scala

getNumber() match { case 1 => doSamething1() case 2 => doSamething2()}

例外 scala.MatchError が発生するが、Actor 内ならリンク先に Exit(Actor, Exception)

37

Page 41: Error handling in Erlang and Scala

リンクのよる相互監視リンクの利点

コードがスッキリする

異常事態を考慮したコードを書く必要がない

その場でウダウダせずに、システム全体の構造により頑健性を担保する

38

Page 42: Error handling in Erlang and Scala

リンクのよる相互監視リンクの利点

コードがスッキリする

とは言え…回復不能な想定外の異常事態が発生した場合の処理のみ省略する事!!

39

Page 43: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

40

Page 44: Error handling in Erlang and Scala

Supervisor TreeActor リンクを木状に構成したもの

木の上位にある Actor(trap_exit=true)が下位の Actor を監視する

監視専用の Actor を Supervisor と呼ぶ

Erlang OTPAkka

41

Page 45: Error handling in Erlang and Scala

Supervisor Tree個人的な設計原則

全ての Actor は Supervisor 配下に設置

Application:Supervisor Tree = 1:1 

42

Page 46: Error handling in Erlang and Scala

Supervisor Tree全ての Actor は Supervisor 配下に設置

Actor が孤独死するシステムは堅牢ではない

43

Page 47: Error handling in Erlang and Scala

Supervisor TreeApplication:Supervisor Tree = 1:1 

Supervisor を複数使いたい?

Root の Supervisor の下に、それらの Supervisor を設置して一元管理

44

Page 48: Error handling in Erlang and Scala

Supervisor Tree

Worker

Supervisor

Worker Supervisor

Worker WorkerWorker

45

Page 49: Error handling in Erlang and Scala

Supervisor TreeSupervisor の仕事

配下の Actor の起動と停止に特化

他の余計な仕事は行わない

46

Page 50: Error handling in Erlang and Scala

Supervisor TreeSupervisor 毎の設定(抜粋)

停止した Actor のみ再起動(one_for_one)

停止した Actor と同じ Supervisor 配下の Actor を全て再起動(one_for_all)

47

Page 51: Error handling in Erlang and Scala

Supervisor TreeSupervisor 毎の設定(抜粋)

一定の秒数以内に一定の回数以上 Worker の起動停止を繰り返したら Supervisor を終了

再起動しても何度も同じ理由で停止する状態を避ける

48

Page 52: Error handling in Erlang and Scala

Supervisor TreeWorker 毎の設定(抜粋)

必ず再起動(permanent)

異常終了した場合だけ再起動(transient)

再起動しない(temporary)

終了処理のタイムアウト時間

49

Page 53: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

50

Page 54: Error handling in Erlang and Scala

Error Loggerエラーハンドリングの仕組み

Erlang OTP 

Erlang では、catch されなかった例外は Error Logger で処理される

OTP の Event Manager Behaviour で作られている

Erlang Behaviour = Scala Trait

51

Page 55: Error handling in Erlang and Scala

Error LoggerEvent Manager 

予め任意の Event に幾つかの Event Handler を登録しておくと、その Event が発生した際に、登録済みの複数の Event Handler を全て実行する

52

Page 56: Error handling in Erlang and Scala

Error Loggerデフォルトで、エラーログを TTY に出力する Error Handler が登録されている

OTP の System Application Support Libraries(SASL) を起動すると…

エラーログをファイルに残す

エラーログファイルをローテションする

などの設定ができる Error Handler を追加する

53

Page 57: Error handling in Erlang and Scala

Error LoggerSASL の Error Handler

速度を上げるため、バイナリ形式でログを残す

専用のログを読むアプリケーション(rb)を使用しないとログが読めない

エラーメッセージが少し解り難い

54

Page 58: Error handling in Erlang and Scala

Error LoggerLagger 

SASL が性に合わない人向け

Riak の Basho 製

解りやすいメッセージをテキスト形式でファイルに保存してくれる Handler が登録される

55

Page 59: Error handling in Erlang and Scala

Error LoggerScala(提案)

Event Manager Trait を作る

Event Manager Trait を extends した Error Logger Actor を作る

Error Logger にメッセージを送る Trait を作る

56

Page 60: Error handling in Erlang and Scala

本日のお題Erlang と Scala の紹介

Actor モデル

リンクによる相互監視

Supervisor Tree 

Error Logger 

例外

57

Page 61: Error handling in Erlang and Scala

例外最後に Actor とは関係無いのですが、Erlang と Scala の例外についての余談をさせてください

58

Page 62: Error handling in Erlang and Scala

例外Erlang 

Erlang には三つの例外がある

error 

throw 

exit 

59

Page 63: Error handling in Erlang and Scala

例外Erlang 

error 

システムエラーであり、呼び出し側が対処できないエラーである場合に使用する

意図的に起こす事もできるが、パターンマッチの失敗等で自動的に発生する

error は catch 非推奨

60

Page 64: Error handling in Erlang and Scala

例外Erlang 

throw 

呼び出し側が対処できるかもしれないエラーである場合に使用する

呼び出し側は、対処できないと判断した場合、無理に catch しなくとも良い

61

Page 65: Error handling in Erlang and Scala

例外Erlang 

exit 

Actor を停止する際に使う

62

Page 66: Error handling in Erlang and Scala

例外Erlang

try foo(), bar()catch error:foo -> handle_foo(); throw:bar -> handle_bar(); Class:Exception -> handle_error(Class, Exception)after baz()end.

63

Page 67: Error handling in Erlang and Scala

例外Scala 

チェック例外が無い

例外は、なるべく異常事態に限定する

Actor や STM の内部での利用は必要悪

Java の throw 宣言されているメソッドを使用する際、catch しなくともコンパイル時にエラーとはならない

64

Page 68: Error handling in Erlang and Scala

例外Scala 

回復可能な想定内のエラーは、Option や Either に包んで返す

Java メソッドの例外は、scala.util.control.Exception.allCatch で Option/Either に包む

65

Page 69: Error handling in Erlang and Scala

例外Scala

import scala.util.control.Exception.allCatch

def foo(): Either[Throwable, Foo] = allCatch either {new JavaFoo}def bar(objFoo: Foo): Either[Throwable, Bar] = allCatch either {new JavaBar(objFoo)}

val result: Either[Throwable, Bar] = for { objFoo <- foo().right objBar <- bar(objFoo).right} yield objBar

66

Page 70: Error handling in Erlang and Scala

ご清聴ありがとうございました

67