打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
[Bernstein09] 2.5. Shared State

2.5. Shared State

Thereare many situations in which components of a TP system need to sharestate information about users, activities, and the componentsthemselves. Some examples of state information are the following:

  • Transaction—the transaction ID of the programs executing a transaction

  • Users—a user’s authenticated identity or the address of the user’s device

  • Activities—the identity or contents of the last message that one component sent to another, or temporary information shared between a client and the system, such as the contents of a shopping cart

  • Components—the identity of transaction managers that need to participate in committing a transaction, or the identity of processes that can handle a certain kind of request

The rest of this section explores these kinds of state and mechanisms to share it.

Thekind of shared state we are interested in here is usually short-lived.That is, it is a state that can be discarded after a few seconds,minutes, or hours, though in some cases it may be much longer thanthat. Often it is information that describes a current activity oflimited duration, such as a transaction or a shopping session. It isusually shared mostly for convenience or performance, to avoid havingto send it repeatedly when components communicate. If this shared stateis lost due to a failure, it can be reconstructed in the same way itwas created in the first place—a nuisance and an expense, but not acatastrophe.

Ofcourse, a TP system also needs to manage long-lived, permanent state.Examples of such state are databases that contain information aboutaccounts, loans, and customers in a bank; or information aboutproducts, warehouses, and shipments in a retail business. In a sense,this information describes the state of the enterprise. This is theinformation that transactions are keeping track of. Unlike theshort-lived state, it must not be lost in the event of a failure. Thiskind of long-lived state information is a very important part of TPsystems, but it is not the kind of state that is the subject of this section.

Transaction Context

Earlierin this chapter, we saw that each transaction has a transaction ID, andthat each program that executes a transaction has context informationthat includes its transaction ID. Thus, the transaction ID is stateshared by the programs executing a transaction.

Thereare two design issues for any kind of shared state: how to establishthe shared state and how to stop sharing and release the state. Fortransaction IDs, the first issue is addressed by native transactionalRPC and WS-Transactions for SOAP. They propagate transaction contextfrom caller to callee, to ensure that all programs executing thetransaction have the same transaction context.

Thesecond issue is addressed in different ways, depending on whether theprogram is a resource manager that needs to participate in two-phasecommit. If so, then it retains the transaction context until after itprocesses the Commit operation in the second phase of two-phase commit.If not, and if it does not need to retain transaction state acrosscalls, then it can release its transaction state when it returns fromthe transactional RPC that called it. If it does need to retaintransaction state across calls, then it retains the transaction stateuntil some later time, determined either by two-phase commit or by theprogram itself.

For example, in .NET, a program can release its transaction context by callingSetComplete orSetAbortbefore returning from a call. As we explained earlier, these operationstell the system that the transaction may or may not be committed(respectively) insofar as the caller is concerned. To retain thetransaction context, the program callsEnableCommit orDisableCommit.These operations tell the system that the transaction may or may not becommitted (respectively) insofar as the caller is concerned, but unlikeSetComplete andSetAbort,they do not release the transaction context. These twosituations—releasing or retaining transaction context—are special casesof stateless and stateful servers, which are discussed in more detaillater in this section.

InJava EE, context is managed using a context object that is created whenthe transaction is started. The Java APIs to release context arejavax.transaction.UserTransaction.commit androllback—there’s no equivalent forSetComplete but forSetAbort the Java extensions (Javax) API providessetRollbackOnly.

Sessions

A communication sessionis a lasting connection between two system components, typically twoprocesses, that want to share state. The main reason to establish asession is to avoid having the components send the shared stateinformation in each message. This saves not only the transmission cost,but also the sender’s cost of obtaining the state information whencomposing the message and the receiver’s cost of validating and savingthe state information when receiving the message. The following aresome examples of state information that might be shared by a session:

  • The network address of both components, so they do not need to incur costly address lookups every time they send a message to each other

  • Access control information, so each party knows that the other one is authorized to be sending it messages, thereby avoiding some security checks on each message

  • A cryptographic key, so the components can encrypt information that they exchange in later messages

  • The identity of the last message each component sent and received, so they can resynchronize in case a message is not delivered correctly

  • The transaction ID of the transaction that both components are currently executing

Asession is created between two components by exchanging messages thatcontain the state to be shared. For example, a component C1 can send a messageREQUEST-SESSION(id, x) to component C2, which asks it to become a party to a new session that is identified byid and whose initial state isx. C2 replies with a messageACCEPT-SESSION(id), which tells C1 that C2 received theREQUEST-SESSION message, agrees to be a party to the session, and has retained the initial session statex. Usually, this is enough to establish the session. However, sometimes C2 needs to be sure that C1 received itsACCEPT-SESSION message before it sends C1 another message. In that case it should require that C1 acknowledge C2’sACCEPT-SESSION message by sending a messageCONFIRM-SESSION(id). In the latter case, the protocol to establish the session is called a three-way handshake (see Figure 2.14).

