Rough text for State finding

I've written up rough text for the state finding primarily for the
EPR-47 discussion.  If the direction is roughly correct, based on TAG
and other feedback, I'll do the conversion to xmlspec, fill in the
missing pieces, add refs, etc.  for more formal publication.

 

State and Applications

 

This is a draft TAG finding on State.  The purpose of the finding is to
provide guidance to application developers on the use of Stateful or
Stateless applications in a Web context.  It examines a variety of
designs for a canonical example application to illustrate the complex
trade-offs in the designs.  It uses HTML browser based and Web service
based examples to show the similarities between the design decisions.
The finding concludes with an analysis of the architectural property
trade-offs between stateful and stateless applications.

 

What is State

State is the data that pertains to an entity at a particular point in
time.  A variety of software entities have state, ranging from
applications to operating systems to network layers.  The state of an
entity changes over time triggered by some kind of event. The event
could be a network message, a timer expiring or an application message.
Entities that do not have state, that is there is no trigger that causes
a transition, are called stateless.  

 

Abstract example

Dirk decides to build an online banking application.  Customers will be
able to view their account balances and make transfers.   The first step
is logging on to the application.  When the customer selects accounts
view, the banking application will ask them for their username and
password.  If they have already entered their username and password,
they will not be asked for it again.  The system will automatically log
the customer out if they haven't done any activity for 10 minutes.  

 

We see a prototypical stateful application from the client perspective.
The application has 2 states: logged-in and not-logged-in.    This state
may be realized by storing state on the client or on the server.

 

Decisions

 

The first decision is whether data or state is persisted.  It's either
the data used to recreate the state, such as username and password, or
it is the state itself.  If the data is stored, then it must be stored
in the client and then sent to the service for each request.

 

Given a decision of storing the state rather than data used to create
the state, another decision is whether the state is stored on the client
or the server.  Applications where the client stores the state are
typically called stateless applications, even though there is state on
the client.  

 

Given a decision of storing the state on the server, how is the state
identified and transmitted by the client.  Web applications will
typically use URIs for identifying entities aka resources.  Where does
either the state identifier exist in the message to the server: in the
URI, the message body, a particular HTTP header?

 

Example using HTTP Authentication

Dirk decides that the banking application will be stateless on the
server and the client will resend the data for each request.  The
application has a URI for the entry page to the banking application and
a link to the account balances.  When any banking URI is requested, the
username/password features of HTTP are used, usually implemented as a
pop-up window asking for username and password.

 

There are very few web sites that are built this way, perhaps the
largest is the W3C web site.  Most web sites use alternative
technologies for logging on and they store the state using HTTP cookies
or using URL rewriting.   

 

The primary reasons for customized security are security concerns, that
is wanting greater control over the security timing out, and ease of use
concerns, particularly wanting direct control over the look and feel of
the screens including helpful tips and links to forgotten passwords.  

 

Example using URL Rewriting with client-side state

Dirk decides that a customized security screen is needed.  A new page
with the entry of username and password is inserted in the application,
after the "show item" page in the state flow.  Upon successful
completion, the URL is rewritten to contain the state that the user has
logged on.  At first, Dirk was going to have the URL contain the
username and password, but that was rejected for obvious security
reasons.  After the security page, any URLs in pages returned are
rewritten to contain the state and the state is encrypted to prevent
tampering and guessing.  

 

This approach has a significant downside of the URL rewriting.  In
general, it is unlikely that URLs with a particular users login state
need to be exchanged or bookmarked.  From a modeling perspective, the
resources that would likely be identified are accounts and particular
transactions, not login state.  Also, it is difficult for the
application to have full control over the URL and do the rewriting, it
is difficult for the application to parse the URL to extra the state.  

 

HTTP Cookies offer the benefit of a well-defined place, the HTTP Cookie
header, for storing and retrieving data without rewriting the URL.

 

Example using Cookies with client-side state

