Getting Startedなどやっているとよく出てくる、定番な機能ですね。ETSは Erlang Term Storage の略です。 ある1つのprocessをキャッシュ代わりに使っている場合、そのprocessの性能や拡張性が処理のボトルネックになることが多くなります。そんなときの解決策としてETSが説明されています。(ETSに限らず、何かの要素と依存関係を持つ場合、その要素のいずれかがボトルネックになることは多々ありますね。) 特徴 Positive etsは、owner processが起動している間だけ使える(in-memoryで) serialize(連続的に)なキャッシュに書き込める 分けられたメモリ空間に書き込まれ、多くのprocessから並行にアクセス可能 globalでアクセス可能 mutable 非常に高速なアクセスが可能 末尾に内容を記載 Negative client processとETS tableはコピーされる ETSに保存されるデータが原因でprocessがcrashする場合、 Supervisorによってリカバリされたprocessも再びcrashする という、悪循環に陥ることがある BEAMの良さであるリカバリシステムを崩す原因になる ETSには、複雑で大きなデータは扱うべきではない ETSはネットワーク越しの他BEAMインスタンスとは共有できない 本当に性能/拡張性を改善したいときだけにするといった用途を制限するほうが良い 高い性能で多くのprcessで共有したいデータか?など ETSの使い方 New http://www.erlang.org/doc/man/ets.html#new-2 table types :set The table is a set table – one key, one object, no order among objects. This is the default table…More
Category Archives: development
[Elixir in Action]Supervision Tree ~ ネストされたSupervisor ~
メモメモ。 前回では、Supervisorというprocessの説明でした。 ここからは、エラーに関する話やSupervision Treeの話。 Supervision treesは、Supervisorによって以下見たく構成されるSupervisor – processの関係性を指します。Supervisorやworkerがlinkの関係を持ち、strategyに沿ってそれぞれのprocessを監視していきます。 Supervisorには、その子processの起動として、以下を定義しています。 Supervisorは、親から子とprocessを順に起動していきます。このprocessの起動は同期的に行われます。なので、上記では worker(Todo.ProcessRegistry, []) => supervisor(Todo.Database, [“./persist/”]) => … という順に前のprocess起動が終わるのを待って次のprocessが起動していきます。 これらのworkerやsupervisorは、 Sample.Supervisor のprocessが終了するとterminateされていきます。(これがsupervisorと、その子の関係ですね) Erlang/Elixirが提供する Supervisor では、 link や monitor をPIDによって指定したプロセスを対象として監視していたものを、抽象化して、processにひも付けたatomによって監視します。これは、PIDはprocessがcrashした後に起動するたびに変わるためですね。 前回にもメモしていましたが、processの監視には link と monitor があります。子processがcrashしたらそれ単体を再起動する、などしたいならlink、子processがcrashしたらそれに関係する他の子processも終了する、とか実装したいならmonitorを使う必要があります。 Supervisorには、その子processのcrash時の挙動として幾つかのstrategyを定義し、提供しています。それらから必要なstrategyを設定して、実際には運用していくことになります。この選択はfault toleranceなシステムを構築するうえで重要な要素。 :one_for_one – if a child process terminates, only that process is restarted. :one_for_all – if a child process terminates, all…More
[Elixir in Action]fault toleranceを保つための特別な責務を負うprocess~Supervisor~
BEAMの真骨頂であるFault toleranceに関して、複数章に渡って説明しているところの話。 ここではその触りの箇所。 fault torelanceであるようにするためには、failureを知り、それに対してリカバリして現状の機能を提供し続けることが最低限必要です。そのためにBEAMがどのような機構を備えて、Elixir/Erlangではどうなのか?をまとめています。 3つのタイプのエラー BEAMでは3つの種類のerrorを持ちます。 errors ** [ArithmeticError] bad argument in arithmetic expression などで意図せずエラーがでるとき exits exit(“I’m done”) のように、意図的にプロセスを終了させる throw throw(:throw_value) のように、意図的にthrowを投げる throwの目的は、non-localな相手へ何か情報を与える時に使うことです。(BEAMでは、remote processに何か処理を任せる、ということが多々ありますね) Elixirでは、すべてのエラーは 必ず 何らかの値を返します。 そのため、任意のエラーに対して共通で何かする、というときは以下のように _ を使う必要があります。 それ以外では、 catch のパターンマッチを使い、特定のエラーの時は意図した処理を行うような処理を書きます。 defexception により、任意のmacroを組むことが可能。 もし、エラー処理を用意していない場合、 processはterminate されます。制御できないエラーはどんどん落としてしまえ、というやつですね。 errors in concurrent system BEAMではprocessで分離しているので、何らかのprocessのエラーが他processへ影響を与えることはありません。 そのため、processを監視して、互いを把握していく必要があります。 Link Process.link/1 や spawn_link/1 を使うことで、2つの異なるprocessをリンクします。リンクするとは、一方のプロセスが死んだら、もう一方はそれを知ることができるし、その逆も然り、という相互の関係を持つことを指します。 正常にexitするときは :normal という値を返します。それ以外は、基本的に異常終了である、と判断します。 通常、終了のシグナルは以下のメッセージを構成します。 何らかのエラーを投げて死ぬ場合は、以下の形式のメッセージを構成します。…More
[Elixir in Action]OTP/GenServerを学んで非同期/並行処理を学ぶ
Elixir in Actionの続き。ようやっと3分の2くらい。写経もほどほどに実施しながらだとこのくらいですかね。 Chatpter6、7ではOpen Telecom Platformと、その上に構成されるGenServerに関する内容をざーっと通してました。 自前のloopで作っていた簡易サーバから、GenServerへと一般化、どのように処理しているのか?をボトルネックを解消していくという話の流れのなかで説明していっています。 サーバの基本的な役割は以下 Spawn でプロセスを分ける loopでプロセスを回す processの状態を管理する messageに反応する 送信元に応答を返す(送る) 最終的にはGenServerに近づいていくので、大きくここら辺は割愛。 ただ、 非常に考え方は重要 だし、ここら辺がErlang/Elixirのアーキテクチャとして選ぶ価値があると判断される箇所だと思うので、ちゃんと理解する方が良さそうです。 Elixir/Erlangのサーバで重要な役割を持つのは以下。 gen_server init, handle_call, handle_castなどのcallbacksを持つ 想定していない処理を無視するために、 def handle_info(_, state), do: something といった処理も入れる superevisor errorハンドリングやリカバリを担う application gen_event gen_fsm single processで処理される時のボトルネックは、多くのリクエストが溜まるにつれて応答(process)が遅くなること。 そこで、concurrentに処理できるように拡張する。ただ、cncurrentに処理できるように spawn により別プロセスで処理可能にすると、同期的に処理したい時が複雑になる。そこで、Elixir/Erlangでは以下のように GenServer.reply を使い、うまいこと非同期処理を利用している。 single processでリクエストを操作し、その実際の処理は子プロセスに実施させる。必ずこの方法が良いというわけではないが、本書ではこの方法を解の1つとして紹介していた。 ボトルネックの話でいうと、databaseを相手にしはじめると、DBとアプリをつなぐ間のpoolを処理するためのプロセスも関係してきますが、そこら辺はEctoでは poolboy が役割を担っているそうな。 poolboy Getting Startedを読んでなくていきなりこれでは辛いけれど、Getting Startedの後なら特にconcurrencyやfault toleranceの話を知る上ではこれは読んで価値ありそうです。特に、Erlang/Elixirに限らず、concurrencyやfault toleranceの考え方は参考になると思います。 補足コード Process.registerは以下…More
[Elixir in Action]BEAMとしてのprincipleとその実現のための処理系
principle against Erlang Minimize, isolate, and recover from the effects of runtime errors (fault torelance) Handle a load increase by adding more hardware resources without changing or redeploying the code (scalability) Run your system on multiple machines so that others can take over if one machine crashes (distribution) それらを達成するために、BEAM VMの処理系が作られてきました。 BEAMのprocessはOSのprocessではない OSのthreadがBEAMのSchedulerを持つ BEAMのSchedulerが、BEAMのprocessを管理する BEAMの1processの初期メモリは1~2KBなので、OSの1processのMByte単位のメモリ使用量に比べて遥かに小さいし、論理的にはBEAMのprocessは約26,8百万のprocessを実行できる BEAMのprocessは、scalabilityを達成するように、資源の追加に対して自動でその資源を使うようになっている…More
[Elixir in Action]polymorphismで拡張していく
Data abstractionsに書かれている章でした。 ここが終わったので、いよいよElixir/Erlangの真骨頂であるHigh Availabilityなシステムを構築するための説明に入ります。 structure moduleは、抽象データを作るために使われる。 map structs mapとstructsは同じように使われることが多い。 ただ、違うところもある。 例えばパターンマッチ このように、structはmapの特殊な形として使われる。 ちなみに、Recordというモジュールもあって、これは主にErlangライブラリを使う時には、Recordをimportして使いましょう、というものらしい。 polymorphism Elixirでは、polymorphismは protocol によって実現される。 defprotocol ではインターフェースを定義して、 defimpl でその実装を加えていく。 例えば、 to_string を独自のmodule、 Sample に加えるなら、 とすると、その結果として と得られる。(IO.putsはString.Chars.to_stringを指している) このprotocolは、他にも Inspect や Access といったものもある。 Elixirでは、このように元となる protocol に対して defimpl 内の実装を増やすことで機能を拡張していく。More
[Elixir in Action]Guard clauseの優先度
control flowの章の、 [Elixir in Action]Erlang/Elixirの再帰計算におけるnon-tail recursionとtail recursion 以外のことを。 以下のように、文字列バイナリも左辺/右辺のマッチングによって分けることができます。 以下のように、連続したマッチングもできます。 以下のように書いた場合、パターンマッチングでは上から順にマッチングを試みます。そのため a(other) が最も先頭にきたらそれがマッチングされます。 Elixirでは、以下のようなGuard clauseによっても適用される関数を条件付けすることができます。この時、 when で使われる型には優先度が存在します。 優先度は以下。 つまり、上記の Sample.a/1 に対してatomの :not_a_number を適用した場合、 が適用されます。エラーはありません。 そのため、数字だけを受け付けるようにするために以下のように書きます。 これで、 :not_a_number のようなものは FunctionClauseError がraiseされるようになります。 Cmprehensionsは、 for x <- [list], do: {何か} で構成される。 into などの要素を使ったりすると、繰り返しをより簡潔にかけたりする。なるほど。 Streamの説明もありましたが、Stream、色々できそうですね。 File.stream! でStreamにした後にごにょごにょStreamで操作した最後にto_list などでlistにして処理をする、といった例が載ってましたが、イマドキぽい感じがします 🙂More
[Elixir][Phoenix]簡単なWebアプリを生成してみた
やったこと備忘録。 最近、細々とElixir 1.0.5 x Phoenix 0.15.0ベースで、簡単な投票Webアプリケーションを作成してみました。 時間にして、作成自体、1日はいかない感じ。EctoやPhoenixを調べながらやって、1日といったところでしょうか。 使ってみた感想としては、PhoenxiはまんまRailsに近しいな、ということですね。 Railsに明るくなくとも、このくらいのアプリだとある程度書き進めることもできます。 ちなみに、私は明るくない側の人間です。 実装したことはこちら リポジトリはこちら Phoenixの他に、ログインなどの状態を保ちたいので、Guardianという認証ライブラリを使いました。 これ書いてて感じたのですが、文法的な表現は確かにElixirのように書くのですが、Supervisorなんかは別に書くわけではないし、なんかElixirを書いている!という感じがしなくもない… 最近Elixir in Actionを読んでいるのですが、ErlangからみたElixirという側面の強い情報を仕入れているのですが、なかなか面白いですね。学び始めて少しして、急にQiitaなんかでもやってみた系記事を見始めたのですが、それよりも前の古参の方々や学び始めた人、ここら辺を最初の一歩としてインプットしてるのかな。 Elixirのテスト関連を中心に色々知見を深めたい。More
[Elixir in Action]Read building blocks
Elixir in Action、Programming ElixirやGetting Startedなんかとは趣が異なって、BEAM VM上で動作するElixirという仕組みを色々深堀しているのですね。説明していること自体はかぶる箇所が多々あるのですが、より言語自体というよりも、その言語によって何を成すか?という目的に対してこの機能がある、といった感じで話が進んでいる感じ。 ところどころ、Erlang混じりの解説やリンクが登場するのはErlangを専門とする著者だから、の特徴かな。これ読んでいると、Erlangの言語的な表記というよりは、内部処理の知見もたまってくるという。 少し読んだところの特徴を抜粋。個人的なメモです。 Elixirは、moduleとfunctionに分けられる Elixirは純粋な関数型言語ではない。そのため、幾つか副作用がある関数が存在する。 データはimmutable。加工したデータは、異なるmemory locationに書き出される。ただし、shallow copyされたデータは共通の元となるデータをなるべく共有している。 booleanは true と false のatom nullabilityは無いので、 nil のatomを使う String typeは無い。binariesかlistで使う。 character listは、3-rd party製のErlangなんかが要求する時のみに使うことが良い。あとはbinary string使いましょう。 complex typeはlist、tuple、mapsだけ Range、Keyword list、HashDict、HashSetはデータシステムの元 keyword-listは値の小さな構造体で使う HashDictは、より大きなコレクションで性能を上げたい時に使おう HashSetはユニークな値の集合 & オペレータでlambdaを使おう Getting started では、 fn x -> function end を簡略化するために & を使ってましたね 粒度が結構違うメモなのですが、Elixirでの命名規則は以下の模様。 Elixirでの命名規則としての ?、! ? : true or false…More
[Elixir]heroku deployのecto操作でエラーがでるが…
2015年8月頭時点 ecto.drop とか、 ecto.create すると以下のようなエラーが出ます。 けれど、特に無視してよくて、そのまま ecto.migrate をしてあげれば良いです。 何かと思った。More