GolangおよびElixirで最もシンプルなHTTPサーバー。 性能比較

画像

数週間前、私はGoでHTTPサーバーの最も単純なを取り上げ、そのパフォーマンスを測定することにしました。 それから私は大胆にフェニックスを取り、同じテストで運転し、動揺した。 結果はElixir / Erlang(Goの場合45133 RPS、Phoenixの場合のみ3065 RPS)を支持していませんでした。 しかし、フェニックスは難しいです。 シンプルさと開発ロジックが、Go上にあるものと少なくともほぼ同等である必要があります。パスがある場合-「/」とそのハンドラー。 カウボーイ + プラグソリューションは論理的な例えのように思えました。「/」をキャッチして応答するルーターがあります。 結果は殺されました-Elixir / Erlangは再び遅くなることが判明しました:







Golang sea@sea:~/go$ wrk -t10 -c100 -d10s http://127.0.0.1:4000/ ... 452793 requests in 10.03s, 58.30MB read Requests/sec: 45133.28 Transfer/sec: 5.81MB
      
      





 elixir cowboy plug sea@sea:~/http_test$ wrk -t10 -c100 -d10s http://127.0.0.1:4000/ ... 184703 requests in 10.02s, 28.57MB read Requests/sec: 18441.79 Transfer/sec: 2.85MB
      
      





生き方は? 2週間、私は眠らず、ほとんど食べませんでした。 私が信じていたこれらすべてのこと:完璧なvmアーラン、FP、グリーンプロセスは、踏みにじられ、燃やされ、風に放たれました。 ショックから少し離れて、落ち着いて、鼻をこすりながら、私は問題が何であるかを理解することにしました。







急いでいる人のために、私はすぐに答えます。
その理由は、私がテストしたあまり正確ではない条件にあった

サーバーとテストプログラムは、VirtualBOX内の同じ仮想マシンで実行され、2つのコアが強調表示されています。







しかし

そのようなまたは同様の条件で作業する必要があることが判明した場合、Goは本当に良い結果を示します





さらに
静的にコンパイルされたプログラムは、インタープリターを備えた仮想マシンよりも高速でなければなりません







テストコンピューター



私がテストした方法。 私は、Windows 7 x64、i7、8 Gb RAMプロセッサー、およびLinuxを搭載したラップトップで作業しています。私の場合、Ubuntu 16ではVirtualBOX内で実行しています。 彼女のために、1 Gb RAMと2コアを割り当てました。 この仮想マシン内でHTTPサーバーを起動し、同じマシン上でabwrkのテストを開始しました 。 この状況では、同じマシンにサーバーとテストの両方がロードされていることがわかります。 ネットワークを介したデータ伝送は、ネットワークを介した伝送がないため、制限を課しません。







その結果、完全に敗北しました。







go vs cowboy wrk -t10 -c100 -d10s http://127.0.0.1-00-00000/
 Go: sea@sea:~/go$ wrk -t10 -c100 -d10s http://127.0.0.1:4000/ Running 10s test @ http://127.0.0.1:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 65.18ms 109.44ms 1.05s 86.48% Req/Sec 4.60k 5.87k 25.40k 86.85% 452793 requests in 10.03s, 58.30MB read Requests/sec: 45133.28 Transfer/sec: 5.81MB Elixir cowboy: sea@sea:~/http_test$ wrk -t10 -c100 -d10s http://127.0.0.1:4000/ Running 10s test @ http://127.0.0.1:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 8.94ms 11.38ms 123.57ms 86.53% Req/Sec 1.85k 669.61 4.99k 71.70% 184703 requests in 10.02s, 28.57MB read Requests/sec: 18441.79 Transfer/sec: 2.85MB
      
      



go vs cowboy wrk -t10 -c1000 -d10s http://127.0.0.1-00-00000/
 Go: sea@sea:~/go$ wrk -t10 -c1000 -d10s http://127.0.0.1:4000/ Running 10s test @ http://127.0.0.1:4000/ 10 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 61.16ms 231.88ms 2.00s 92.97% Req/Sec 7.85k 8.65k 26.13k 79.49% 474853 requests in 10.09s, 61.14MB read Socket errors: connect 0, read 0, write 0, timeout 1329 Requests/sec: 47079.39 Transfer/sec: 6.06MB Elixir cowboy: sea@sea:~/http_test$ wrk -t10 -c1000 -d10s http://127.0.0.1:4000/ Running 10s test @ http://127.0.0.1:4000/ 10 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 123.00ms 303.25ms 1.94s 88.91% Req/Sec 2.06k 1.85k 11.26k 71.80% 173220 requests in 10.09s, 26.79MB read Socket errors: connect 0, read 0, write 0, timeout 43 Requests/sec: 17166.03 Transfer/sec: 2.65MB
      
      