Nadia decides to change the banking application to store the application
state in a cookie.  The application still has URIs for the banking
application page.  The application stores the state in a cookie that is
sent to the browser upon successful completion of the page, and sent
back to the service on every request.  

 

Yet still, very few web applications are built this way.  Most secured
web sites use cookies where the state is stored on the server, rather
than encapsulated in the client.  The motivations are primarily about
performance, particularly giving the serviced application the control
over whether to keep the state in memory or passivate to disk.  The
state could get quite large or it may be difficult to serialize and so
serialization to the client could be difficult.  Another motivation is
concerns about network performance if the state gets quite large and
security of the state.  A final motivation is the visibility of the
state id

 

Example using Cookies with session ids.

Nadia further updates the banking application to store the log-in state
in a server side component.  The server-side component is identified
with an id, commonly called a session id.  This session id is stored in
the cookie.

 

Stateful resource identifers

The previous examples explored the issues and designs related to session
identification and transmission.  As described in the URL rewriting
example, the session information is probably not a stateful resource
that requires an identifier.  However, a particular user's account view,
particular bank account or particular transaction is intuitively a
stateful resource where the identifier could include the particular
account or transaction identifier.

 

In the banking application, there are 2 different account balance URI
designs: one URI for all users or URI per user.  The first design does
not have distinct URIs for each of the user account balances.  Rather,
there is a "dispatch" URI and the particular user account requested is
encoded in the request message or headers.  For example, after logging
in, the http cookie contains the user id.  When the user requests the
generic page, the particular user id is sent in the HTTP POST data.  

 

The second design has a distinct URI for each of the user ids.  The user
clicks on the login, and this redirects them to a unique URI for their
account..  

 

The URI per account design, sometimes called "deep-linking", has all the
network effect advantages that the web has to offer: the users account
is bookmarkable, exchangeable, etc.  

 

It does suffer from potential increased complexity as it may be easier
to populate and parse the FORM POST data for the account id rather than
the URI.  Another problem with clicking on a URL that takes them to say
'cleared checks for my savings account' then if the website is
redesigned (a frequent event, at least on the back end) then that URI
will break. Either that or the website has to maintain complex mapping
tables to handle versioning URIs across multiple versions of the
website.   Hence many websites would rather just force users to come in
through a well defined home page and then focus on making navigation as
easy as possible to get them quickly to where they want to be.

 

It is worth noting that the application has 2 different types of state
information that are being identified: the account balance and the
session id.  By putting the account id in the URI and keeping the
session id separate, the application has achieved a separation and the
different benefits achievable from the transient session information and
the network effect of re-usable URIs.

 

Web service example

Dirk is tasked with making the banking application available as a Web
service rather than HTML pages.  He uses XML, SOAP, WSDL, and
WS-Addressing to do this.  The banking application is a service with an
interface containing two operations:log-in and getBalance.   The first
operation is a log-in operation.  If successful, it returns a
WS-Addressing "ReplyTo" containing an EPR that client should use for
requesting the account information.  The EPR contains a reference
parameter that contains the session id and a reference parameter that
contains the account id.

 

An example, slightly modified from the WS-Addressing specification is

 

<wsa:ReplyTo>

  <wsa:EndpointReference

     xmlns:wsa="http://www.w3.org/2005/08/addressing"

     xmlns:fabrikam=http://example.com/fabrikam>

   <wsa:Address>http://example.com/fabrikam/acct</wsa:Address>       

   <wsa:ReferenceParameters>

    <fabrikam:CustomerKey>123456789</fabrikam:CustomerKey>

    <fabrikam:SessionID>ABCDEFG</fabrikam:SessionID>

   </wsa:ReferenceParameters>

  </wsa:EndpointReference>

</wsa:ReplyTo>

 

A request to the service, such as "GetBalance", might have a fragment
like:

 

<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"

         xmlns:wsa="http://www.w3.org/2005/08/addressing"

         xmlns:fabrikam="http://example.com/fabrikam">

   <S:Header>

     ...

    <wsa:To>http://example.com/fabrikam/acct</wsa:To>

    <wsa:Action>http://example.com/fabrikam/GetBalance</wsa:Action>

    <fabrikam:CustomerKey
