Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

It turns out to be simpler and more efficient to ship the request when it arrives to the node that has the ticket than to struggle to ship the ticket in advance to all the nodes that may receive the request.

The modern network Front End device can be easily programmed with a small amount of knowledge of CAS protocol to route each request to the server that can best handle it. If that is not possible with your network administrators, then the CushyFrontEndFilter does the same thing less efficiently than programming the Front End but more efficiently than running Ehcache or similar ticket replication mechanisms without the Filter.

Front End Background

Any cluster of Web Servers requires some sort of Front End device to screen and forward network traffic. Ten years ago this was a computer with some fairly simple programming. Common strategies for distributing requests:

...

So teaching a Front End about CAS protocol is not that big a deal. Commercial sites do this all the time, but they don't run CAS. Universities probably spend less time optimizing eCommerce applications and so they may not normally think about Front End devices this way.

Routing the CAS Protocol

First, however, we need to understand the format of CAS ticketids because that is where the routing information comes from:

...

Cases 1-3 are only meaningful for a GET request. The only CAS POST is the login form and it is case 4.

CushyFrontEndFilter

It is not always possible to convince the network administrators who own the Front End device to add programming for CAS protocol. It turns out, however, that this sort of programming is a good idea even if you have to wait until the request hits the application servers.

CushyFrontEndFilter is a Java Servlet Filter that you can insert using Although the best place to do Front End programming is in the Front End, the CAS administrator does not control that device. You can, however, introduce a version of the same logic with the CushyFrontEndFilter. A Servlet Filter processes Web requests before the main part of the application (that is, before Spring and CAS see it).

CushyFrontEndFilter is enabled when you add it to the list of filters in the WEB-INF/web.xml in the CAS WAR file. It is typically configured by CushyClusterConfiguration to know the ticket suffix and URL of the other nodes in a CAS cluster. It builds a small file. Set the filter mapping to "/*" so it scans all requests. It has been designed to work with Ehcache or CushyTicketRegistry. It depends on configuration automatically generated if you use CushyClusterConfiguration, although I suppose it could be manually configured. Clearly it cannot do anything unless the uniqueIdGenerator.xml file has been configured with node specific ticket suffix values.

It uses Apache HttpClient to maintain a pool of reusable SSL sessions with each member of the other nodes in the cluster and uses them to forward GET requests that the . When a GET request arrives and "case 1-3" analysis indicates would better be handled by that another node that generated the ticket . It sends back to the browser whatever reply the other node generated. In short, it does what we would prefer the Front End do, but it waits until the request hits the processing stack of one of the CAS servers.

This adds some overhead and some network delay due to the request forwarding. However, it turns out that you can save more overhead and reduce more delay than the Filter consumes.

Start with an existing configuration that uses Ehcache for the TicketRegistry. The standard configuration creates a Service Ticket cache that replicates ticket operations "synchronously" (the node that creates the ticket has to wait until the RMI call to all the other nodes finishes copying the ticket to the other caches before it can return the ticketid to the browser). If you have a two node cluster, then every Service Ticket that is created has to wait for one RMI call to the other node, and then because all operations are synchronous, every ST validation that deletes the ticket also has to wait for that RMI call to get to the other node. So the overhead is two network operations and each is synchronous, delaying the return of the response to the client.

Now consider the same configuration with CushyFrontEndFilter inserted in front of the stack, and because of that you reconfigure the ticketRegistry.xml file so that Ehcache uses delayed replication for Service Tickets with the same parameters it uses for Login Tickets.

The Front End randomly chooses a CAS server, which creates the Service Ticket and sends it back to the

 

If you would like to see how this sort of programming is done, but you don't want to learn about real Front End devices, the same program logic is defined in the CushyFrontEndFilter.

In Java, an application can specify one or more Filters. A Filter is a Java class that can scan the Request as it is coming in to the application (CAS in this case) and it can scan the response generated by the application. The CushyFrontEndFilter scans incoming Requests an applies the logic for cases 1-3 to forward requests best handled by another node in the cluster.

If the programming is added to the Front End device, then it forwards request to the CAS server that issued the ticket and holds it in memory. However, without intelligent Front End programming the request arrives at a randomly chosen CAS node. At this point we have only two possible strategies:

  • The traditional idea is to configure the TicketRegistry to replicate ticket information to all the nodes or to the database server before returning the ST back to the browser. So 100% of the time you have a network transaction from one server to all the other servers and there is a delay for the network operation to complete added to the end of the Service Ticket generation. However, you should not forget that when the ticket gets validated the ST is deleted, and since you cannot configure Ehcache or any of the other technologies to do addTicket synchronously and deleteTicket asynchronously, then 100% of the time you get a second operation at the end of ST validation. 
  • With CushyFrontEndFilter the Service Ticket generation returns immediately. When the ST validation request comes in then there is a 1/n chance it will be routed to the right server by chance (that is, in a two node cluster it goes the the right place 50% of the time). Only if it goes to the wrong server is there a network operation, and then it will be from the server that received the request to the server that owns the ticket. There will only be the one exchange instead of two operations and two delays. 