Erlang / Elixirを防御するために言えることは、タイムアウトの数が少ないことだけです。 HiPEでアプリケーションを構築しても、パフォーマンスは向上しませんでした。 しかし、まず最初に







テスト環境v.2



仮想マシンではなく、スタンドアロンシステムでテストする方が良いことが明らかになりました。 テストしたhttpサーバーをより弱いマシンに配置することをお勧めします。テストマシンは、サーバーを完全にいっぱいにして技術的な能力の限界に到達できるように、より強力にする必要があります。 制限に陥らないように、高速ネットワークを使用することをお勧めします。







そのため、テストマシンとして、ラップトップをi7に残すことにしました。 そして、サーバーとして、Orange PI Oneを苦しめることにしました。 ネットワーク上での交換速度を制限するよりも、パフォーマンスを実行することをお勧めします。 オレンジPI Oneは、100 Mbpsの速度でUTPを介してルーターに接続されています。







画像







製造元のWebサイトでは、Orange PI Oneの周波数が1200 MHzのA7 Quad Coreプロセッサを搭載していることが示されました。 しかし、開発者のエラーにより、システム全体がオーバーヒートのカーネルアラートに悩まされているため、プロセッサの速度を600 MHzに固定しました。 だから、それはさらに面白いでしょう。 システムは安定して動作しますが、何もしなくても、平均負荷は2.00、2.01、2.05です(これは奇妙です)。 Ubuntu 14がインストールされており、メモリは512 MBなので、念のために、スワップセクションをUSBフラッシュドライブ上のファイルに接続しました。







画像<h4>ラウンド2 </ h4>







プロジェクトをGoに、ElixirをOrange PIに転送するために、Githubで2つのプロジェクトをすぐに作成しました。







https://github.com/UA3MQJ/go-small-http

https://github.com/UA3MQJ/elx-small-http-cowboy







オレンジPIのGolangは問題なく配信されました。 しかし、Erlang / Elixirを使用すると、少し作業しなければなりませんでした。 しかし、この作業は長い間行われてきました。 プロジェクトの組み立てと立ち上げはスムーズに進みました。 テストとして、Windowsで動作するツールを取りました。これはJmeterです。







最初のテストでは、次のパラメーターを使用します。







画像







彼らは...力が等しいことを示しました!







RPS-移動:







画像







RPS-エリクサー:







画像







応答時間-移動:







画像







応答時間-エリクサー:







画像







興味深い観察



Goは常に1つのコアで動作します:







画像







エリクサーが全員と一度に:







画像







この球面テストでは、エリクサーが勝ちました。







go vs cowboy wrk -t10 -c100 -d10s http://192.168.1.16-00-00000/
 Go: sea@sea:~$ wrk -t10 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 19.04ms 7.70ms 81.05ms 70.53% Req/Sec 531.09 78.11 828.00 77.10% 52940 requests in 10.02s, 6.82MB read Requests/sec: 5282.81 Transfer/sec: 696.46KB Elixir cowboy: sea@sea:~$ wrk -t10 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 14.27ms 10.54ms 153.60ms 95.81% Req/Sec 753.20 103.47 1.09k 80.40% 74574 requests in 10.04s, 11.53MB read Requests/sec: 7429.95 Transfer/sec: 1.15MB
      
      





go vs cowboy wrk -t100 -c100 -d10s http://192.168.1.16-00-00000/
 Go: sea@sea:~$ wrk -t100 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 60.14ms 137.57ms 1.52s 94.28% Req/Sec 38.45 20.62 130.00 60.30% 34384 requests in 10.10s, 4.43MB read Requests/sec: 3404.19 Transfer/sec: 448.79KB Elixir cowboy: sea@sea:~$ wrk -t100 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 13.32ms 5.25ms 90.37ms 73.31% Req/Sec 75.51 22.04 191.00 67.49% 75878 requests in 10.10s, 11.74MB read Requests/sec: 7512.75 Transfer/sec: 1.16MB
      
      





go vs cowboy wrk -t100 -c500 -d10s http://192.168.1.16-00-00000/
 Go: sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 93.81ms 18.63ms 328.78ms 84.98% Req/Sec 53.13 11.12 101.00 77.60% 52819 requests in 10.10s, 6.80MB read Requests/sec: 5232.01 Transfer/sec: 689.77KB Elixir cowboy: sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 93.24ms 96.80ms 1.26s 94.47% Req/Sec 62.95 23.33 292.00 79.87% 61646 requests in 10.10s, 9.53MB read Requests/sec: 6106.38 Transfer/sec: 0.94MB
      
      





