15

Scotty のベンチマークを実行して、ネットワーク I/O の効率と全体的なスループットをテストしようとしました。

このために、Haskell で記述された 2 つのローカル サーバーをセットアップしました。何もせず、単に API として機能するもの。

同じコードは

{-# LANGUAGE OverloadedStrings #-}


import Web.Scotty

import Network.Wai.Middleware.RequestLogger 

import Control.Monad
import Data.Text
import Control.Monad.Trans
import Data.ByteString
import Network.HTTP.Types (status302)
import Data.Time.Clock
import Data.Text.Lazy.Encoding (decodeUtf8)
import Control.Concurrent
import Network.HTTP.Conduit
import Network.Connection (TLSSettings (..))
import Network.HTTP.Client
import Network
main = do 
  scotty 4001 $ do
    middleware logStdoutDev
    get "/dummy_api" $ do
        text $ "dummy response"

このサーバーを呼び出して応答を返す別のサーバーを作成しました。

{-# LANGUAGE OverloadedStrings #-}


import Web.Scotty

import Network.Wai.Middleware.RequestLogger 

import Control.Monad
import Control.Monad.Trans
import qualified Data.Text.Internal.Lazy as LT
import Data.ByteString
import Network.HTTP.Types (status302)
import Data.Time.Clock
import Data.Text.Lazy.Encoding (decodeUtf8)
import Control.Concurrent
import qualified Data.ByteString.Lazy as LB
import Network.HTTP.Conduit
import Network.Connection (TLSSettings (..))
import Network.HTTP.Client
import Network


main = do 
  let man = newManager defaultManagerSettings 
  scotty 3000 $ do
    middleware logStdoutDev

    get "/filters" $ do
        response <- liftIO $! (testGet man)
        json $ decodeUtf8 (LB.fromChunks response)

testGet :: IO Manager -> IO [B.ByteString]
testGet manager = do
    request <- parseUrl "http://localhost:4001/dummy_api"
    man <- manager
    let req = request { method = "GET", responseTimeout = Nothing, redirectCount = 0}
    a <- withResponse req man $ brConsume . responseBody
    return $! a

これらの両方のサーバーを実行して、wrkベンチマークを実行したところ、非常に高いスループットが得られました。

wrk -t30 -c100 -d60s "http://localhost:3000/filters"
Running 1m test @ http://localhost:3000/filters
  30 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    30.86ms   78.40ms   1.14s    95.63%
    Req/Sec   174.05     62.29     1.18k    76.20%
  287047 requests in 1.00m, 91.61MB read
  Socket errors: connect 0, read 0, write 0, timeout 118
  Non-2xx or 3xx responses: 284752
Requests/sec:   4776.57
Transfer/sec:      1.52MB

これは、Phoenix などの他の Web サーバーよりも大幅に高かったのですが、応答の大部分がファイル記述子の枯渇により発生した 500 エラーであったため、これは何の意味もないことに気付きました。

かなり低い制限を確認します。

ulimit -n
256

これらの制限を

ulimit -n 10240

もう一度 wrk を実行したところ、明らかに十分なスループットが大幅に低下していました。

wrk -t30 -c100 -d60s "http://localhost:3000/filters"
Running 1m test @ http://localhost:3000/filters
  30 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   105.69ms  161.72ms   1.24s    96.27%
    Req/Sec    19.88     16.62   120.00     58.12%
  8207 requests in 1.00m, 1.42MB read
  Socket errors: connect 0, read 0, write 0, timeout 1961
  Non-2xx or 3xx responses: 1521
Requests/sec:    136.60
Transfer/sec:     24.24KB

500 エラーの量は減少しましたが、完全にはなくなりませんでした。Ginと Phoenix のベンチマークScottyを行ったところ、500 の応答がない場合よりもはるかに優れていました。

欠けているパズルのピースは何ですか? デバッグに失敗している問題があると思われます。

http-conduitはこれらのエラーと多くの関係があり、http-clientライブラリはフードの下でそれを使用しており、これは とは何の関係もないことを理解していScottyます。

4

1 に答える 1

1

@ユラスの類推は正しかった。サーバーを再度実行すると、2xx 以外のステータス コードに関連するすべての問題がなくなりました。

メインブロックの最初の行が原因でした。から行を変更しました

main = do 
  let man = newManager defaultManagerSettings

main = do 
  man <- newManager defaultManagerSettings

出来上がり、問題はありませんでした。また、プログラムの高いメモリ使用量は、以前の 1GB から 21MB に安定しました。

理由はわからないけど。これについての説明があるとよいでしょう。

于 2015-10-22T20:11:59.837 に答える