So with Ehcache or any other synchronous replication strategy there is a 100% probability of two network transactions and delays, while with the Filter there is a 50% chance of no operation or delay, and a 50% chance of one operation and delay. Roughly speaking, the Filter has 25% of the overhead of the traditional mechanism.

But wait, you say, tickets still have to be replicated to other nodes for recovery if a node crashes. Yes, that is right, at least for Login TGTs and PGTs. However, Service Tickets are created, validated, and deleted so fast that if you are replicating ticket asynchronously, whether you use CushyTicketRegistry or Ehcache default replication every 10 seconds, that most of the time the ST doesn't hang around long enough to get replicated.

So while programming the Front End is the best solution, using CushyFrontEndFilter should clearly be more efficient than the current system of synchronous ST ticket replicationassociated with the request, then it forwards the request to the CAS node that can best handle it, and it forwards the response from that node back to the requester. Essentially this duplicates the Front End behavior using Java programming.

It turns out that forwarding requests is more efficient than synchronously replicating tickets. To prove this, we need to walk through request processing with and without the Filter. Consider the two node configuration (because when you do the numbers, more than two nodes is even more favorable to the Filter).

Start with an Ehcache TicketRegistry and default configuration. Consider the sequent of creating and then validating a Service Ticket.

An HTTP GET arrives from the browser with a service= value in the query string. CAS issues the ST, and then the addTicket operation is intercepted by Ehcache and, because the Ehcache Service Ticket cache is configured for synchronous replication, an RMI call is sent to the other node, and the request waits until a response is received. Then the ST ID is returned to the browser. There has been one network transaction and one delay.

The application issues an HTTP GET to validate the ticket. It is processed by CAS and a deleteTicket call is made. Although there is no rush to delete a ticket, it turns out that you cannot make a cache partially synchronous. If addTicket is synchronous, then deleteTicket has to be also. So this request also has to wait until an RMI request completes to delete the ticket on the other node. Again there is one network transaction and one delay.

If you add CushyFrontEndFilter processing in front of the CAS logic, then the validate request will always be forwarded to the node that created the Service Ticket. Replication does not have to get there before the validate request, so it does not have to be done synchronously. Reconfigure the Service Ticket cache to do lazy asynchronous replication just like Ehcache processing of Login TGTs.

When a real Front End is programmed, the "case 3" situation routes requests based on the CASTGC cookie suffix to the node that generated the login ticket. In Ehcache the TGTs are replicated and shared by all the nodes. So it is not necessary with Ehcache to do CAS Cookie routing. This can be turned off in the CushyFrontEnd filter. We will consider the overhead with or without this optimization.

When the browser submits a request to generate a Service Ticket there is a 50% chance of selecting the node that generated the Login ticket. If Cookie based routing is turned on, then half the time there is a network transaction and a delay, while if it is turned off there is no transaction and delay. We save at least a half of a transaction, or all of it without Cookie routing.

When the application submits a request to validate a Service Ticket, there is a 50% chance of selecting the node that generated the ST. When that happens, there is no network transaction. When it doesn't happen, then the filter borrows an SSL socket that already exists, sends a packet of HTTP Headers to the other node, and gets back the validation response to send back to the application. This is as good or better than the RMI request that naked Ehcache sends to synchronously delete the ticket. So on this operation we are no worse and sometimes better.

To be honest, a Round Robin scheduling algorithm will tend to maximize cost. Because the validate request comes in very quickly, there is a good chance it will be the next CAS operation. Round Robin guarantees that it will be sent to a different server than the one that handled the previous request, which is the server that created the ticket. Random selection of a server would be better.

However, the big payoff occurs when you realize that in this configuration there is really no need to replicate Service Tickets at all. Each ST is created, processed, and deleted on the host that created it. You still need a place to store them in memory, so you still need the Ehcache Service Ticket cache. You just don't need to configure that cache to be replicated to other nodes.

If you use CushyTicketRegistry then you must either have real Front End programming or the Filter. If you use the Filter, you must not disable "case 3" routing based on the CASTGC Cookie. However, this analysis of cost indicates that the Filter is still better than naked synchronous Ehcache, so the requirement to use the Filter (or real Front End programming) does not provide any advantage to Ehcache over CushyTicketRegistry. Rather, you have to compare the two TicketRegistry implementations on their own and make your own choice.