wsa:IsReferenceParameter='true'>123456789</fabrikam:CustomerKey>

    <fabrikam:ShoppingCart
wsa:IsReferenceParameter='true'>ABCDEFG</fabrikam:ShoppingCart>

     ...

   </S:Header>

   <S:Body>

     ...

   </S:Body>

</S:Envelope>

 

Alternatively, the EPR could insert the CustomerKey in the EPR:

<wsa:ReplyTo>

  <wsa:EndpointReference

     xmlns:wsa="http://www.w3.org/2005/08/addressing"

     xmlns:fabrikam=http://example.com/fabrikam>

   <wsa:Address>http://example.com/fabrikam/acct/123456789</wsa:Address>


   <wsa:ReferenceParameters>

    <fabrikam:SessionID>ABCDEFG</fabrikam:SessionID>

   </wsa:ReferenceParameters>

  </wsa:EndpointReference>

</wsa:ReplyTo>

 

EPRs "on the Web"

For the purposes of EndpointReferences-47 discussions, there is no
binding of an WSA Message Addressing Properties, including EPRs, into an
HTTP request.  Some hypothetical instances of the above EPR into an HTTP
GET request:

 

GET /fabrikam/acct?CustomerKey=123456789&SessionID=ABCDEFG

 

GET /fabrikam/acct/CustomerKey/123456789?SessionID=ABCDEFG

 

GET /fabrikam/acct/123456789?SessionID=ABCDEFG

 

GET /fabrikam/acct/123456789

Cookie: $Version="1"; SessionID="ABCDEFG"; $Path="/fabrikam"

 

GET /fabrikam/acct/

Cookie: $Version="1"; SessionID="ABCDEFG"; 

        CustomerKey="123456789"; $Path="/fabrikam"

 

 

<<Insert WSDL samples?  This would show the application structure and
messages, but might also overly complicate what is already a moderately
lengthy write-up.  >>

 

State decision factors

The decision on where to place the state in the distributed application
and how to identify the state are affected by numerous factors.  Some of
the key considerations are scalability, reliability, network and
application performance, security, and ease of design.

 

Roy Fielding argues in his REST dissertation [1] that stateless server
has the benefits of increasing reliability, scalability, visibility and
while potentially decreasing network performance.  However, I believe
the trade-offs from an application developers perspective are somewhat
different, and need to be examined from a holistic perspective.

 

Ease of Application construction

 

There are two primary types of designers that are relevant: the network
administrator that controls the deployment of applications and
publication of URIs, and the application developer that controls the
contents of messages including http headers.  The application developer
can develop the application without affecting the URI with the state id
information and so avoid a potential conflict with the administrator.

 

Many, if not most, applications are built to exchange state information
that is not "identifying" information, such as session ids.  This is
evidenced by the widespread use of HTTP Cookies.  In the cases where
these applications are also exchanging identifying information, the
application development is simpler when the same mechanisms are used for
exchanging both types.  Examining the Web example, the application
developer can easily insert and parse information in the cookie header,
rather than rewriting the URI that is sent.  

 

In the Web services example, it is very easy to do dispatch based upon a
soap header block, which is an XML QName.   The tree-like structure of
XML and use of SOAP and SOAP Header blocks means that an application
developer can use widely available tooling, such as JAX-RPC handler
chains, that makes it easy to use the XML QNames.  On the converse,
there are no standards available for inserting or parsing a QName(s)
into or from a URI.  

 

It is worth explicitly noting that there is a trade-off between the
control over the URI versus other parts of the message body, and a
trade-off between the ease of updating/parsing URIs and the other parts
of the message body.  

 

Scalability

Scalability is directly related to the availability of important
resources for requested load.  The resources can be processes, threads,
memory, cpu cycles, database connections, network connections.
Allocation and re-use of the resources happens on a per-resources basis.
For example, most applications use database connection pooling but they
typically gain the functionality from middleware of some kind.  The
scalability trade-off is whether the cost of acquiring the necessary
resources for a request is best served with the state on the client or
on the server, and that completely depends upon how the resources are
freed up and then re-allocated.  

 

