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
ます。