Session doc updates.

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2020-09-17 09:39:40 +02:00
parent 4d992a4315
commit 8b53c386b1
5 changed files with 174 additions and 49 deletions

View File

@ -0,0 +1,39 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
[[pg-server-session-cachingsessiondatastore]]
==== Session Components: The CachingSessionDataStore
[plantuml]
----
interface SessionDataMap
class CachingSessionDataStore
interface SessionDataStore
CachingSessionDataStore "1" *-down- "1" SessionDataMap
CachingSessionDataStore "`" *-down- "1" SessionDataStore
----
The `CachingSessionDataStore` is a special type of `SessionDataStore` that acts as an L2 cache for `SessionData`.
It has 2 components: the cache, and the actual backing `SessionDataStore`.
The cache is an instance of a link:{JDURL}/org/eclipse/jetty/server/session/SessionDataMap.html[SessionDataMap].
The `CachingSessionDataStore` consults this cache before consulting the actual `SessionDataStore`.
Using a cache for the `SessionData` can improve the performance of slow stores.
Jetty provides one implementation of this L2 cache based on `Memcached`, link:{JDURL}/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.html[MemcachedSessionDataMap].

View File

@ -23,15 +23,20 @@ There is one `SessionCache` per `SessionHandler`, and thus one per context.
Its purpose is to provide an L1 cache of `Session` objects.
Having a working set of `Session` objects in memory allows multiple simultaneous requests for the same session to share the same `Session` object.
A `SessionCache` uses a `SessionDataStore` to create, read, store and delete the `SessionData` associated with the `Session`.
``SessionCache``s can be created by `SessionHandlers` as needed via a `SessionCacheFactory` registered as a bean on the `Server`.
Alternatively, you can construct and configure an instance of a `SessionCache` and explicitly set it on a `SessionHander`.
Be aware that in this case, you must _also_ ensure your instance is set up with a `SessionDataStore`.
If instead the `SessionHandler` uses the `SessionCacheFactory` to create a `SessionCache` instance, it will be responsible for choosing a `SessionDataStore`: if a `SessionDataStoreFactory` bean is found on the `Server` instance, it will use that; otherwise it uses the `NullSessionDataStore`.
More on ``SessionDataStore``s later, in this section we will concentrate the `SessionCache`.
There are two ways to create a `SessionCache` for a `SessionHandler`:
. allow the `SessionHandler` to create one lazily at startup
The `SessionHandler` looks for a `SessionCacheFactory` bean on the server to produce the `SessionCache` instance.
It then looks for a `SessionDataStoreFactory` bean on the server to produce a `SessionDataStore` instance to use with the `SessionCache`.
. pass a fully configured `SessionCache` instance to the `SessionHandler`
You are responsible for configuring both the `SessionCache` instance and its `SessionDataStore`
More on ``SessionDataStore``s xref:pg-server-session-sessiondatastore[later], in this section we will concentrate on the `SessionCache` and `SessionCacheFactory`.
The link:{JDURL}/org/eclipse/jetty/server/session/AbstractSessionCache.html[AbstractSessionCache] provides most of the behaviour of ``SessionCache``s.
If you are implementing a custom `SessionCache` we recommend you extend this base class, as the Servlet Specification has many subtleties and extending the base class ensures that your implementation will take account of them.
If you are implementing a custom `SessionCache` we strongly recommend you extend this base class, as the Servlet Specification has many subtleties and extending the base class ensures that your implementation will take account of them.
Some of the important behaviours of ``SessionCache``s are:
@ -51,7 +56,7 @@ The eviction strategies are:
saveOnInactiveEviction::
This controls whether a session will be persisted to the `SessionDataStore` if it is being evicted due to the EVICT_ON_INACTIVITY policy.
Usually sessions are written to the `SessionDataStore` whenever the last simultaneous request exits the session.
However, as `SessionDataStores` can be configured to xref:pg-server-session-sessiondatastore[skip some writes], this option ensures that the session will be written out.
However, as `SessionDataStores` can be configured to xref:pg-server-session-sessiondatastore-skip[skip some writes], this option ensures that the session will be written out.
saveOnCreate::
Usually a session will be written through to the configured `SessionDataStore` when the last request for it finishes.
@ -99,14 +104,16 @@ The link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCache.html#getSe
reset::
The link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCache.html#resetStats()[DefaultSessionCache.resetStats()] zeros out the statistics counters.
As a convenience, you can use the link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.html[DefaultSessionFactory] to create a `DefaultSessionCache` whenever a new `SessionHandler` is started.
If you create a link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.html[DefaultSessionFactory] and register it as `Server` bean, a `SessionHandler` will be able to lazily create a `DefaultSessionCache`.
The `DefaultSessionCacheFactory` has all of the same configuration setters as a `DefaultSessionCache`.
Alternatively, if you only have a single `SessionHandler`, or you need to configure a `DefaultSessionCache` differently for every `SessionHandler`, then you could dispense with the `DefaultSessionCacheFactory` and simply instantiate, configure and pass in the `DefaultSessionCache` yourself.
[source,java,indent=0]
----
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java[tags=defaultsessioncache]
----
NOTE:: If you don't configure any `SessionCache` or `SessionCacheFactory`, the `SessionHandler` will automatically use a `DefaultSessionCache`.
NOTE:: If you don't configure any `SessionCache` or `SessionCacheFactory`, the `SessionHandler` will automatically create a `DefaultSessionCache`.
[[pg-server-session-null]]
===== The NullSessionCache
@ -115,6 +122,11 @@ It is suitable for clustered deployments without a sticky load balancer and non-
As no sessions are actually cached, of course functions like `invalidateOnShutdown` and all of the eviction strategies have no meaning for the `NullSessionCache`.
There is a `NullSessionCacheFactory` which you can instantiate, configure and set as a `Server` bean to enable the `SessionHandler` to automatically create new ``NullCache``s as needed.
All of the same configuration options are available on the `NullSessionCacheFactory` as the `NullSessionCache` itself.
Alternatively, if you only have a single `SessionHandler`, or you need to configure a `NullSessionCache` differently for every `SessionHandler`, then you could dispense with the `NullSessionCacheFactory` and simply instantiate, configure and pass in the `NullSessionCache` yourself.
[source,java,indent=0]
----
include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java[tags=nullsessioncache]
@ -123,15 +135,15 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/session/Sess
[[pg-server-session-customcache]]
===== Implementing a Custom SessionCache
As previously mentioned, the best thing to do is to extend the `AbstractSessionCache`.
As previously mentioned, we highly recommend that you extend the link:{JDURL}/org/eclipse/jetty/server/session/AbstractSessionCache.html[AbstractSessionCache].
===== Heterogenous Caching
Using the `DefaultSessionCacheFactory` or the `NullSessionCacheFactory` will ensure that every time a `SessionHandler` starts, by default it will create a new instance of the corresponding type of `SessionCache`.
Using one of the s`SessionCacheFactory``s will ensure that every time a `SessionHandler` starts it will create a new instance of the corresponding type of `SessionCache`.
But, what if you deploy multiple webapps, and for one of them, you don't want to use sessions?
Or alternatively, you don't want to use sessions, but you have one webapp that now needs them?
In that case, you can configure the factory appropriate to the majority, and then specifically create the right type of cache for the others.
In that case, you can configure the `SessionCacheFactory` appropriate to the majority, and then specifically create the right type of `SessionCache` for the others.
Here's an example where we configure the `DefaultSessionCacheFactory` to handle most webapps, but then specifically use a `NullSessionCache` for another:
[source,java,indent=0]

View File

@ -19,8 +19,8 @@
[[pg-server-session-sessiondatastore]]
==== Session Components: The SessionDataStore
There is one link:{JDURL}/org/eclipse/jetty/server/session/SessionDataStore.html[SessionDataStore] per `SessionCache`.
Its purpose is to create, store, read and delete the `SessionData` related to a `Session`.
A link:{JDURL}/org/eclipse/jetty/server/session/SessionDataStore.html[SessionDataStore] mediates the storage, retrieval and deletion of `SessionData`.
There is one `SessionDataStore` per `SessionCache`.
The server libraries provide a number of alternative `SessionDataStore` implementations.
[plantuml]
@ -48,50 +48,32 @@ AbstractSessionDataStore <|-- MongoSessionDataStore
SessionDataStore <|-- CachingSessionDataStore
----
The `AbstractSessionDataStore` provides most of the behaviour common to ``SessionDataStore``s.
The common characteristics for all ``SessionDataStore``s that derive from `AbstractSessionDataStore` are:
The link:{JDURL}/org/eclipse/jetty/server/session/AbstractSessionDataStore.html[AbstractSessionDataStore] provides most of the behaviour common to ``SessionDataStore``s:
passivation::
Supporting passivation means that session data is serialized.
Some persistence mechanisms serialize, such as JDBC, GCloud Datastore etc.
Others store an object in shared memory, e.g. Infinispan.
Whether or not a clustering technology entails passivation controls whether or not ``HttpSessionActivationListener``s will be called.
Others store an object in shared memory, e.g. Infinispan and thus don't serialize session data.
Whether or not a persistence technology entails passivation controls whether or not ``HttpSessionActivationListener``s will be called.
When implementing a custom `SessionDataStore` you need to decide whether or not passivation will be supported.
[[pg-server-session-sessiondata-skip]]
savePeriod::
This is an interval defined in seconds.
It is used to reduce the frequency with which `SessionData` is written.
Normally, whenever the last concurrent request leaves a `Session`, the `SessionData` for that `Session` is always persisted, even if the only thing that changed is the `lastAccessTime`.
If the `savePeriod` is non-zero, the `SessionData` will not be persisted if no session attributes changed, unless the time since the last save exceeds the `savePeriod`.
If the `savePeriod` is non-zero, the `SessionData` will not be persisted if no session attributes changed, _unless_ the time since the last save exceeds the `savePeriod`.
Setting a non-zero value can reduce the load on the persistence mechanism, but in a clustered environment runs the risk that other nodes will see the session as expired because it has not been persisted sufficiently recently.
gracePeriod::
The `gracePeriod` is an interval defined in seconds.
It is an attempt to deal with the non-transactional nature of sessions with regard to finding sessions that have expired.
Because the servlet api does not define session transactions, in a clustered configuration - even with a sticky load balancer - it is always possible that a session is live on a node but not yet updated in the persistent store.
In a clustered configuration - even with a sticky load balancer - it is always possible that a session is "live" on a node but not yet updated in the persistent store.
This means that it can be hard to determine at any given moment whether a clustered session has truly expired.
Thus, we use the `gracePeriod` to provide a bit of leeway around the moment of expiry.
The `AbstraceSessionDataStore` uses the `gracePeriod` in the following manner to help xref:pg-server-session-housekeeper[scavenge] expired sessions:
Thus, we use the `gracePeriod` to provide a bit of leeway around the moment of expiry during xref:pg-server-session-housekeeper[scavenge]:
* on every scavenge cycle it searches for sessions that belong to our context that expired at least one `gracePeriod` ago
* infrequently we also do a scan to find and summarily delete sessions - from any context - that expired at least 10 `gracePeriod``s ago
* on every xref:pg-server-session-housekeeper[scavenge] cycle an `AbstractSessionDataStore` searches for sessions that belong to the context that expired at least one `gracePeriod` ago
* infrequently the `AbstractSessionDataStore` searches for and summarily deletes sessions - from any context - that expired at least 10 ``gracePeriod``s ago
The trivial link:{JDURL}/org/eclipse/jetty/server/session/NullSessionDataStore.html[NullSessionDataStore] - which does not persist sessions - is the default used by the `SessionHandler`.
===== CachingSessionDataStore
[plantuml]
----
interface SessionDataMap
class CachingSessionDataStore
interface SessionDataStore
CachingSessionDataStore "1" *-down- "1" SessionDataMap
CachingSessionDataStore "`" *-down- "1" SessionDataStore
----
The `CachingSessionDataStore` is a special type of `SessionDataStore` that acts as an L2 cache for `SessionData`.
It has 2 components: the cache, and the actual backing `SessionDataStore`.
The cache is an instance of a link:{JDURL}/org/eclipse/jetty/server/session/SessionDataMap.html[SessionDataMap].
The `CachingSessionDataStore` consults this cache before consulting the actual `SessionDataStore`.
Using a cache for the `SessionData` can improve the performance of slow stores.
Jetty provides one implementation of this L2 cache based on `Memcached`, link:{JDURL}/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.html[MemcachedSessionDataMap].
NOTE:: The trivial link:{JDURL}/org/eclipse/jetty/server/session/NullSessionDataStore.html[NullSessionDataStore] - which does not persist sessions - is the default used by the `SessionHandler`.

