Hi all,

I would like to let you know some updates on this:

1) Results of performance measurement with various configurations and the 
SPDY-Redirector
2) Switching to Async I/O for the implementation of the IIS module


1) Performance

> -----Original Message-----
> From: Christopher Schultz [mailto:ch...@christopherschultz.net]
> Sent: Monday, September 30, 2013 8:53 PM
> To: Tomcat Developers List
> Subject: Re: Possible IIS SPDY Redirector for Tomcat
> 
> Konstantin,
> 
> > So it seems that the main performance problem is IIS when using
> > managed code/ASP.Net to write to the response, but I need to do
> > additional testing.
> 
> Wow. Are you sure the thread burning the CPU is the one running the
> above code? Seems ... unfortunate.

I have now done additional testing with various configurations and I think my 
previous statement was wrong - IIS is not the culprit here. I guess it's the 
multiplexing that the SPDY Redirector is doing (multiplexing multiple HTTP 
requests on a single TCP connection) that causes the CPU usage. However, I 
don't think that there is a real problem here comparing the performance/CPU 
usage to Jetty.

To measure performance (speed and CPU usage), I set up a 2-CPU VM with IIS 8.5 
(Windows Server 2012 R2 x64), Tomcat 7.0.42 (for ISAPI Redirector) and Jetty 
8.1.13 (for SPDY Redirector). For IIS, I created one web application using the 
SPDY Redirector (connecting to Jetty) and one web application using the ISAPI 
Redirector (connecting to Tomcat).
I then created a Servlet 3.0 webapp with a Servlet that produces ~ 700 MB of 
random data, sending it in 32 KB chunks to the client, using the following code:

    protected void doGet(HttpServletRequest request, HttpServletResponse 
response) throws ServletException, IOException {
        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment; 
filename=\"myTextfile.txt\"");

        byte[] bytes = new byte[32768];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte)'a';
        }
        
        long bytesWritten = 0;
        long lastDisplay = 0;
        try (OutputStream out = response.getOutputStream()) {
            while (true) {
                out.write(bytes);
                bytesWritten += bytes.length;
                
                if (bytesWritten - lastDisplay > 500 * 1024) {
                    lastDisplay = bytesWritten + 500 * 1024;
                    System.out.println(bytesWritten + " Bytes written 
(completely).");
                }
                
                if (bytesWritten > 700 * 1024 * 1024)
                    break;
            }
        }
    }


Then, I created a C# application that creates a TCP connection and sending the 
following raw request:
GET /TestSpdyServer/BigFileProducerServlet HTTP/1.1
Host: localhost
Connection: close

and reads from the TCP connection until it is closed, counting the bytes and 
milliseconds to calculate the average speed.
I then tested the speed when 1) connecting directly to Jetty (HTTP), 2) 
connecting directly to Tomcat (HTTP), 3)+4) connecting to IIS with 
SPDY-Redirector, 5) connecting to IIS with ISAPI redirector, 6) connecting to 
IIS using a ASP.Net handler producing 700 MB of random data, equally to the 
Servlet above.
This is what I got:

1) JettyHttp-Direct: 260 MB/s (Jetty: 47% CPU)
2) TomcatHttpBio-Direct: 275 MB/s (Tomcat: 45% CPU)
3) Iis-SpdyRedirector(Async)-JettySpdy (64 KB initial window size): 170 MB/s 
(Jetty: 35% CPU, IIS: 43% CPU)
4) Iis-SpdyRedirector(Async)-JettySpdy (128 KB initial window size): 205 MB/s 
(Jetty: 40% CPU, IIS: 50% CPU)
5) Iis-IsapiRedirector-TomcatAjpBio: 190 MB/s (Tomcat: 10% CPU, IIS: 20% CPU)
6) Iis-Asp.Net-Handler-Direct: 400 MB/s, 50% CPU

