Even with a single Web server, one of the biggest challenges faced by application developers is maintaining session state or coherency, which is to say, ensuring that client session information is not lost.
ASP Application state versus Session state
Application state is global and applies to all users of an application. You can use it, for example, to initialize variables and update application-wide data. Application state is typically used for Active Server Pages (ASP) output/input caching.Session state refers to each user of the application. Session state is a temporary store for user session information such as user preferences.
In a load-balanced, multi-server environment, managing and resolving session state for individual clients is more complex.
In certain scenarios a client request can get re-mapped to the wrong cluster member, which is to say the client requires state information that was created on a different member during an earlier part of the session. This typically happens when a client connection originates from a proxy server environment that consists of several servers, and different servers may be used to proxy requests from a single client. Because NLB maps requests according to the client's IP address, successive requests that are really coming from the same client appear to have a different IP address. As a result, the most recent request may get sent to a different cluster member. This situation is particularly problematic for server applications that maintain state locally on the server (in memory or in persistent storage), such as ASP Session state. There are alternative ways of keeping state, depending on your business or application needs (which determine how important session state really is). Among these alternatives are client-side cookies and databases.
NOTE
The issue of maintaining session state is not unique to NLB; all load-balancing solutions have the potential to map a new client request to the wrong server.
The Application Center request forwarder is a mechanism designed to resolve session state issues when handling HTTP client requests.
The request forwarder design is based on these principles:
The request forwarder, implemented as an ISAPI filter and extension, sits between the HTTP client and server applications (for example, ISAPI and ASP pages). It stores information that identifies the sticky server—the first server that handled the client request—in an HTTP cookie.
NOTE
The cookie, which is only generated for sessions that require coherency, consists of a single name-value pair where RQFW is {server instance GUID}. The server instance globally unique identifier (GUID) is known by every member and is used to ensure that requests are forwarded only within a cluster or to members in the out of cluster forwarding (OCF) list.
This cookie is returned to the client on its first trip, and on subsequent client requests the cookie is checked to see which server first handled the client during a given session. If NLB sends the request to a different server than the original, the request forwarder sends the request to the sticky server. The request forwarder behaves like a proxy server without caching—if a request needs to be forwarded, the server holding the request opens a connection to the sticky server and forwards the HTTP request over the back-end network. The original server responds to the HTTP request, and the request forwarder pipes the response back out to the client. The next two drawings, Figures 5.5 and 5.6, show the processing logic that the request forwarder uses when determining how to handle an incoming client request.
NOTE
The following abbreviations are used in Figures 5.5 and 5.6:
- RF—request forwarder
- CC—cluster controller
- FP—FrontPage
- DAV—Distributed Authoring and Versioning
- ASP—Active Server Page
- VDir—virtual directory
- HTMLA—HTML Admin
By default, request forwarding is enabled for any site where ASP is enabled, which is by default all sites, but you can change this option or disable session coherency if you don't want to use this feature. The configuration options for advanced load balancing are described in detail in "Network Load Balancing Administration" later in this chapter.
Let's look at the request forwarder architecture before covering the different scenarios that require this feature, and seeing how request forwarding works in an Application Center cluster.
Figure 5.5 Request forwarding process flow chart, part 1
Figure 5.6 Request forwarding process flow chart, part 2
From an architectural perspective, the request forwarder, which runs in process to IIS, consists of two parts: the request forwarder filter and the request forwarder engine.
The Request Forwarder Filter
The request forwarder filter is an ISAPI filter that monitors incoming requests and decides whether to allow requests to pass through and be executed locally or forward the request to another server, and if it must forward the request, it does the necessary preparatory work. It also gives out and interprets routing cookies, which allow for session coherency (sticky sessions) where a client is attached (stuck) to a single server for the lifetime of its browser session.
The request forwarder filter is similar in design to the ISAPI application provided with Microsoft Proxy Server. It is installed as a high-priority SF_NOTIFY_PREPROC_HEADERS filter, which means that it will execute before all other filters except for READ_RAW filters.
NOTE
It's important to ensure that the Security Support Provider Interface (SSPI) filter precedes the request forwarder filter in the filter list.
When the filter receives a request, the URL is retrieved and the directory, file name, and type are extracted. Most of the forwarding decision-making can be made from this information alone. One of the primary objectives at this stage is to ensure maximum performance for static file processing because static files take the least amount of time to process, and as a consequence, the request forwarding impact is the greatest.
NOTE
For security reasons, the request forwarder filter ensures that no URLs are permitted to address the request forwarder engine directly; therefore, URLs that access files with an .rqrw file extension are not allowed through.
The Request Forwarder Engine
The request forwarder engine is an ISAPI extension that uses a COM component to forward requests. By having the request forwarder engine reside in the same DLL as the request forwarder filter it is easier to maintain connection state and support connections for special cases such as NTLM authentication.
NOTE
For authenticated requests, the request forwarder engine passes the authentication HTTP headers through to the target. It does not attempt to do any authentication itself. Because NTLM authentication requires the same connection for the lifetime of the authenticated request, connections are kept alive for the duration of the requests.
The request forwarder engine prepares each client request and does the actual forwarding. The engine is script-mapped to handle GETs for URLs that have an .rqfw file extension. After a packet is prepared for transmission to the target server, the request forwarder pipe COM component is called to perform the actual transfer.
NOTE
The request is dispatched to a thread pool for an asynchronous connection to the target. After a connection is established, control passes to a thread pool, which in turn sends the request to the target. The thread pool streams data from the target's response back to the client.
After the data is sent and a response received, it is the engine's responsibility to handle all error cases, including those summarized in Table 5.2. These error cases will always return a 502.1 error.
Request forwarding is generic, and allows forwarding to any cluster member. However, for security reasons destination members for sticky sessions are always validated against the directory of known members before allowing forwarding, and forwarding, by default, is restricted to the members within the cluster that received the client request.
NOTE
There may be special cases (a cluster farm, for example) in which request forwarding between clusters is required, and OCF needs to be enabled.You can create an MD_RF_OCF_SERVERS list that the request forwarder will check whenever it receives a request for a sticky session where the server GUID is not a cluster member. This list is a MULTI_SZ metabase entry where items take the form of IP, {guid}. The metabase path to this entry is: /LM/Appcenter/Cluster. The IP address referenced here is the IP address of the back-end adapter on the member to which you want to forward the request.
Table 5.2 Request Forwarding Error Cases and Their Resolution
Error case | Resolution |
---|---|
Target server busy | The response is returned to the user as is, so they have the option of clicking the Refresh button. |
Target server unavailable 1 | This occurs when the request forwarder fails to connect to the target, or if a failure occurs during the forwarding process. Server state cannot be recovered in this case, so the current server has to handle the request. The existing cookie is deleted and the request is forwarded back to the current server for processing. |
1. If the request fails once the first packet has been sent, the request forwarder is unable to recover the original request information and will not be able to forward the request back to the forwarding server for local processing. In this case a 502.1 error will be returned and an error code or explanation of the failure will be present in the body of the message.
This section contains miscellaneous information related to request forwarding.
Header Information
Because the target sees the forwarding server as a regular client, data from the originating client needs to be stored and passed along. This data is stored as header information that's added to the request. These headers are summarized in Table 5.3.
Table 5.3 Custom Header Information
Header | Example | Description |
---|---|---|
MS-RFServer | WebServer1 | The name of the server from which the request is coming. |
MS-RFClient | 192.168.100.001 | The IP address of the client that made the original request. |
MS-RFUsername | Username | The user name, if any, of the client that made the original request. |
MS-RFTTL | 4 | The number of times that this request has been forwarded. By default a request can be forwarded only once. |
MS-RFHostHeader | Microsoft.com | The original host header requested by the client. See sidebar. |
Sites bound by IP address
Normally, sites are identified by a combination of ip:port:hostheader. A site that is bound by IP address will have a binding of the form ip:port:. The problem that the request forwarder faces is that if a request is forwarded to another server, the IP address that is forwarded will be the IP address on the back-end adapter, not the front-end adapter that the binding is for. The request forwarder automatically adds new headers to each IP-bound site to enable request forwarding. The new header takes the form port:ACv1VSite#, where # is the InstanceID of the virtual site. Because the host header has to be altered to enable forwarding—overwriting the original header information—the request forwarder adds the MS-RFHostHeader to store the original host header information. When the request forwarder detects the presence of the MS-RFHostHeader, it restores the originating header information on the target.
NOTE
Because IIS is unaware that forwarding has occurred, if an ISAPI or ASP application is to retrieve the client information correctly, it must check for these special headers first. If the headers are not present, the application sends a request to IIS for the relevant information.
Security alert—IP address spoofing using HTTP headers
If the IIS application uses any information in the request forwarder headers to identify a client, it opens itself up to spoofing attacks. For example, the client sends a direct request to Server A by using the GUID or dedicated IP address of a cluster member and spoofs the following values in the HTTP header fields:
- MS-RFServer:ServerB
- MS-RFClient:192.168.001.001
- MS-RFUserName:Administrator
- RMS-RFTTL:1
This makes Server A think that the request was forwarded by Server B and that the client's source IP address is 192.168.001.001. As a result, ASP and ISAPI filters will perceive the request as coming from Server B, with the client source IP address specified, and authenticated as an administrator.
For Internet clients IIS applications should treat the request forwarder headers as unreliable information and, where available, use reliable sources (like IIS) for this information—use the request forwarder headers only as a last resort.
The request forwarder filter has to modify the appropriate headers to ensure that the request gets forwarded to the correct cluster member. The forwarding server also has to parse returning responses to ensure that notifications, the "Connection:close" notification in particular, are caught.
Because HTTP server (HTTPS) requests are encrypted, the receiving server has to perform a full Secure Sockets Layer (SSL) handshake before it can examine the routing cookie. After the routing information is decrypted, the forwarding server encrypts the request and sends it to the correct server. We recommend that you configure NLB with either Single or Class C affinity because this ensures the session stability that's needed for encryption.
NOTE
Because the request forwarder uses host-headers to determine the destination server, and that information is encrypted in the packet, the request forwarder supports SSL on a per-port basis only.Application Center only supports one SSL site per cluster if the site uses port 443 because encryption requests cannot be forwarded to multiple sites. You can overcome this by binding SSL to non-standard ports for the other site, that is to say, not port 443. However, most public sites will want to use 443 for obvious reasons.
There are several instances where the request forwarder filter has to be positioned correctly in the filter priority chain to ensure that request forwarding is handled correctly. These instances are:
Application Center contains a collection of performance counters and error messages that are specific to the request forwarder.
Table 5.4 lists the counters that are available and can be accessed through the Windows Performance Monitor.
Table 5.4 Available Request Forwarder Performance Counters
Counter | The total number of | Unit |
---|---|---|
Total Application Center Administration Requests | Requests received by the Application Center Administration site. | Integer |
Total Application Center Administration Requests/sec | Requests received by the Application Center Administration site, expressed on a per-second basis for a given period of time. | Integer/time |
Total Coherent Session Requests | Requests for pages requiring session coherency. | Integer |
Total Coherent Session Requests/sec | Requests for pages requiring session coherency, expressed on a per-second basis for a given period of time. | Integer/time |
Total Dynamic Requests | Requests for dynamic content. | Integer |
Total Dynamic Requests/sec | Requests for dynamic content expressed on a per-second basis for a given period of time. | Integer/time |
Total Failed Requests | Failed requests. | Integer |
Total Failed Requests/sec | Failed requests expressed on a per-second basis over a given period of time. | Integer/time |
Total Forwarded Requests | Requests forwarded. | Integer |
Total Forwarded Requests/sec | Requests forwarded, expressed on a per- second basis over a given period of time. | Integer/time |
Total Publishing Requests | Requests submitted by a publishing tool such as Microsoft FrontPage 2000 (FrontPage). | Integer |
Total Publishing Requests/sec | Requests submitted by a publishing tool, such as FrontPage, expressed on a per- second basis over a given period of time. | Integer/time |
Total Requests | Requests received by the request forwarder. | Integer |
Total Requests/sec | Requests received by the request forwarder, expressed on a per-second basis over a given period of time. | Integer/time |
Total Web Administration Requests | Requests received by the Web Administration site. | Integer |
Total Web Administration Requests/sec | Requests received by the Web Administration site, expressed on a per-second basis over a given period of time. | Integer/time |
Error Messages
The request forwarder generates a single custom error on a per-virtual site basis (a 502.1 error) for the events listed in Table 5.5, which also lists the corresponding error message for each event.
Table 5.5 Request Forwarder Error Events and Messages
Event | Message |
---|---|
Server offline | Unable to forward request to an offline member. |
Memory error | Unable to process request; out of memory. |
Incorrect extension | Extension .rqfw reserved for use by Application Center. 1 |
No controller error | Unable to forward request to controller. |
Instance error | Unable to retrieve the InstanceID of the request. |
Metabase error | Unable to retrieve the property from the metabase. |
Port error | Unable to retrieve, or invalid, port. |
IP error | Unable to retrieve the IP number. |
Initialize error | Initialization error prior to forwarding. |
Get hop count error | Unable to retrieve hop count from IIS. |
Set hop count error | Unable to set hop count header. |
Hop count error | Too many hops, not forwarding. |
HRESULT error | Windows HRESULT error. |
1. The request forwarder returns error 404 when it receives a request to an incorrect extension (.rqfw).
Each error is accompanied with the following information:
"While acting as a transparent gateway, the server attempted to contact an upstream content server and received a response that was not valid."
The error file is installed in the IIS custom errors directory, and the filter transmits the file by using the IIS support function transmit file. The actual response code sent to IIS reads "502.1 Transparent Gateway Error". There is a special metabase entry in the root node of each virtual site that specifies the location of this file. Setting this entry, ID 57615, is supported at the per-virtual site level only. In the event that this file cannot be found in the custom file list for the Web site, or if the file is missing, there is an abbreviated version of the file's messages stored as a resource string.
In an Application Center cluster, the following scenarios require request forwarding:
NOTE
A list of static file types (shown in the Advanced Load Balancing Options dialog box) is maintained as a global table stored at the AppCenter/Cluster level. If an incoming file extension is not found in this table, it's considered to be dynamic and will be treated as a sticky file. You can reduce or expand this list according to the file types handled at your site. Remember that while there is a performance cost as the list increases in size, there is an even greater performance cost associated with forwarding files unnecessarily.
NOTE
Typically, there is a delay in getting new content pushed out from the controller to all the cluster members. This lag may result in a user seeing old content when they browse a site simply because the new pages haven't been synchronized to the server that received the client request.