Difference between revisions of "Simple Servers"

From HaskellWiki
Jump to navigation Jump to search
Line 1: Line 1:
 
Some example of simple web server designs using increasingly more sophisticated approaches. Requirements:
 
Some example of simple web server designs using increasingly more sophisticated approaches. Requirements:
   
* Recent GHC
+
* Recent GHC
* Libraries: [http://hackage.haskell.org/package/network network], [http://hackage.haskell.org/package/network-bytestring network-bytestring], [http://github.com/tibbe/event/blob/master/docs/design.md event]
+
* Libraries: [http://hackage.haskell.org/package/network network], [http://hackage.haskell.org/package/network-bytestring network-bytestring], [http://github.com/tibbe/event/blob/master/docs/design.md event]
   
 
Benchmarks with httperf,
 
Benchmarks with httperf,
Line 36: Line 36:
 
Measurements:
 
Measurements:
 
 
* <code>$ ghc -O2 --make A.hs</code>
+
* <code>$ ghc -O2 --make A.hs</code>
* Request rate: 6569.1 req/s (0.2 ms/req)
+
* Request rate: 6569.1 req/s (0.2 ms/req)
   
 
=== Concurrent, with network-bytestring ===
 
=== Concurrent, with network-bytestring ===
Line 70: Line 70:
 
Measurements:
 
Measurements:
   
* <code>$ ghc -O2 --make H.hs</code>
+
* <code>$ ghc -O2 --make H.hs</code>
* Request rate: 9901.7 req/s (0.1 ms/req)
+
* Request rate: 9901.7 req/s (0.1 ms/req)
   
 
=== Epoll-based event callbacks ===
 
=== Epoll-based event callbacks ===
Line 115: Line 115:
 
Measurements:
 
Measurements:
   
* <code>ghc -O2 --make Epoll.hs</code>
+
* <code>ghc -O2 --make Epoll.hs</code>
* Request rate: 15042.6 req/s (0.1 ms/req)
+
* Request rate: 15042.6 req/s (0.1 ms/req)
   
 
So significantly better.
 
So significantly better.

Revision as of 02:00, 18 January 2010

Some example of simple web server designs using increasingly more sophisticated approaches. Requirements:

Benchmarks with httperf,

   $ httperf --server=localhost --port=5002 --uri=/ --num-conns=10000

Basic concurrent server

Concurrent, with String IO:

import Network
import Control.Concurrent
import System.IO

main = withSocketsDo $ do
    sock <- listenOn $ PortNumber 5002
    loop sock

loop sock = do
   (h,_,_) <- accept sock
   forkIO $ body h
   loop sock
  where
   body h = do
       hPutStr h msg
       hFlush h
       hClose h

msg = "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nPong!\r\n"

Measurements:

  • $ ghc -O2 --make A.hs
  • Request rate: 6569.1 req/s (0.2 ms/req)

Concurrent, with network-bytestring

Now, using bytestring IO (via the network-bytestring package) (but still using the rts' select-based preemptive threads)

{-# LANGUAGE OverloadedStrings #-}

import Data.ByteString.Char8

import Network hiding (accept)
import Network.Socket
import Network.Socket.ByteString (sendAll)
import Control.Concurrent

main = withSocketsDo $ do
    sock <- listenOn $ PortNumber 5002
    loop sock

loop sock = do
   (conn, _) <- accept sock
   forkIO $ body conn
   loop sock
  where
   body c = do sendAll c msg
               sClose c

msg = "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nPong!\r\n"

Measurements:

  • $ ghc -O2 --make H.hs
  • Request rate: 9901.7 req/s (0.1 ms/req)

Epoll-based event callbacks

Now, instead of using the RTS' select mechanism to wake up threads, we use a custom epoll handler. Using epoll-based event handling, and bytestring IO:

{-# LANGUAGE OverloadedStrings #-}

-- A simple example of an epoll based http server in Haskell.
--
-- Uses two libraries:
--   * network-bytestring, bytestring-based socket IO.
--      - cabal install network-bytestring: 
--
--   * haskell-event, epoll-based scalable IO events
--      - git clone git://github.com/tibbe/event.git
--      - autoreconf ; then cabal install

import Network hiding (accept)
import Network.Socket (fdSocket, accept)
import Network.Socket.ByteString
import Data.ByteString.Char8
import System.Event
import System.Posix
import System.Posix.IO

main = withSocketsDo $ do
    sock <- listenOn $ PortNumber 5002
    let fd = fromIntegral (fdSocket sock)
    mgr <- new
    registerFd mgr (client sock) fd evtRead
    loop mgr

client sock _ _ = do
    (c,_) <- accept sock
    sendAll c msg
    sClose c

msg = "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nPong!\r\n"

Measurements:

  • ghc -O2 --make Epoll.hs
  • Request rate: 15042.6 req/s (0.1 ms/req)

So significantly better.