Development app-with-elixir

1,053 views

Published on

development otp application with elixir
key value store server example.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,053
On SlideShare
0
From Embeds
0
Number of Embeds
12
Actions
Shares
0
Downloads
4
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Development app-with-elixir

    1. 1. DevelopmetApplication with Elixir @k1complete
    2. 2. abstract• Elixirにおいて、本格的なアプリケーション を開発するために必要そうな内容を実例に そって紹介• Erlang/OTPの知識を前提とせず頑張ってみ ます• 最終的にはElixir、Erlang/OTPのドキュメン トを読む気になれば
    3. 3. Elixirとは• José Valimが開発しているErlang VM上に構築された、以下の 特徴を持つプログラミング言語 • 現代的な文法 • Erlang/OTPとのバイナリ相互互換性(並行指向、耐障害性 といったErlang/OTPの特徴を全て持つ)。JavaVMでScala がしたことをErlang VMで行っているようなもの • メタプログラミング支援機能 • プロトコル、レコードによるポリモーフィズム • 本物のマクロ
    4. 4. Erlang/OTPとは• Open Telecom Platformの略で、EricssonのOTPチームにより母体が開 発され、Erlangコミュニティにより継続されている、通信アプリケー ションに必要とされる機能/非機能要件をサポートするライブラリ • アプリケーション管理(applicationビヘイビア) • 汎用サーバ(gen_serverビヘイビア) • 状態遷移マシン(gen_fsmビヘイビア) • スーパバイザ(supervisorビヘイビア) • 動的アップグレード(releaseハンドラ) • ando more....!
    5. 5. お題: KVSサーバ1. Key-Valueストア機能の要件(FR) 1.1.ユーザごとに個別のKV空間を割り当てる。 1.2.キーはアトムのみで登録と読み出し、削除、変更がで きる。2. それ以外の要件(NFR) 2.1.マルチユーザにサービスする事 2.2.クライアントが接続しているサーバがクラッシュして も復活する事
    6. 6. 全体の構造 app 起動と停止 クライアントの要求によりsupervisor for supervisor serverの起動を行う 1サーバに一つ起動し、サーバクラッシュ supervisor supervisor 時の再起動と、KVSテーブル保持 for server for server 1クライアントに一つ起動し、KVSの操作 gen_server gen_server を実施 gen_serverのコールバックとして実装する ekvs ETSを利用したKVSモジュール(not OTP)なるだけOTPモジュールを組み合わせるのがOTP way
    7. 7. ekvs• ekvsはETS(erlang term strage)を利用し て簡単にすます defmodule Ekvs do def new(id) do defp keys(_id, :"$end_of_table", a) do new(id, []) a end end def new(id, opts) do defp keys(id, r, a) do :ets.new(id, opts) keys(id, :ets.next(id, r), [r | a]) end end def put(id, k, v) do def keys(id) do true = :ets.insert(id, {k, v}) keys(id, :ets.first(id), []) id end end def delete(id, k) do def get(id, k) do :ets.delete(id, k) case :ets.lookup(id, k) do id [] -> nil end [{^k, v}] -> v end end end
    8. 8. gen_serverとは• 並行指向のElixir(Erlang/OTP)では、単にマルチユー ザを束ねるプロセスをサーバとは考えない。• サーバはそのリソースを管理するものと考える。• サーバとして共通に必要な部分をビヘイビア(振る舞 い)としてまとめたのがgen_server• 固有部分は指定された名前のコールバック関数を実装 することで、適切にgen_server側から呼び出される。
    9. 9. ekvsサーバの実装 • elixirではGenServer.Behaviorモジュールがある ため、これをuseしてコールバックを実装する。defmodule Kvs.Server do use GenServer.Behavior def handle_call({:delete, key}, _from, state) do def start_link(id, tbl_id) do {:reply, :ok, Ekvs.delete(state, key)} :gen_server.start_link({:local, id}, __MODULE__, [id, endtbl_id], []) def handle_call({:keys}, _from, state) do end {:reply, Ekvs.keys(state), state} def init([_id, tbl_id]) do end :io.format("kvs.server[~p]~n", [tbl_id]) def terminate(reason, state) do {:ok, tbl_id} :error_logger.error_report(#{inspect __MODULE__} end crashed:n#{inspect reason}) def handle_call({:get, key}, _from, state) do :error_logger.error_report(#{inspect __MODULE__} {:reply, Ekvs.get(state, key), state} snapshot:n#{inspect state}) end :ok def handle_call({:put, key, value}, _from, state) do end {:reply, value, Ekvs.put(state, key, value)} end end
    10. 10. supervisorとは• 子プロセスの(再)起動に責任を持つビヘイビア。プログラマは再起動ポリシーと子プロセス のスペックを指定するだけで、異常事態(プロセスのクラッシュ)への対処を行ってくれる • 再起動ポリシー • one_for_one 一つが落ちたら、その一つを再起動 • one_for_all 一つが落ちたら、全ての子プロセスを再起動 • rest_for_all 一つが落ちたら、そのプロセス以降に起動された物を全て再起動 • 再起動トライ数、最大リトライ秒数... • 子プロセスのスペック • restart :permanent(常に再起動), :transient(再起動されない), :temporary(異常終了の ときのみ再起動) • type worker/supervisorのいずれか • module_list 子プロセスを実装するモジュール。リリースハンドラはこれを元にアッ プグレード時に再起動するプロセスを決定します。
    11. 11. supervisor for GenServer• init()は以下のとおり defmodule Kvs.Srv.Sup do • :ets.newでテーブルを作成し、 use Supervisor.Behavior, [] def init(args) do それをKvs.Serverへ渡すように key = args childspecを記述。 tbl_id = :ets.new(key, [:public]) childspec = {key, {Kvs.Server, :start_link, [key, tbl_id]}, • :one_for_oneタイプと :permanent, し、:permanent に存在さ 100000, :worker, せ、:workerタイプの子プロセス [Kvs.Server]} {:ok, {{:one_for_one, • サーバの起動は、 10, # AllowedRestart(count) 100}, # MaxSeconds(sec) Kvs.Server.start_linkを呼び出 [childspec]}} す。 end end• 以上でsupervisor完了
    12. 12. Supervisor for Supervisor defmodule Kvs.Sup do• クライアントからの要求に応じ use Supervisor.Behavior, [] def init(_args) do て、子プロセスを起動するような {:ok, {{:one_for_one, supervisorは、 10, # AllowedRestart(count) 100}, # MaxSeconds(sec) supervisor.start_childと []}} end supervisor.terminate_childを使う。 def connect(super_ref, key) do childspec = {key, • connect関数: Kvs.SrvSupの生成 {Kvs.Srv.Sup, :start_link, [key]}, :temporary, supervisor.start_child 関数によ 10000, #shutown wait time(milisec) り動的に開始 :supervisor, [Kvs.Srv.Sup]} • quit関数: Kvs.SrvSupの終了 :supervisor.start_child(super_ref, childspec) end supervisor.terminate_child関数 def quit(super_ref, key) do :supervisor.terminate_child(super_ref, key) 呼び出し end end
    13. 13. application defmodule KvsApp do• OTPアプリケーションと @behaviour :application def start() do して start, stop関数を用意 :ok = :application.start(:kvs) end def start(_type, args) do する必要がある。 Kvs.Sup.start_link(:kvs_sup, args) end def stop() do• 中身はトップレベルの :application.stop(:kvs) end supervisorモジュールであ def stop(state) do Kvs.Sup.stop(:application_stop, state) end るKvs.Sup.start_linkや end Kvs.Sup.stopを呼び出す だけ。
    14. 14. mix.exs defmodule MyApp.MixFile do• ビルド用のmix.exs use Mix.Project def project do• ビルド定義もelixirスクリプトで記 [app: :kvs, version: "0.0.1"] 述。 end def application do [mod: {KvsApp,[]},• バージョンやアプリケーションの applications: [:sasl ], registered: [:kvs], メインモジュール、デスクリプ description: Hello Server App] ションを指定するだけで、kvs.app end end は自動でmixがビルドしてくれる。• mix new <app>で<app>用のセッ トアップをしてくれる。
    15. 15. github今回のコードは以下に曝していますのでご自由にどうぞ。https://github.com/k1complete/kvs.git

    ×