Figure 2.14. Three-Way Handshake to Create a Session. Component C1 initiates the protocol by requesting to establish a session. C2 agrees to be a party to the session. Finally, C1 acknowledges receipt of that agreement.


Sometimesa session is established as a side-effect of another message. Forexample, it might be a side-effect of the first RPC call from a clientto a server, and it stays around until it times out.

Eachcomponent that is involved in a session needs to allocate some memorythat holds the shared state associated with the session. This isusually a modest cost per session. However, the memory cost can besignificant if a component is communicating with a large number ofother components, such as server with sessions to a million clientsover the Internet. This is one good reason why HTTP is not asession-oriented protocol.

Mostsessions are transient. This means that if one of the components thatis involved in a session fails, then the session disappears. Continuingwith our example, suppose component C2fails and loses the contents of its main memory. Then it loses thestate information that comprises the session. The other component C1 involved in the session may still be operating normally, but it will eventually time out waiting for a message from C2, at which point it discards the session. If C2 recovers quickly, before C1 times out, then C2 might reply to C1’s attempt to re-establish contact. However, since C2lost the session due to its failure, it no longer has the shared stateof the session when it recovers. Therefore, it should reply to C1’s message with a negative acknowledgment, thereby telling C1 to discard the session. If C1 and C2 want to re-establish their session after C2 has recovered, then they have to recreate the session from scratch.

If C2had sessions with only a few other components at the time it failed,then re-establishing the sessions does not cost very much. However, ifit had a large number of sessions at the time it failed, thenre-establishing them all at recovery time can be very time-consuming.During that time, C2 is still unavailable. If one of the components with which C2 is re-establishing a session is slow to respond to theREQUEST-SESSION or, even worse, is unavailable, then C2’s availability may be seriously degraded waiting for that session to be established.

Agiven pair of components may have more than one session between them.For example, they may have a transport session for the networkconnection, a session for the application state, and a session for enduser information. Although in principle these sessions could be bundledinto a single session between the components, in practice they areusually maintained independently, because they have differentcharacteristics. For example, they may be established in differentways, use different recovery strategies, and have different lifetimes.

Tosummarize, the benefit of using sessions is to avoid resending andreprocessing the same information over and over again in every messageexchange between a pair of components. The costs are the time toestablish the session and to recover it after a failure, which in turnnegatively affects availability.

Onecommon use of sessions in TP is to connect an application component toa database system. The session state typically includes a databasename, an authenticated user ID, and the transaction ID of the currenttransaction being executed by the application component. When theapplication component creates the session viaREQUEST-SESSION, it includes the user ID and password as parameters. They are validated by the database system before it replies withACCEPT-SESSION.The database system executes all the operations it receives from theapplication component on behalf of the session’s user. Thus, operationsonly succeed if the session’s user has privileges for them. All theoperations execute within the session’s transaction. After theapplication commits the transaction, the session either automaticallystarts a new transaction (i.e., if it uses the chained transactionmodel) or it no longer is operating in the context of a transaction(i.e., if it uses the unchained transaction model).

Anothercommon use of sessions in TP is to connect transaction managers thatparticipate in the two-phase commit protocol for a given transaction.The protocol for establishing sessions between these participants is amajor part of a two-phase commit implementation and is discussed in Chapter 8.

Stateless Servers

Considera session between a client process and a server process, where theclient calls the server using RPC in the context of the session, soboth the client and server can use the session’s shared state. Thereare three problems that arise in this arrangement:

  1. The session ties the client to a particular server process. In a distributed system with multiple server processes that are running the same application, it is desirable for a given client to be able to send different requests to different server processes; for example, to use the most lightly loaded one. However, if the client is relying on the server to retain state information about their past interactions, then it does not have the freedom to send different requests to different servers. All its requests have to go to the same server, namely, the one that is keeping track of their shared state.

  2. If the server fails, then the session is lost. Since the client was depending on the server to remember the state of the session, the server needs to rebuild that state after it recovers. The server can do this either by having the client resend that state or by recovering the state from persistent storage, which in turn requires that the server saved the state in persistent storage before it failed.

  3. If the server is servicing requests from a large number of clients, then it costs a lot of memory for it to retain a shared state. Moreover, the problem of rebuilding sessions after a failure becomes more acute.

