首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用Scotty的网络I/O吞吐量意外降低

使用Scotty的网络I/O吞吐量意外降低
EN

Stack Overflow用户
提问于 2015-06-03 12:42:52
回答 1查看 359关注 0票数 15

我尝试对Scotty进行基准测试,以测试网络I/O效率和总体吞吐量。

为此,我设置了两个用Haskell编写的本地服务器。其中一个不做任何事情,只是充当一个API。

同样的代码是

代码语言:javascript
复制
{-# 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"

我编写了另一个服务器,它调用此服务器并返回响应。

代码语言:javascript
复制
{-# 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基准测试,并获得了极高的吞吐量。

代码语言:javascript
复制
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个错误。

我检查了非常低的限制。

代码语言:javascript
复制
ulimit -n
256

我将这些限制增加到

代码语言:javascript
复制
ulimit -n 10240

我再次运行wrk,这一次很明显,吞吐量已经大幅降低。

代码语言:javascript
复制
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无关。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-23 04:12:00

@Yuras的类比是正确的。再次运行服务器时,所有与非2xx状态代码相关的问题都消失了。

主代码块中的第一行是罪魁祸首。我把这行改成

代码语言:javascript
复制
main = do 
  let man = newManager defaultManagerSettings

代码语言:javascript
复制
main = do 
  man <- newManager defaultManagerSettings

瞧,没有任何问题。此外,程序的高内存使用率从之前的1 1GB稳定到21MB。

不过我不知道原因。如果能对此有一个解释那就太好了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30611005

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档