しかし、 HiPEを使用してerlangサーバーを起動するとどうなりますか?







これを行うには、まずその方法をグーグルで検索する必要があります。 Erlangでこれを行う方法は明らかです。 しかし、私はElixirについてGoogleで検索する必要がありました。 さらに、HiPEをテストした人は、HiPEで標準的なものよりもさらに遅くなることが多いと書いています。 これは、HiPEなしで依存関係を構築できる(そして同じモードで構築する必要がある)という事実に加えて、コンテキストスイッチのシステムカウンターを評価する必要があるためです。多くのスイッチがある場合、これはパフォーマンスに悪影響を与え、悪い結果を示します。







HiPEコンパイラーでプロジェクトの依存関係を構築する







 $ ERL_COMPILER_OPTIONS="[native,{hipe, [verbose, o3]}]" mix deps.compile --force
      
      





プロジェクトをまとめる







 $ ERL_COMPILER_OPTIONS="[native,{hipe, [verbose, o3]}]" mix compile
      
      





テストでは、HiPEが成長しないことを示しましたが、逆に悪い結果を示しています。







カウボーイvsカウボーイ(HiPE)wrk -t100 -c500 -d10s http://192.168.1.16-00-00000/
 Elixir cowboy: sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 93.24ms 96.80ms 1.26s 94.47% Req/Sec 62.95 23.33 292.00 79.87% 61646 requests in 10.10s, 9.53MB read Requests/sec: 6106.38 Transfer/sec: 0.94MB Elixir cowboy (HiPE): sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 111.84ms 160.53ms 1.89s 95.42% Req/Sec 59.19 29.68 383.00 81.63% 56425 requests in 10.10s, 8.72MB read Socket errors: connect 0, read 0, write 0, timeout 34 Requests/sec: 5587.39 Transfer/sec: 0.86MB
      
      





逆襲



Goが1つのプロセッサで動作するのはなぜですか? Goがまだ1つのプロセッサで動作しているときに、古いバージョンにデフォルトで付属するGoのパッケージでしょうか? そうです!







 sea@OrangePI:~$ go version go version go1.2.1 linux/arm
      
      





更新して繰り返す必要があります! armv7用にアセンブルされたGoバージョン1.7.3は、 https: //github.com/hypriot/golang-armbuilds/releasesで見つかりました







このバージョンで構築されたGolangサーバーは、4つのカーネルすべてをすでにロードしています。







画像







カウボーイvs Go1.7.4 wrk -t100 -c500 -d10s http://192.168.1.16-00-00000/
 Elixir cowboy: sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 93.24ms 96.80ms 1.26s 94.47% Req/Sec 62.95 23.33 292.00 79.87% 61646 requests in 10.10s, 9.53MB read Requests/sec: 6106.38 Transfer/sec: 0.94MB sea@sea:~/tender_pro_bots$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 70.17ms 57.84ms 754.39ms 90.61% Req/Sec 84.09 31.01 151.00 73.20% 78787 requests in 10.10s, 10.14MB read Requests/sec: 7800.43 Transfer/sec: 1.00MB
      
      





Goが先に跳躍しています!







Go and fasthttp



Golangのバージョンの変更を推奨した後、 fasthttpとgccgoからアドバイスを受けました。 最初のものから始めましょう。







https://github.com/UA3MQJ/go-small-fasthttp







ダウンロードを見てみましょう。 4つのコアすべてがロードされていることがわかりますが、100%ではありません。







画像







さあ







go vs cowboy wrk -t10 -c100 -d10s http://192.168.1.16-00-00000/
 Go fasthttp: sea@sea:~/tender_pro_bots$ wrk -t10 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 43.56ms 85.95ms 738.51ms 89.71% Req/Sec 676.18 351.12 1.17k 70.80% 67045 requests in 10.04s, 9.78MB read Requests/sec: 6678.71 Transfer/sec: 0.97MB Elixir cowboy: sea@sea:~$ wrk -t10 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 14.27ms 10.54ms 153.60ms 95.81% Req/Sec 753.20 103.47 1.09k 80.40% 74574 requests in 10.04s, 11.53MB read Requests/sec: 7429.95 Transfer/sec: 1.15MB
      
      





