After a long struggle with the Page Lifecycle in ASP.NET and its performance, we've begun refactoring our web app to implement web services (plain-vanilla .asmx .NET web-services) and jQuery on the client-side. NOTE: this does not implement MVC or ASP.NET in any way, these are just web services.
In both dispensations of the application, we generate all content dynamically in a single page. In the ASP.NET dispensation, this meant (due to the Page Lifecycle) that the entire page needed to be torn down and rebuilt with (almost) every AJAX call or change to the web form. This presented a huge scalability issue for an app intended to serve many concurrent users. In the web services/jQuery dispensation, we can selectively focus on only those elements of the DOM which need to send or receive data to the server, which means far fewer requests and a much faster user experience.
The first iteration of the app showed a performance improvement by an order of magnitude; however, as we have begun to build more and more web services, the performance of the app is now at parity with the performance of the ASP.NET dispensation.
After much Googling/soul searching and load testing, it became clear that HTTP Session was the culprit. Essentially, every read (and sometimes by simply including Session in the web service method scope) is a blocking call which introduces a 500ms delay. Once you know where to look, this is well documented in the MSDN literature. As implemented, Session (if used by multiple web services by the same user) transforms asynchronous requests into synchronous requests with a 500ms buffer. We mitigate this currently by chaining all of our AJAX calls as "on success" events of each other, making them synchronous requests from the client side. This eliminates the 500ms delay incurred by requesting a read on a locked Session object.
Making the client-side app behave in a "synchronous" way has solved many of the performance issues; however, it's only a stop-gap solution for the short term.
What viable (scalable!) alternatives to Session exist, again keeping in mind that we're not on ASP.NET or MVC or WCF, etc? Our biggest hurdle is the persistence of our Metadata collection which is initialized for each user on login. This is the single most expensive operation in the app (by a factor of 10 or more), and one which we only want to execute once. Session provided a simple way to sweat to the oldies once and never look back; but this approach is looking less feasible.
One approach might be to eliminate this single Metadata collection god class and evolve this monotheistic class into a polytheistic collection of demigods. Instancing the demigods could be done more frequently at a lower cost. Feasible but requires considerable refactoring, extensive development and QA time. Another candidate is simply storing all state information in the database, but this has its own costs--latency not the least of which.
Are there any other solutions to this problem which might involve a lower level of effort to implement?
It's really easy to fix your problem.
Create a table in sql server:
create table Session ( SessionId int (or a guid) ... ... )
Create separate tables that have a foreign key back to your session table (with delete cascade) and that store session specific information
On the application side, either store the SessionId in a cookie or in the query string. You can then look up all the session information you need on-demand. This will work a lot faster than the default session state providers, since you only get information when you need the information! Also, you don't have to carry the default session object on your back any longer.
Throw more hardware at it!
No, seriously. For sites like yours, you might benefit from configuring a separate machine as a session state server (see MSDN documentation), which you can do from the IIS GUI or commandline.
After you have the state server set up, you need to set up your web config to use the new machine. A nice description of the process is available here, but in short, you set the web.config's system.web.sessionState element as follows:
<?xml version="1.0"?>
<configuration>
<system.web>
<sessionState
mode="StateServer"
stateConnectionString="tcpip=your_server_ip:42424"
cookieless="false"
timeout="20" />
</system.web>
</configuration>
Now if you want to go real heavy duty, you can have many state servers and write your own routine for resolving which server contains your session state. See a description of the process here. This strategy should help you scale more or less indefinitely without abandoning your use of HttpSession.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With