94
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Elixirでプロセス5000万くらい作ってみた

Elixirで、表題の通り5000万プロセスぐらい作ってみた。

Elixirで20万プロセスを作ったその後

Elixirはerlang VMをベースとした関数型の言語だ。Rubyっぽい文法も使えて便利である。erlangの特徴である、軽量のプロセスが使えるのが一つの売りである。

少し前に、Elixirでプロセス20万位作ってみた という投稿を行った。その時は、デフォルトのprocess_limitのサイズ約26万を超えて、プロセスを指定する方法がわからなかった。親切な方から、26万を超えるprocess_limitの指定方法を教えてもらったので、それならどれくらいまで行けるかと思い、5000万までプロセスを作ってみた。プロセスの単位がインフレしすぎて、実際何の単位なのかわからなくなった。

erlangのプロセス

この場合のプロセスは、erlangで使われる軽量プロセスのことだ。プロセスはerlangの並列処理を形作っており、それぞれ別のCPUでも動作する。プロセスにすることで複数のCPUを効率的に使える。
プログラムの並列度を高める方法として、(通常の)マルチプロセス、マルチスレッド、コルーチン、rubyのfiberなどがあるが、そのような中で、erlangの軽量プロセスがどの程度並列に動くか試してみた。

通常のOSのプロセスを複数立ち上げた場合、大体数百プロセス以上は辛くなりそう。また、スレッドの場合は、数千レベルで辛くなるだろう。一方、erlangの軽量プロセスは数万のオーダーで並列化出来ることが知られている。

実験環境

実験環境として、AWSのm4.10largeを利用した

インスタンスタイプ CPU メモリ OS erlang elxir
m4.10xlarge 40 160GiB Ubuntu14.04 Erlang/OTP 18 1.1.1

40CPUで160GiBだ。昔、erlangが途中で落ちてコアを吐いたことがあり、その時はメモリいっぱい使っていて、HDDのそのメモリーイメージそのまま吐いたことがあった(うろ覚え)。160GiBのコアを吐く可能性があったのでHDDDは250GB程度用意した。

erlangとElixirのバージョンは以下

Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:40:40] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.1.1) - press Ctrl+C to exit (type h() ENTER for help)

erlangの最大プロセス数の指定

こちらのブログにあるが、+P 1024などと指定すれば、最大プロセス数を設定できる。
elixirで使う場合には、

export ELIXIR_ERL_OPTIONS="+P 50000000"

と環境変数を設定すれば、最大プロセス数を指定できる。

5000万プロセスを作ってみる。

次のレポジトリに、今回使ったコード一式を用意した。簡単なkey-value storeを5000万個作ってそれぞれに値を入れ引き出す。簡単なプログラムだ。殆どの処理はlib/many_process.exに入っている。値の取得を一回しかやらないため、多くのプロセスは一回値の出し入れをした後、休眠状態になる。

git cloneで手に入れた後、mk.shを実行

iexが立ち上がった後、次のようにした。

Interactive Elixir (1.1.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(bar@localhost)1> :erlang.system_info(:process_limit)
67108864
iex(bar@localhost)2> iex(bar@localhost)2> ManyProcessFactory.main(["--pnum=50000000"])

のようにすれば良い。

そうすると、ひたすら5000万のプロセスを作る。
5000万プロセスが出来た段階で、大体メモリは130GB位使っていた。

top

free

実験結果

elixirを使えば、大体5000万プロセスくらい作れる。ただしメモリーは139GB程度使用する。

その他Tips

バイナリでの実行

当初は、mix escript.buildでプログラムを作って実行していたが、

export ELIXIR_ERL_OPTIONS="+P 50000000"
./many_process --pnum=10000

みたいにして、上手くプロセス数が変更できず、仕方なくiexで立ち上げる方式を採用した。

プロセス数とプロセスリミット

プロセス数は

psize = Enum.count(:erlang.processes)

で取れた。
プロセス数の上限は

plimit = :erlang.system_info(:process_limit)

で取れた。

afterを使った定時実行

afterを使えば、例えば10秒毎に、プロセス数を取得するみたいな構文がかけるが、このやり方がベストプラクティスかはわからない。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
94
Help us understand the problem. What are the problem?