質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Erlang

Erlangとは、多目的でありガーベッジコレクションを行うプログラミング言語および実行環境です。Erlangは並行処理・分散化された環境・フォルトトレランスを実装しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Elixir

Elixirは、並列処理や関数型に特化した、Erlang VM (BEAM) 上で動作する汎用プログラミング言語です。分散システム、耐障害性、ソフトリアルタイムシステムなどの機能を持ちます。

解決済

Elixir+Phoenixが早い理由と、これでDB処理を作った時のデッドロックについて

yokatone
yokatone

総合スコア43

Erlang

Erlangとは、多目的でありガーベッジコレクションを行うプログラミング言語および実行環境です。Erlangは並行処理・分散化された環境・フォルトトレランスを実装しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Elixir

Elixirは、並列処理や関数型に特化した、Erlang VM (BEAM) 上で動作する汎用プログラミング言語です。分散システム、耐障害性、ソフトリアルタイムシステムなどの機能を持ちます。

1回答

0リアクション

0クリップ

5136閲覧

投稿2018/08/25 03:37

概要

Elixir + Phoenixが早い理由としてどこがキモになるのか。
関数型言語であること、並行処理が可能であることが大きなシナジーを生んでいる言語と考えてよいのか。
その場合、DBアクセス処理設計を行うときは、並行処理という特性を踏まえた慎重なものにしなければならないのか。

といった要旨です。
整理しきれずすみません。質問が大きく二つございます。

質問したいこと - Elixir+Phoenixが早い理由

Elixir+PhoenixのCRUDを作ってみよう系のコードやベンチマークのコードを見ていると、
(言葉は悪いですが)特に工夫もないコードしかなく、(Erlangで並行処理を宣言するspawnが使われているわけではない)
これで高速なレスポンスが可能である理由がわかりませんでした。

言語特性として並行処理が可能である、VM内でのマルチプロセスが可能である
これが高速の根拠であるのなら、Elixir+Phoenixは裏でマルチプロセス処理を行なっているから早い
ということで良いのでしょうか。それとも単にErlangの関数型言語という仕様だったり、BEAM VMが優秀だからであって、
更にPhoenixは裏で自動ビルドしているので、スクリプト言語に比べて処理が高速である、ということでしょうか。
(=並行処理機能がベンチマーク結果に寄与しているわけではない)

また、もしElixir+Phoenixが裏でマルチプロセス処理を行なっているのであれば、
|>を使わない処理は全てElixir+Phoenixによって並行処理に変換されていたりするのでしょうか。。
(以下の質問はこの前提に立って話が進みます。ここがそもそも間違っていたらすみません。)

質問したいこと - 並行処理によるDBのデッドロック

Elixir+PhoenixでのAPIサーバーを構築する記事を読んでふと感じたのですが、
Erlangの特性である並行処理って、DBアクセス時に簡単にデッドロックを引き起こしてしまいそうなのですが、
実際のところどうなのでしょうか?
(実例が思いつかなくて恐縮です。次の項目で詳しく考えたことを書いてみています。)

うまく言えませんが、関数の設計において、
従来通り設計を行えばよくて、並行処理の特性などは考慮しなくても良いのか、
並行処理の特性を考えながら設計しなければならないのか....

また、後者の場合、アクセス処理は結局DBが行うものなので
Elixirに対応できるDBの選定などが必要になってくる気がしていますが、これも実際必要でしょうか?
(たとえばsqliteは実質的にマルチプロセス向きではなく、PostgreSQLはマルチプロセスで構築されてるから、
sqliteをElixir+PhoenixのDBとして使うと速攻で破綻してしまう、とか。。)

考えたこと

仮定1

並行処理ということは、
普通にWebアプリケーションを作って、APIをPHPなんかで実装して、複数人からアクセスがきた時に発生する処理と、
Elixirで実装して、1人がアクセスしたときに発生する処理は
同じような処理が走るのではないかな(=同時DBアクセスが発生する)と想像しています。

なので、従来の実装の考え方では

「基本的に関数A内で定義してあるDBアクセス処理はこの順番で走るのだから、
この設計さえ間違えなければ、複数人アクセスがきても
誰しもが同じ順番でDBアクセスされるはずなので、問題は発生しない」

だったのが、