In the simplest case, it may be that not freeing up the resources an
amount of time is the most scalable.  Keeping the state in memory, with
a time-out optimized for typical client latency, can scale better than
release resources when the time-out is set correctly and the resource
acquisition/freeing is significant. Anecodatally, Jim Gray has observed
that 5 minutes has been a historically accurate cut-off time for caching
in memory rather than persisting to disk.  

 

In other configurations, it may be that it is "cheaper" to free up
resources by responding with the session id in the response and
persisting the data to the database rather than responding with the
entire state to the client because the "cost" of transmitting to the
client is more expensive than the cost of sending to the database.
Likewise, it may be "cheaper" to reify the session by acquiring it from
the database than from the client.  

 

However, the cost of freeing up state and recovering state is based on a
variety of factors, specifically the system architecture and the
connections to the client and database, the middleware software, the
database software, and hardware/software platforms used for the system.


 

Reliability

Reliability of Stateful applications has two distinct aspects:
reliability of the machines and reliability of the network.  The
reliability of the network is not typically a factor in the design of
the application style, as it is typically assumed that the network is
unreliable.  The aspect of reliability that concerns this writing is
machine reliability.  For a given client, the two time periods of
interest are during a request and in between requests.

 

In a stateless application design, a machine can fail between a request
without affecting the clients view of the system.  They send a request
and it is dispatched to an available machine.  If a machine has crashed
in between requests, there is no disruption.  

 

In a stateful application design, the systems can be designed to handle
failures between a request.  Common techniques are duplicating the state
- RAID disks, back-up nodes - and hardening the system - UPS, memory
checksums, etc.  For example, an application server can have a primary
and backup node.  If a machine fails, then the backup node is used for
subsequent requests.

 

Stateful and stateless application design must deal with the situation
of where a machine crashes during a request.  In stateless applications,
typically the request is lost.  Let us make a simplifying assumption
that the request is "atomic" and is either completed or aborted.  This
allows us to avoid the problem of determining application state where
the problems of meaning of reliability in a synchronous environment
arise.  Many systems are designed to handle machine failure during
processing by having a stateful "dispatcher" that has tracked the
request and can replay the request to a different machine if one fails
during a request.  

 

Related to Reliability is manageability, as systems are often managed
for reliability.  For example, a component may be starting to behave
erratically and the administrator wishes to replace the component.
Stateful and stateless systems would probably be designed for this task
by letting the requests "drain" off of the system that is due for
maintenance.  A stateful system has the downside that the states may be
long-running and hence take longer to "drain".   Advances in application
server technology provide for managing these by supporting
"transferring" state from one machine to another.  

 

The discussions so far have not discussed "client" reliability.  Web
based systems typically have a simplifying assumption that browsers are
for a single user, are unreliable, and responses must be received within
about 30 seconds for good HMI design.  We have made a simplifying, but
erroneous assumption that systems where the client has the state are
"stateless".  The state always exists somewhere, and in many EAI and B2B
systems, the web based simplifying assumptions are not true.   The
system, whether it is the client or the server or the network, must
contain the state.   Imagine a system where the client keeps the state
for long periods of time, it must deal with reliability of the state
information.  If a machine crashes, the system can't lose the state.  

 

Stateful systems can deliver virtually the same reliability as stateless
systems, it is more appropriate described as a matter of cost.  A
stateful system may require more costly infrastructure in the form of
components selected to achieve the same reliability.  OTOH, the
difference between the reliability for a stateless system versus a
stateful system may be small given the overall reliability desired.

 

<<TBD: Improve text to hit the point that many systems are not like the
human-centric web and "stateless" is a complete misnomer>>

 

Network Performance

<<TBD>>

 

 

 

 

 

 

Received on Saturday, 15 October 2005 18:55:49 UTC