As you can see, with the SPDY redirector, both Jetty and IIS have a high amount 
of CPU usage (probably the costs of multiplexing) whereas the ISAPI redirector 
had a low CPU usage. However, I'm pretty happy with the current performance of 
the SPDY redirector.


2) Switching the implementation of the IIS module to Async I/O - see [1]: 
"Scalable Apps with Asynchronous Programming in ASP.NET"

.Net 4.5 introduces new "async" and "await" keywords for C# that allow you to 
easily create asynchronous code. E.g. you can write code just as you would with 
synchronous operations, and the compiler will create the Async State Machine 
for you.

As the previous implementation of the SPDY Redirector used blocking/synchronous 
IO for the IIS module, it meant that 1 thread was used per request. Now imagine 
you have 200 clients that simultaneously do requests to a resource that 
produces the response body very slowly, it would mean that IIS had to create 
200 threads for serving the requests. This can be a problem also e.g. for 
long-polling comet applications (where it may take some time until the HTTP 
response is sent) or Websocket connections (however WebSockets with IIS 8 can 
only be used with async IO so I had to do the switch to Async anyway for being 
able to support Websocket).

For example, with Servlet 3.1 you can use non-blocking I/O so that you don't 
need to acquire a thread for the complete duration of a request.

Therefore, I now switched the IIS module implementation of the SPDY redirector 
to async IO (with the "async" and "await" keywords this was rather simple). The 
result is that if a request takes a long time to complete, IIS does not need to 
acquire a thread for the complete duration of the request - instead it uses a 
thread from its Threadpool only if there is new data to be forwarded. (The 
underlying SPDY connector still uses blocking I/O for the SPDY connection, but 
since one SPDY connection is intended to multiplex a huge amount of HTTP 
requests, atm there is no need for the SPDY connector to use async I/O for the 
SPDY TCP connection).


For example, the ISAPI redirector seems to use blocking I/O when forwarding 
HTTP requests to Tomcat. I tested this by creating a servlet that writes 100 
lines of text and waiting 10 seconds after writing each line. Then, I made a C# 
application creating 170 TCP connections and simultaneously sending a request 
on each connection.

Then I monitored the number of threads of the IIS worker processes (w3wp.exe) 
before and after sending the requests:
IIS with SPDY Redirector: 29 Threads -> 35 Threads
IIS with ISAPI Redirector: 26 Threads -> 195 Threads (the additional threads 
are also created very slowly - I saw 1 thread per second - which means there is 
additional waiting time for the clients)

As you can see, with the async implementation of the IIS module of the SPDY 
redirector the number of threads did not significantly increase when doing 170 
concurrent requests (initially I wanted to try more, but Jetty does not allow 
this - after about 180 requests are created on the SPDY connection, Jetty 
simply sends a GOAWAY frame and closes the TCP connection, effectively aborting 
all running HTTP requests).

Also, as AJP needs one TCP connection for each request, doing 170 concurrent 
requests means the ISAPI redirector has to establish 170 separate TCP 
connections to Tomcat, whereas the SPDY redirector only needs a single TCP 
connection where it can multiplex the concurrent requests.


The SPDY Redirector does not yet support redirecting WebSocket connections, but 
I think I will look into the "WebSocket Layering over SPDY/3" [1] document (and 
the Websocket protocol spec) to implement redirecting Websocket connections 
(Jetty 8.1 seem to support Websockets while it is only Servlet 3.0, whereas 
Jetty 9.1 should support Servlet 3.1 but I was not yet able to create a non-SSL 
SPDY/3 connector with it).


If you would like to test the SPDY redirector with a downloadable version of 
IIS 8 (that runs also on client Windows editions), you can find the 
instructions for setting it up at [2]. I would appreciate if someone could test 
the SPDY redirector for some feedback.


What do you think?


Thanks!

Regards,
Konstantin Preißer


[1] http://msdn.microsoft.com/en-us/magazine/cc163463.aspx
[2] http://markmail.org/message/atwky5b4qpm52qq3


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to