go vs cowboy wrk -t100 -c100 -d10s http://192.168.1.16-00-00000/
 Go fasthttp: sea@sea:~/tender_pro_bots$ wrk -t100 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 8.95ms 3.08ms 42.23ms 75.69% Req/Sec 112.61 16.65 320.00 70.18% 112561 requests in 10.10s, 16.42MB read Requests/sec: 11144.39 Transfer/sec: 1.63MB Elixir cowboy: sea@sea:~$ wrk -t100 -c100 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 13.32ms 5.25ms 90.37ms 73.31% Req/Sec 75.51 22.04 191.00 67.49% 75878 requests in 10.10s, 11.74MB read Requests/sec: 7512.75 Transfer/sec: 1.16MB
      
      





go vs cowboy wrk -t100 -c500 -d10s http://192.168.1.16-00-00000/
 Go fasthttp: sea@sea:~/tender_pro_bots$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 46.44ms 10.69ms 327.50ms 93.21% Req/Sec 107.71 15.10 170.00 82.06% 107349 requests in 10.10s, 15.66MB read Requests/sec: 10627.97 Transfer/sec: 1.55MB Elixir cowboy: sea@sea:~$ wrk -t100 -c500 -d10s http://192.168.1.16:4000/ Running 10s test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 93.24ms 96.80ms 1.26s 94.47% Req/Sec 62.95 23.33 292.00 79.87% 61646 requests in 10.10s, 9.53MB read Requests/sec: 6106.38 Transfer/sec: 0.94MB
      
      





fasthttpを使用したGolangは、自分よりも速く、エリクサーカウボーイよりも高速でした。







測定の正確さについて



より注意するために、カウボーイとGo-は異なるバイト数で応答することがわかります。 これは、発行するHTTPヘッダーが異なるためです。







発行に行く:







 HTTP/1.1 200 OK Date: Thu, 30 Mar 2017 14:37:08 GMT Content-Length: 18 Content-Type: text/plain; charset=utf-8
      
      





カウボーイの問題:







 HTTP/1.1 200 OK server: Cowboy date: Thu, 30 Mar 2017 14:38:17 GMT content-length: 18 cache-control: max-age=0, private, must-revalidate
      
      





ご覧のとおり、カウボーイは「server:Cowboy」という行も追加します。これは、カウボーイの場合に転送されるバイト数に必然的に影響します。 送信されるデータはそれ以上です。







更新しました。 BEAMでepollを操作するオプションを含めるのを忘れました



+ Kキーを思い出してくれたnwalkerに感謝します。 起動時にそれを示します:







 sea@OrangePI:~/http_tests/elx-small-http-cowboy$ iex --erl '+K true' -S mix Erlang/OTP 19 [erts-8.1] [source] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:true]
      
      





今回は10秒ではなく、1分をロードします。







カウボーイvsカウボーイepoll wrk -t100 -c500 -d60s http://192.168.1.16-00-00000/
 Elixir cowboy: sea@sea:~/tender_pro_bots$ wrk -t100 -c500 -d60s http://192.168.1.16:4000/ Running 1m test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 78.63ms 38.59ms 1.00s 90.17% Req/Sec 65.08 14.19 158.00 54.94% 389764 requests in 1.00m, 60.28MB read Requests/sec: 6485.27 Transfer/sec: 1.00MB Elixir cowboy with epoll: sea@sea:~/tender_pro_bots$ wrk -t100 -c500 -d60s http://192.168.1.16:4000/ Running 1m test @ http://192.168.1.16:4000/ 100 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 90.25ms 78.45ms 1.96s 95.36% Req/Sec 59.91 19.71 370.00 64.78% 356572 requests in 1.00m, 55.15MB read Socket errors: connect 0, read 0, write 0, timeout 21 Requests/sec: 5932.94 Transfer/sec: 0.92MB
      
      





しかし、epollをオンにしたOrangePIでは、結果は悪化しました。







結論



そして、誰もが自分で結論を出します。 Go'shniksはGo、そしてErlangistsとElixirsは彼らの製品を喜ぶでしょう。 誰もが自分のままになります。 Erlangの支持者はGoの速度を確認しました。Goの速度は、桁違いに2倍(わずかに少ない)でしたが、Erlangのすべての機能を10倍に増やしても放棄しませんでした。 同時に、Go'shnikはErlangに興味を持ちそうになく、速度が遅くなり、関数型プログラミングの学習で起こりうるすべての困難について耳にします。







今日の世界では、プログラマーの時間は高価で、時には機器のコストよりも高くなります。 テストは、「球状」タスクの「球状」RPSだけでなく、開発時間、洗練とメンテナンスの複雑さでも必要です。 経済的実現可能性。 しかし、時にはあなたは本当にすべてをdrれさせたい 馬力 メガヘルツと優れた会社でいくつかのレースを手配します! 素晴らしい乗り心地。







画像








All Articles