Dela via


ASP.NET Session State: Architectural and Performance Considerations

I recently came across a great post on one of the internal forums describing the strengths
and weaknesses of different ASP.NET session state strategies. Its author, J.D. Meier,
has graciously given me permission to use it as the basis of a blog entry.

As you're probably aware, state management is an important consideration for web developers.
The HTTP protocol is connectionless, so any web application that persists data across
multiple web page requests needs some mechanism to ensure this session-based data
is maintained. Examples of session-based data include shopping carts (on an ecommerce
site), the currently logged-on user credentials, and other application-specific data
that would normally be held on a client. Various strategies have been utilised over
the last few years, including hidden forms, cookies and server-based state engines.
Of these choices, the latter is perhaps architecturally most attractive since it reduces
the dependence on a client; unfortunately, maintaining session state on the server
can be expensive on resources and makes it hard to scale out using web farms or secure
pages with HTTPS.

Enter the ASP.NET session state engine, which attempts to make server-side session
state a much more viable option. ASP.NET offers three separate choices for session
state storage when it's switched on: locally on the server (InProc), remotely in a
SQL Server database (SqlServer), or remotely using a session state service (StateServer).
I'll go through each of those options and compare the benefits of each.

InProc

The local option is not dissimilar to that provided by ASP, in that it requires all
requests to come to the same physical server rather than being randomly split across
multiple IIS machines. The upside is that it's very fast (it runs in-process), and
it's simple to implement. If you've just got one web server, this is the best choice
in most scenarios. The only time when you might want to consider something else in
this scenario is when the session data is expensive to rebuild, since any InProc session
data is flushed when the ASP.NET worker process or IIS restarts. If, for example,
you're maintaining a shopping cart as local session data that gets cleared out, you
risk annoying customers sufficiently that they take their business elsewhere.

For multiple servers, InProc is unsuitable unless you can implement some form of server
affinity, so that every time a particular client requests a web page they are directed
back to that same server. Services such as Network
Load Balancing
(part of Windows Server 2003 Enterprise Edition) can provide this,
although they inevitably add their own overhead.

StateServer

I've come across a few developers who haven't come across this choice. The state server
relies on a Windows service which is disabled by default, which perhaps explains why
people haven't noticed it - go to Administrative Tools / Services and enable the ASP.NET
State Service to get it working. You can run the state service on a dedicated machine
or shared with a web server host; the main requirement to make this service work efficiently
is plenty of RAM. Because the service is isolated from IIS, you can restart IIS without
losing the session data contained within it, and you can point multiple distributed
ASP.NET boxes at the same service, thereby removing server affinity issues. However,
the session data isn't persisted onto disk, so it can't be backed up and a server
reboot will lose the data. On the plus side, you don't need SQL Server or anything
beyond a Windows licence to run it, making this option easy to set up and maintain.
This option is however signficantly slower than using InProc, due to network latency
and roundtrip costs. Keeping the state server on a dedicated private LAN with the
other web server boxes will help.

Finally, don't forget that you can run the ASP.NET State Service in a single web server
environment - this provides durability against IIS restarts, but at a performance
cost due to it running out of process.

SqlServer

This is the high-end option in terms of flexibility and reliability, but is also the
most expensive to build and maintain. Rather than storing session data in memory,
it is persisted to a SQL Server instance. It's more reliable than any of the other
approaches, since the data is persisted in a more durable form (e.g. it will survive
a server restart and can be backed up). You can even use SQL Server clustering support
to increase session state reliability still further. From a performance point of view,
it's generally comparable to the StateServer service when you've got multiple web
servers using it for session state. The session state itself is stored as a BLOB in
a persisted or temporary table, which can reduce the serialization cost but makes
it harder to view the session data itself.

In most cases, integrated Windows authentication is the best choice, preferably utilising
Kerberos (NTLM requires an extra roundtrip for authentication). Connection pooling
can be used to minimise the initial performance hit.

Further Reading

The MSDN
documentation
is quite good at describing the configuration of these options;
meanwhile, Rob Howard has a short
white paper
that is now a little old but still mostly appropriate. Finally, keep
an eye out for a new guide that will shortly be released from the Patterns & Practices
group, entitled "Improving .NET Application Performance and Scalability". This paper
will go into these topics and others in far greater detail.

Comments

  • Anonymous
    November 23, 2003
    Something that developers need to also pay close attention to is SerializableAttribute. When running InProc, any CLR type can be shoved into the session object without much consideration and be confident of retrieval in a subsequent page request. However, developers often find themselves with serialization problems when migrating a system to production where one of the two out of process modes is selected. This is because types that are to be stored in the HttpSessionState object must be marked with the SerializableAttribute when a setting other than InProc is used (since they will need to be marshalled between processes) e.g. :[Serializable] class Dog { }A good recommendation is for developers to assume that deployment will be an out of process mode of operation. Developers should use StateServer IMHO, that way, they will catch serialization problems at development time and not at deployment time.

  • Anonymous
    November 23, 2003
    Great comment Steve - very insightful.

  • Anonymous
    April 08, 2004
    Just to save you some headaches: Regarding important Steve's tip on marking classes [Serializable], there are several classes on the Framework Class Library that are NOT marked as serializable, and if you use objects of those types on your own objects, they will NOT be serializable, even if you tag them so. I had a most disapointing experience using a DataRow member on my classes, and then trying to put the session state on an State Server... ASp.NET said that "System.Xml.XmlBoundElement in Assembly System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 is not marked as serializable". It's a (internal & undocumented) part of a DataRow object, and that has stoped me from changing the session state storage of my web app.

  • Anonymous
    April 28, 2004
    Well ... GB ... I have an object graph of my own objects that are serializable and they have a member that is a DataTable (which one would think includes DataRow instances). Maybe the DataTable creates the datarows on deserialization, meaning that having a DataRow as a member of a custom class is your whole problem.

  • Anonymous
    May 03, 2004
    It seems to me that introducting a State Server into a distributed web farm creates a single point-of-failure that does not fail gracefully. What is the best way to ensure that out-of-process session state management is "fault tolerant"?

  • Anonymous
    July 24, 2004
    Steve is 100% correct. I just got bit on this because I had a reference type passed into Session that was being read by one page (to display status) and being updated on another thread via an async call. Worked like a champ InProc. Won't work at all with SQLServer or StateServer Session storage.

    I will always assume out-of-proc from now on.

  • Anonymous
    April 08, 2005
    I have also experienced the same problem when i wrote a code that did not have classes marked as Serializable. My suggestion would be that InProc should not be used during the development of application as it saves the overhead of extra effort needed for changing the classes.Although StateServer(or for that matter SQL Server) are slower than InProc, they are the best viable options available when you think of scaling up your application.

  • Anonymous
    April 29, 2006
    The comment has been removed

  • Anonymous
    September 13, 2006
    I am so [url=http://access.2surf.eu]lucky[/url] on having what I have! And good luck in yours [url=http://2access.2surf.eu]search[/url].
    Just visit [url=http://access.122mb.com]my site[/url].









  • Anonymous
    December 08, 2006
    Hay guys. During testing of system that I'v develop (Business application for call center) I observed, that some times, session state server return null (in c# language) when asking, but should return a value (not a simple tape like .net DataSet). No matter, why it do that. The frequency of that behavior increase according to ammount of request/response cycle (in each cycle appliaction puts some data into session and gets some data back) and also to user making requests. Please help if you can explain that kind of behavior.

  • Anonymous
    September 20, 2008
    העשרה שבועית בנושא והפעם מאמר מקיף על האפשרויות של sessionState בתוך web.config. (נושא שנתתי הסבר מזורז