Alternatives to HTTP Session state in plain-vanilla .NET web services app
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 s开发者_高级运维ometimes 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.
- Turn off session in your web.config for the entire web site
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 most of your requests only require read-access to the session then you have a simple solution. Set the EnableSessionState
attribute to ReadOnly and they're acquire a read-only lock on the session only. I'm not sure how to apply this to web servcies, but I'm sure there is an equivalent setting.
http://msdn.microsoft.com/en-us/library/aa479041.aspx#aspnetsessionstate_topic3
Other than that, ASP.NET locks the session object for the entire duration of each request and effectively serializes the requests. One solution to allow requests to run in parallel is not use the built-in sessions and roll your own solution. The advantage here is that you can use much finer grained locking so certain aspects of the requests will have to by synchronized and will run serially, but the majority of each request can run in parallel.
An alternate solution is to simply reduce the number of parallel calls per request. Don't try to run them in parallel at all. Batch them up on he client side and send them as a single request. You'll end up with less overhead in the number of requests, less likelihood of a single client hogging a lot of resources, and very likely can get better performance overall and for each aggregated request.
Without seeing your code, or what you are loading and storing in session, it's difficult to actually help you. However, a .5 second delay for session is certainly not normal in my experience. I would very much like to see the documentation that you are referring to that says this is so.
Well written asp.net (whether webforms, asmx, mvc, or other options) is certainly VERY scalable.
That being said, where is your session being stored? In process? The IIS State server? In a DB? How much data are you really storing in session? Do you really use all that data you load into session nearly every request?
It's tough to give you real answer, without understanding your problem domain better: what you have to keep state for, how large are the objects that you are using to keep state, how much traffic you have, etc etc.
精彩评论