「Elixirで処理を関数Aにある通りに定義したが、どの処理が最初に走って終わるのかが明確ではないから
関数Aに内包される全てのDBアクセスの組み合わせを検証して、どれもデッドロックが生じないように
クエリやアクセスを考えなければならない」

となるような気がしています。。

仮定2

また、Elixir+Phoenixの早い理由がいまいちつかめていないのですが、
ソースを見ても関数をすごく細かい粒度に分割していたり、spawnを多用しているわけでもなく、
普通に他言語と同じような書き方をするだけで早くなっているような印象を受けました。
勝手な推測ですが、関数型言語ということで、関数単位で並行処理してるのかな?という妄想をしています。
(=JSにおけるvarの巻き上げのような現象が、関数単位で発生する。
つまり必ずしも上から下に書いてある通りに処理されない...というイメージです。)

例えば次のような形です。

php

//この場合、BとCはAの処理開始時に同時にスタートする public function A(){ $this->B(); $this->C(); } //こうすれば順番に処理される public function X(){ if($this->Y()){ $this->Z(); } }

結論

典型的なデッドロックの例として、
テーブルA, テーブルBがあって、
BがAに対して参照を持っている時、トランザクション1がAに対してUpdate, トランザクション2がBに対してInsertすると発生しますが、
DBアクセス処理が順番に処理されず、同時並行的に処理される場合、容易にこれが生じてしまいそうな気がしています。

なので、Elixir+Phoenixが高速な理由が仮定2の通りならば、
次のような関数の定義を行うと、デッドロックが(容易に)発生してしまうような気がしていますが、どうなのでしょうか。

elixir

def 関数A_裏でspawnが自動で行われてると仮定すると、この関数ではデッドロックが発生する?(connect) do case TableA.Update(params) do {:ok, _} -> # ... case TableB.Insert(params) do {:ok, _} -> # ...

また上のコードが真である前提に立つと、
次のような形で定義すればデッドロックが起きないような気がしていますが、
さながらコールバック地獄で、実装が大変そうだな...と感じていますが
実際にデッドロックを意識したとき、PhoenixのDBアクセス部分を設計するときのコードは
大抵こんな形になるものなのでしょうか。

elixir

def 関数A_パイプラインを使って順番に処理すれば、デッドロックが発生しない?(connect) do case TableA.Update(params) do {:ok, _} -> |> case TableB.Insert(params) do {:ok, params} -> # ... {:error, params} -> |> putMsg(:error, params)

付記

自分で調べていて混乱していたので、ここで使っている言葉の概念を次のようにまとめてみました。
(合っているといいのですが)

ことば意味
非同期処理関数と関数の間隙にキューされた処理が割り込む。ワンオペでうまいこと厨房を回してるイメージ(レンジを3分にセットして、その間に配膳して、チンされたら取り出して....みたいな)
並行処理(マルチプロセス/マルチタスク)別のプロセスを起動する。その分リソースを食う。複数人で処理を行うイメージ。きちんと管理しないと同期しない。お店で例えるとドライブスルー担当、調理担当、配膳担当がいて、それぞれちゃんと現在の業務内容を共有しないと業務が滞るイメージ
並列処理(マルチスレッド)1つのプロセスの中で複数のスレッドを起動する。スレッドの使うメモリは共通。並行処理を包摂している。お店で例えると何店舗もあるチェーン店のそれぞれの動きを俯瞰で見てるイメージ

正直言ってデッドロック排他制御などの用語の字面だけ知っているような初心者で、
Elixirについては実際にコードも書いたことがなく、
上の表を見てもわかるように、マルチ***についても全く詳しくないです。

このFWが早い理由と、並行でDBアクセスが発生するときどう処理するのか、といった点に興味を持っただけなので、
完全に杞憂だったらすみません。

十分な知識がないまま、色々質問してしまってすみません。
ご存知の方、ご回答のほどよろしくお願いいたします。

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Erlang

Erlangとは、多目的でありガーベッジコレクションを行うプログラミング言語および実行環境です。Erlangは並行処理・分散化された環境・フォルトトレランスを実装しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Elixir

Elixirは、並列処理や関数型に特化した、Erlang VM (BEAM) 上で動作する汎用プログラミング言語です。分散システム、耐障害性、ソフトリアルタイムシステムなどの機能を持ちます。