Jump to: navigation, search

Difference between revisions of "Jetty/Tutorial/MongoDB Session Clustering"

(New page: =Session Clustering using MongoDB= Jetty can support session clustering by persisting sessions into MongoDB. Each Jetty instance locally caches sessions for which it has received requests...)
 
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
=Session Clustering using MongoDB=
 
=Session Clustering using MongoDB=
  
Jetty can support session clustering by persisting sessions into MongoDB. Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the database as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the Session.setAttribute() method to ensure that changes are persisted.
+
{{Jetty Redirect|http://www.eclipse.org/jetty/documentation/current/session-clustering-mongodb.html}}
 +
 
 +
Jetty can support session clustering by persisting sessions into MongoDB. Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the Session.setAttribute() method to ensure that changes are persisted.
  
 
The persistent session mechanism works in conjunction with a load balancer that supports stickiness. Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.
 
The persistent session mechanism works in conjunction with a load balancer that supports stickiness. Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.
  
In this type of solution, the database can become both a bottleneck and a single point of failure. Jetty takes steps to reduce the load on the database (discussed below), but in a heavily loaded environment you might need to investigate other optimization strategies such as local caching and database replication. You should also consult your database vendor's documentation for information on how to ensure high availability and failover of your database.
+
In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck.  You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario.  Applications with a heavy write profile to their sessions will consume more network bandwidth then profiles that are predominately read oriented.  We recommend using this session manager with largely read based session scenarios.
  
 
==Configuration==
 
==Configuration==
Line 32: Line 34:
 
</source>
 
</source>
  
Notice that the MongoSessionIdManager needs access to a mongodb cluster. Here's an example:
+
Notice that the MongoSessionIdManager needs access to a mongodb cluster. The default settings are for localhost and default port for mongo db.
 +
 
 +
The more complex setup is to configure with remote mongodb instances, this is an example of how that would look.
  
 
<source lang="xml">
 
<source lang="xml">
 +
  <New id="mongodb" class="com.mongodb.Mongo">
 +
  <Arg>
 +
    <New class="java.util.ArrayList">
 +
      <Call name="add">
 +
        <Arg>
 +
          <New class="com.mongodb.ServerAddress">
 +
            <Arg type="java.lang.String">foo.example.com</Arg>
 +
            <Arg type="int">27017</Arg>
 +
          </New>
 +
        </Arg>
 +
        </Call>
 +
        <!-- Add more Call statements here as desired -->
 +
      </New>
 +
  </Arg>
 +
 +
  <Call name="getDB">
 +
    <Arg>HttpSessions</Arg>
 +
    <Call id="sessionDocument" name="getCollection">
 +
      <Arg>sessions</Arg>
 +
    </Call>
 +
    </Call>
 +
    <!-- If you want to configure Jetty to be able to read through the slaves, call the following: -->
 +
    <Call name="slaveOk"/>
 +
</New>
 +
 
  <Set name="sessionIdManager">
 
  <Set name="sessionIdManager">
 
     <New id="mongoIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
 
     <New id="mongoIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
 
         <Arg><Ref id="Server"/></Arg>
 
         <Arg><Ref id="Server"/></Arg>
 +
        <Arg><Ref id="sessionDocument"/></Arg>
 
         <Set name="workerName">fred</Set>
 
         <Set name="workerName">fred</Set>
        INSERT HERE
+
         <Set name="scavengePeriod">60</Set>
         <Set name="scavengeInterval">60</Set>
+
 
       </New>
 
       </New>
 
  </Set>
 
  </Set>
<Call name="setAttribute">
+
   
      <Arg>mongoIdMgr</Arg>
+
      <Arg><Ref id="mongoIdMgr"/></Arg>
+
</Call>
+
 
</source>
 
</source>
  
Line 57: Line 83:
 
  MongoSessionIdManager idMgr = newMongoSessionIdManager(server);
 
  MongoSessionIdManager idMgr = newMongoSessionIdManager(server);
 
  idMgr.setWorkerName("fred");
 
  idMgr.setWorkerName("fred");
  idMgr.setScavengeInterval(60);
+
  idMgr.setScavengePeriod(60);
 
  server.setSessionIdManager(idMgr);
 
  server.setSessionIdManager(idMgr);
  
 
</source>
 
</source>
 +
 +
The MongoDB Session Id Manager has slightly different options then some of our more traditional session options.  The mongodb session id manager has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity.  New to this session id manager is the extra purge setting which governs removal from the mongodb cluster.  This can be configured through the 'purge' option.  Purge is by default set to true and by default runs daily for each node on the cluster.  Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default.  This means that invalid sessions will be removed after lingering in the mongodb instance for a day.  There is also an option for purging valid sessions that have not been used recently.  The default time for this is 1 week.  You can disable these behaviors by setting purge to false.
  
 
You must configure the MongoSessionIdManager with a <code>workerName</code> that is unique across the cluster. Typically the name relates to the physical node on which the instance is executing. If this name is not unique, your load balancer might fail to distribute your sessions correctly.
 
You must configure the MongoSessionIdManager with a <code>workerName</code> that is unique across the cluster. Typically the name relates to the physical node on which the instance is executing. If this name is not unique, your load balancer might fail to distribute your sessions correctly.
  
You can also configure how often the persistent session mechanism sweeps the database looking for old, expired sessions with the <code>scavengeInterval</code> setting. The default value is 60 seconds. We recommend that you not increase the frequency because doing so increases the load on the database with very little gain; old, expired sessions can harmlessly sit in the database.
+
You can also configure how often the persistent session mechanism sweeps the mongo cluster looking for old, expired sessions with the <code>scavengeInterval</code> setting. The default value is 60 seconds. We recommend that you not increase the frequency because doing so increases the load on the database with very little gain; old, expired sessions can harmlessly sit in the database.
 +
 
 +
* scavengeDelay–How often will a scavenge operation occur looking for sessions to invalidate?
 +
* scavengePeriod–How much time after a scavenge has completed should you wait before doing it again?
 +
* purge (Boolean)–Do you want to purge (delete) sessions that are invalid from the session store completely?
 +
* purgeDelay–How often do you want to perform this purge operation?
 +
* purgeInvalidAge–How old should an invalid session be before it is eligible to be purged?
 +
* purgeValidAge–How old should a valid session be before it is eligible to be marked invalid and purged? Should this occur at all?
 +
 
  
 
===Configuring a MongoSessionManager===
 
===Configuring a MongoSessionManager===
Line 73: Line 109:
  
 
<source lang="xml">
 
<source lang="xml">
 +
  <Ref name="Server" id="Server">
 +
  <Call id="mongoIdMgr" name="getSessionIdManager"/>
 +
  </Ref>
  
<Ref name="Server" id="Server">
+
  <Set name="sessionHandler">
  <Call id="mongoIdMgr" name="getAttribute">
+
    <Arg>mongoIdMgr</Arg>
+
  </Call>
+
</Ref>
+
+
<Set name="sessionHandler">
+
 
     <New class="org.eclipse.jetty.server.session.SessionHandler">
 
     <New class="org.eclipse.jetty.server.session.SessionHandler">
 
       <Arg>
 
       <Arg>
Line 90: Line 123:
 
       </Arg>
 
       </Arg>
 
     </New>
 
     </New>
</Set>  
+
  </Set>
 
+
 
</source>
 
</source>
  
Line 119: Line 151:
 
<source lang="java">
 
<source lang="java">
 
   
 
   
  //assuming you have already set up the JDBCSessionIdManager as shown earlier
+
  //assuming you have already set up the MongoSessionIdManager as shown earlier
 
  //and have a reference to the Server instance:
 
  //and have a reference to the Server instance:
 
   
 
   

Latest revision as of 16:05, 23 April 2013

Session Clustering using MongoDB


Jetty can support session clustering by persisting sessions into MongoDB. Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the Session.setAttribute() method to ensure that changes are persisted.

The persistent session mechanism works in conjunction with a load balancer that supports stickiness. Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing.

In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck. You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario. Applications with a heavy write profile to their sessions will consume more network bandwidth then profiles that are predominately read oriented. We recommend using this session manager with largely read based session scenarios.

Configuration

There are two components to session management in Jetty: a session ID manager and a session manager.

  • The session ID manager ensures that session IDs are unique across all webapps hosted on a Jetty instance, and thus there should only be one session ID manager per Jetty instance.
  • The session manager handles the session lifecycle (create/update/invalidate/expire) on behalf of a web application, so there is one session manager per web application instance.

These managers also cooperate and collaborate with the org.eclipse.jetty.server.session.SessionHandler to enable cross-context dispatch.

Configuring the MongoDBSessionIdManager

You need to configure an org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager instance, either in embedded code or in a jetty.xml file. Here is an example of a jetty.xml setup:

 <Set name="sessionIdManager">
     <New id="mongoIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
         <Arg><Ref id="Server"/></Arg>
         <Set name="workerName">fred</Set>
         <Set name="scavengeInterval">60</Set>
     </New>
 </Set>
 <Call name="setAttribute">
       <Arg>mongoIdMgr</Arg>
       <Arg><Ref id="mongoIdMgr"/></Arg>
 </Call>

Notice that the MongoSessionIdManager needs access to a mongodb cluster. The default settings are for localhost and default port for mongo db.

The more complex setup is to configure with remote mongodb instances, this is an example of how that would look.

  <New id="mongodb" class="com.mongodb.Mongo">
   <Arg>
     <New class="java.util.ArrayList">
       <Call name="add">
         <Arg>
           <New class="com.mongodb.ServerAddress">
             <Arg type="java.lang.String">foo.example.com</Arg>
             <Arg type="int">27017</Arg>
           </New>
         </Arg>
        </Call>
        <!-- Add more Call statements here as desired -->
      </New>
   </Arg>
 
   <Call name="getDB">
     <Arg>HttpSessions</Arg>
     <Call id="sessionDocument" name="getCollection">
       <Arg>sessions</Arg>
     </Call>
    </Call>
    <!-- If you want to configure Jetty to be able to read through the slaves, call the following: -->
    <Call name="slaveOk"/>
 </New>
 
 <Set name="sessionIdManager">
     <New id="mongoIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager">
         <Arg><Ref id="Server"/></Arg>
         <Arg><Ref id="sessionDocument"/></Arg>
         <Set name="workerName">fred</Set>
         <Set name="scavengePeriod">60</Set>
       </New>
 </Set>

As Jetty configuration files are direct mappings of XML to Java, it is straightforward to see how to do this in code, but here's an example anyway:

 Server server = new Server();
     ...
 MongoSessionIdManager idMgr = newMongoSessionIdManager(server);
 idMgr.setWorkerName("fred");
 idMgr.setScavengePeriod(60);
 server.setSessionIdManager(idMgr);

The MongoDB Session Id Manager has slightly different options then some of our more traditional session options. The mongodb session id manager has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity. New to this session id manager is the extra purge setting which governs removal from the mongodb cluster. This can be configured through the 'purge' option. Purge is by default set to true and by default runs daily for each node on the cluster. Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default. This means that invalid sessions will be removed after lingering in the mongodb instance for a day. There is also an option for purging valid sessions that have not been used recently. The default time for this is 1 week. You can disable these behaviors by setting purge to false.

You must configure the MongoSessionIdManager with a workerName that is unique across the cluster. Typically the name relates to the physical node on which the instance is executing. If this name is not unique, your load balancer might fail to distribute your sessions correctly.

You can also configure how often the persistent session mechanism sweeps the mongo cluster looking for old, expired sessions with the scavengeInterval setting. The default value is 60 seconds. We recommend that you not increase the frequency because doing so increases the load on the database with very little gain; old, expired sessions can harmlessly sit in the database.

  • scavengeDelay–How often will a scavenge operation occur looking for sessions to invalidate?
  • scavengePeriod–How much time after a scavenge has completed should you wait before doing it again?
  • purge (Boolean)–Do you want to purge (delete) sessions that are invalid from the session store completely?
  • purgeDelay–How often do you want to perform this purge operation?
  • purgeInvalidAge–How old should an invalid session be before it is eligible to be purged?
  • purgeValidAge–How old should a valid session be before it is eligible to be marked invalid and purged? Should this occur at all?


Configuring a MongoSessionManager

The way you configure a MongoSessionManager depends on whether you're configuring from a context xml file or a jetty-web.xml file or code. The basic difference is how you get a reference to the Jetty org.eclipse.jetty.server.Jetty instance.

From a context xml file, you reference the Server instance as a Ref:

  <Ref name="Server" id="Server">
   <Call id="mongoIdMgr" name="getSessionIdManager"/>
  </Ref>
 
  <Set name="sessionHandler">
    <New class="org.eclipse.jetty.server.session.SessionHandler">
      <Arg>
        <New id="mongoMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionManager">
          <Set name="idManager">
            <Ref id="mongoIdMgr"/>
          </Set>
        </New>
      </Arg>
    </New>
  </Set>

From a WEB-INF/jetty-web.xml file, you can reference the Server instance directly:

 
 <Get name="server">
    <Get id="mongoIdMgr" name="sessionIdManager"/>
 </Get>
 <Set name="sessionHandler">
    <New class="org.eclipse.jetty.server.session.SessionHandler">
      <Arg>
        <New class="org.eclipse.jetty.nosql.mongodb.MongoSessionManager">
          <Set name="idManager">
            <Ref id="mongoIdMgr"/>
          </Set>
        </New>
      </Arg>
    </New>
 </Set>

If you're embedding this in code:

 
 //assuming you have already set up the MongoSessionIdManager as shown earlier
 //and have a reference to the Server instance:
 
 WebAppContext wac = new WebAppContext();
  ... //configure your webapp context
 MongoSessionManager mongoMgr = new MongoSessionManager();
 mongoMgr.setIdManager(server.getSessionIdManager());
 wac.setSessionHandler(mongoMgr);