View File

@ -20,49 +20,140 @@
==== Session Components: The SessionHandler
Each context can have a single `SessionHandler`.
The purpose of the `SessionHandler` is to interact with the `Request` and `Response` to create, maintain and propagate sessions
The purpose of the `SessionHandler` is to interact with the `Request` and `Response` to create, maintain and propagate sessions.
It also calls the context-level session listeners at appropriate points in the session lifecycle.
===== Configuration =====
The majority of configuration for the `SessionHandler` can be done via `web.xml` `<session-config>` declarations, or the `javax.servlet.SessionCookieConfig` api.
There are also a few jetty-specific configuration options that we will cover here:
checkingRemoteSessionIdEncoding::
Boolean, default `false`.
This controls whether or not the `javax.servlet.http.Response.encodeURL(String)` method will include the session id as a path parameter when the URL is destined for a remote node.
This can also be configured by:
* setting the `org.eclipse.jetty.servlet.CheckingRemoteSessionIdEncoding` context init paramter
setMaxInactiveInterval::
Integer, seconds.
This is equivalent to the `<session-config><session-timeout/></session-config>` that can be set in `web.xml`, although take note that that in `web.xml` this is specified in _minutes_ but this method uses _seconds_.
This is the amount of time after which an unused session may be scavenged.
This can also be configured by:
* defining the `<session-config><session-timeout/></session-config>` element in `web.xml`, although take note that this element is specified in _minutes_ but this method uses _seconds_.
* calling the `javax.servlet.ServletContext.setSessionTimeout(int)` method, where the timeout is configured in _minutes_.
setHttpOnly::
Boolean, default `false`.
This is equivalent to using `javax.servlet.SessionCookieConfig.setHttpOnly(boolean)` method, or the `<session-config><cookie-config><http-only/></cookie-config></session-config>` element.
If `true`, the session cookie will not be exposed to client-side scripting code.
This can also be configured by:
* using `javax.servlet.SessionCookieConfig.setHttpOnly(boolean)` method
* defining the `<session-config><cookie-config><http-only/></cookie-config></session-config>` element in `web.xml`
[[pg-server-session-refreshcookie]]
refreshCookieAge::
Integer, seconds, default is `-1`.
This controls resetting the session cookie when `SessionCookieConfig.setMaxAge(int)` is non-zero.
See also xref:pg-server-session-maxAge[setting the max session cookie age with an init parameter].
If the amount of time since the session cookie was last set exceeds this time, the session cookie is regenerated to keep the session cookie valid.
sameSite::
`HttpCookie.SameSite`, default `null`.
The values are `HttpCookie.SameSite.NONE`, `HttpCookie.SameSite.STRICT`, `HttpCookie.SameSite.LAX`.
secureRequestOnly::
Boolean, default true.
Boolean, default `true`.
If `true` and the request is HTTPS, the set session cookie will be marked as `secure`, meaning the client will only send the session cookie to the server on subsequent requests over HTTPS.
This can also be configured by:
* using the `javax.servlet.SessionCookieConfig.setSecure(true)` method, in which case the set session cookie will _always_ be marked as `secure`, even if the request triggering the creation of the cookie was not over HTTPS.
sessionCookie::
String, default is `JSESSIONID`.
This is the name of the session cookie.
It can alternatively be configured by:
* using `javax.servlet.SessionCookieConfig.setName(String)` method
* setting the `org.eclipse.jetty.servlet.SessionCookie` context init parameter.
sessionIdPathParameterName::
String, default is `jsessionid`.
This is the name of the path parameter used to transmit the session id on request URLs, and on encoded URLS in responses.
It can alternatively be configured by:
* setting the `org.eclipse.jetty.servlet.SessionIdPathParameterName` context init parameter
sessionTrackingModes::
`Set<javax.servlet.SessionTrackingMode>`.
Default is `SessionTrackingMode.COOKIE`, `SessionTrackingMode.URL`.
This can also be configured by:
* using the `setSessionTrackingModes(Set<javax.servlet.SessionTrackingMode>)` method
* using the `javax.servlet.ServletContext.setSessionTrackingModes<Set<javax.servlet.SessionTrackingMode>)` method
* defining up to three ``<tracking-mode>``s for the `<session-config>` element in `web.xml`
usingCookies::
Boolean, default `true`.
Determines whether or not the `SessionHandler` will look for session cookies on requests, and will set session cookies on responses.
If `false` session ids must be transmitted as path params on URLs.
This can also be configured by:
* using the `setSessionTrackingModes(Set<javax.servlet.SessionTrackingMode>)` method
* using the `javax.servlet.ServletContext.setSessionTrackingModes<Set<javax.servlet.SessionTrackingMode>)` method
There are also a few session settings that do not have SessionHandler setters, but can be configured with context init parameters:
[[pg-server-session-maxAge]]
org.eclipse.jetty.servlet.MaxAge::
This is the maximum number of seconds that the session cookie will be considered to be valid.
By default, the cookie has no maximum validity time.
See also xref:pg-server-session-refreshcookie[refreshing the session cookie].
The value can also be configured by:
* calling the `SessionCookieConfig.setMaxAge(int)` method.
org.eclipse.jetty.servlet.SessionDomain::
String, default `null`.
This is the domain of the session cookie.
This can also be configured by:
* using the `javax.servlet.SessionCookieConfig.setDomain(String)` method
* defining the `<session-config><cookie-config><domain/></cookie-config></session-config>` element in `web.xml`
org.eclipse.jetty.servlet.SessionPath::
String, default `null`.
This is used when creating a new session cookie.
If nothing is configured, the context path is used instead, defaulting to `/`.
This can also be configured by:
* using the `javax.servlet.SessionCookieConfig.setPath(String)` method
* defining the `<session-config><cookie-config><path/></cookie-config></session-config>` element in `web.xml`
===== Statistics =====
Some statistics about the sessions for a context can be obtained from the `SessionHandler`, either by calling the methods directly or via `jmx`:
sessionsCreated::
This is the total number of sessions that have been created for this context since Jetty started.
sessionTimeMax::
The longest period of time a session was valid in this context before being invalidated.
sessionTimeMean::
The average period of time a session in this context was valid.
sessionTimeStdDev::
The standard deviation of the session validity times for this context.
sessionTimeTotal::
The total time that all sessions in this context have remained valid.
You can reset the statistics counters by either calling the following method directly on the the `SessionHandler`, or using `jmx`:
statsReset::
Resets the `SessionHandler` statistics counters.

View File

@ -25,3 +25,4 @@ include::session-architecture.adoc[]
include::session-sessionidmgr.adoc[]
include::session-sessioncache.adoc[]
include::session-sessiondatastore.adoc[]
include::session-cachingsessiondatastore.adoc[]