Continuing with the same seemingly simple web service scenario as before, last time we saw an obvious problem and solution with our proposed architecture. The problem I want to talk about this time is a little more difficult to solve.
Suppose that against all odds, Steve's map service actually becomes quite popular and several users are connecting and downloading maps at a time. On the server side, we start to notice a steady increase in allocated memory as the number of simultaneously connected clients grows larger. Some memory growth is expected since we have to pay for all of those connections, but what Steve actually sees is multiple megabytes of growth per client. The map server is quickly swamped by its own popularity and goes down. What went wrong?
One thing that is probably going wrong is that the server is buffering all of the map data in memory while sending the maps out. Since those maps are large, it takes a while to deliver a map, and there are many clients, these buffers fill up a lot of server memory. WCF supports multiple modes for transferring data. In buffered mode, messages are turned into a byte array from which data is read and sent across the transport. In streamed mode, we can dribble a little bit of the message out at a time without having to allocate a buffer the size of the message. Even in streamed mode, the SOAP headers are buffered because we need all of them before we can process the message. However, headers are usually small compared to the size of the message bodies. Streaming transfers are an obvious solution to this buffer allocation problem.
The problem is, we can't just switch from buffered to streamed mode with this architecture. Our security is provided by message security at the SOAP level. Message security requires us to use buffered mode so that we can process the protected messages. The solution is to switch from security at the message level to security at the transport level so that we can enable streaming. There are tradeoffs to this approach that I'll talk about in the future, but for now let's change the architecture to use transport security which is applied to the stream as it goes across the network.
Here's a sketch of the new architecture:
Now, we get a much smaller growth rate of allocated memory and can support many more clients with the same hardware.
Streamed transfers have the same problems with proxy servers as I mentioned before. The decision to use a streamed or buffered transfer mode is a point-to-point decision. A proxy server or other intermediary is going to choose a transfer mode according to the system policy of the administrator.
Next time: Slicing the Windows Communication Foundation Technology Stack, Part 4