For these three reasons, it is sometimes recommended that server processes be stateless.That is, there is no session between the client and server processes,and the server retains no application state after it services andreplies to a client’s request. Thus, it processes each request messagefrom a clean state. Let us reconsider the preceding three problems forstateless server processes. First, if there are multiple serverprocesses running the same application, then successive calls from aclient can go to any of the server processes since none of them retainany state from the client’s previous calls. Second, if a statelessserver process fails, then it has no application state that it needs torecover. And third, a stateless server process does not incur thememory cost of retaining shared state.

Therecommendation that servers be stateless applies mainly tocommunication between middle-tier servers and front-end processesassociated with an end-user (i.e., clients), such as a browser or otherpresentation manager on a desktop device. This is a case where thesethree problems are likely to appear: (1) a client may want to senddifferent requests to different servers, depending on server load; (2)re-establishing client-server sessions may be problematic, becauseclients can shut down unexpectedly for long periods and because aserver would need a large number of these sessions since there istypically a large number of clients; and (3) the server would need todedicate a lot of memory to retain shared state.

Bycontrast, this recommendation usually does not apply to communicationbetween a middle-tier server and a back-end server, which are oftendatabase systems. As mentioned earlier, there usually aresessions between a middle-tier server and each back-end database systemit invokes. Therefore, the back-end server is stateful with respect tothe middle-tier servers that call it. Thus, the preceding threeproblems need to be addressed. We will discuss solutions in the nextsection.

It maysound a little strange to hear about stateless middle-tier serverprocesses, because of course a TP application needs to store a lot ofapplication state in databases. The point is that this database stateis the only state that the stateless server process depends on. Theserver process itself does not retain state. Thus, if the server failsand subsequently recovers, it doesn’t need to rebuild its internalstate, because all the state that it needs is ready and waiting in thedatabases it can access.

Awell-known example of a stateless middle-tier process is the use of aweb server for HTTP requests for static web pages. All the state neededby the web server is stored in files. After servicing a request, a webserver does not need to retain any state about the request or response.Since such web servers are stateless, if there are multiple web serverprocesses, then each request can be serviced by a different web server.And if a web server fails and is then restarted, it has no state thatneeds to be recovered.

Stateful Applications

Havingjust explored reasons why stateless applications are beneficial, let usnow examine cases where a middle-tier application needs to retain stateinformation across multiple front-end requests. Here are four examples:

  1. A user request requires the execution of several transactions, and the output of one transaction may need to be retained as input to the next.

  2. A middle-tier server wants to retain information about a user’s past interactions, which it will use for customizing the information it displays on later interactions.

  3. A front end establishes a secure connection with a server using authentication information, which requires it to cache a token.

  4. A user wants to accumulate a shopping cart full of merchandise before actually making the purchase.

Ineach of these scenarios, the state that is retained across clientrequests has to be stored somewhere. There are several places to putit, such as the following:

  • Save it in persistent storage, such as a database system. The operation that stores the state should be part of the transaction that produces the state, so that the state is retained if and only if the transaction that produces it commits.

  • Save it in shared persistent storage, but not within a transaction.

  • Store it in volatile memory or in a database that is local to one server process. This makes the server stateful. Whether or not there is a communication session, future requests from the same client need to be processed by the server that has the shared state.

  • Return it to the caller that requested the transaction execution. It is then the caller’s responsibility to save the state and pass it back to the server on its next invocation of that server.

Whereverthe state is stored, it must be labeled with the identity of the clientand/or server, so that both client and server can find the state whenthey need it.

Letus explore these ways of managing state and client-server identities inexamples (1) to (4) in the previous list. The first scenario is abusiness process, that is, a user request that requires the executionof multiple transactions. A variety of state information is accumulatedduring a business process execution. This state includes a list of thebusiness process steps whose transactions have committed and those thathave yet to be executed. It may also include results that were returnedby the transactions that committed, since these results may be neededto construct input to other transactions in the business process (see Figure 2.15).For example, if a travel reservation executes as a business process,then the arrival time of the flight that is returned by the flightreservation transaction may be needed to construct the input to a carrental reservation transaction, since that input requires a pick-uptime. This information also needs to be saved so it can be returned tothe client when the business process has finished executing.

Figure 2.15. Retaining State in a Business Process. Each transaction in a business process saves the process state for use by the next transaction in the sequence.


Likeany transaction, each transaction that executes as part of a businessprocess should execute at most once. Therefore, the business processstate must be maintained in persistent storage. If it were stored involatile memory instead of persistent storage, and the contents of thatmemory were lost due to a failure, then it could not be reconstructedby executing the business process’ transactions again (becausetransactions should execute at most once). For the same reason, thestate must be updated by each transaction that executes as part of thebusiness process. Suppose the application is written so that the resultof the transaction is stored in the business process state after thetransaction committed. If a failure occurs between the time thetransaction commits and the time its results are supposed to be writtento the business process state, then those results would be lost.

Inscenario (2) the server keeps track of a user’s interactions over along period of time. For example, it may remember all the user’s pastorders and past window-shopping. It may use this information to suggestnew products that are likely to be of interest based on that pastbehavior. In this case, the shared state needs to be identified by along-lived name. The user’s e-mail address commonly is used for thispurpose. But in some cases it might not be good enough, since the usermay access the server both from home and the office, and may switche-mail providers from time to time. The user’s full name and addressmight be better, although this too has problems due to variations inspelling and typos. Thus, depending on the requirements, selecting andusing long-lived names can be a nontrivial design problem.

Inscenario (3) a client browser establishes a secure connection with aserver by exchanging authentication information. The connectionestablishes trust between the client and server so that theauthentication information does not have to be passed on eachsubsequent call. The server caches the authentication token andidentifies it with the connection to the browser. This is handy becausethen the user does not have to log in again and can submit multiplerequests during the same session to the same resource. Since theconnection is established as secure, the user’s credentials do not haveto be presented on each request.

Scenario(4) concerns creating and maintaining a shopping cart. Each item that auser selects to buy is put into the user’s shopping cart. Since a usermay be shopping for awhile, the shopping cart may be stored in a databaseor other persistent storage, to avoid the expense of using main memoryfor information that is infrequently accessed. This need not be writtenin the context of a transaction. However, the shopping cart is not thepermanent state. The server system retains the shopping cart untileither the user checks out and purchases the items in the cart, oruntil a time-out has occurred after which the server disposes of theshopping cart. The shopping cart is the shared state between the userand the system. So is the user ID that the system needs to know inorder to find the user’s shopping cart while processing each of theuser’s operations.

Whatuser ID should be associated with the shopping cart? If the server isstateful, the session ID can be used to identify the user and hence theshopping cart. If the session goes away before the customer purchasesthe contents of the shopping cart, then the shopping cart can bedeleted. If the server is stateless, and the user has not identifiedherself to the server, then the system must generate a user ID. Sincethe server is stateless, that user ID must accompany every call by thatuser to the server. One way to do this is to ensure that all calls fromthe client to the server, and all return messages, include theserver-generated user ID. Since this is rather inconvenient, adifferent mechanism has been adopted for web browsers, called cookies.

A cookieis a small amount of information sent by a server to a web browser thatthe web browser then stores persistently and returns to the same serveron subsequent calls. For example, when an anonymous user places his orher first item in a shopping cart, the server that performs the actioncould generate a user ID for that user and return it in a cookie. Theuser’s subsequent requests to that server would contain the cookie andtherefore would tell the server which shopping cart is relevant tothose subsequent requests. Thus, the cookie is the shared state betweenthe web browser and the server.

Acookie has a name, domain, and path, which together identify thecookie. It also has a value, which is the content of the cookie, suchas a server-generated user ID for the shopping cart. For privacyreasons, the browser should send the cookie with HTTP requests only tothe cookie’s domain (e.g., books.elsevier.com). Since cookies areeasily sniffed, they are also usually encrypted. Each cookie also hasan expiration date, after which the browser should dispose of thecookie.

Cookiesare sometimes not available, for example, because a user disabled themin the browser. In this case, the server can use a different technique,called URL rewriting.Before the server sends an HTML page back to the browser, it rewritesall the URLs on the page to include the user’s session ID. For example,it could append “;jsessionid=1234” to every URL on the page. That way,any action that the user takes on that page causes the session ID to besent back to the server.

URLrewriting is less secure than an encrypted cookie, since it can be seenby others. Moreover, an unsuspecting user might copy the rewritten URLinto an e-mail to send to a friend, who might thereby have access tothe sender’s private session information.

Insummary, maintaining the state across multiple requests requires a fairbit of design effort to choose where and how the state is identifiedand maintained. For this reason, it is worthwhile to design anapplication to limit the use of shared state whenever possible.


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Nuts and Bolts of Transaction Processing
学习派派窝联盟技术架构
SQL server异常处理机制
如何处理错误消息Please install the gcc make perl packages from your distribution
SAP常用ok_code列表(ABAP Basis OK_Codes)
新浪l2数据接口如何布局?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服