diff --git a/jetty-documentation/src/main/asciidoc/operations-guide/old_docs/sessions/session-base.adoc b/jetty-documentation/src/main/asciidoc/operations-guide/old_docs/sessions/session-base.adoc index d41eac0b801..183269cc1ce 100644 --- a/jetty-documentation/src/main/asciidoc/operations-guide/old_docs/sessions/session-base.adoc +++ b/jetty-documentation/src/main/asciidoc/operations-guide/old_docs/sessions/session-base.adoc @@ -43,7 +43,7 @@ IMPORTANT: If you have more than one Jetty instance, it is *crucial* that you co jetty.sessionScavengeInterval.seconds:: This is the period in _seconds_ between runs of the `HouseKeeper`, responsible for orchestrating the removal of expired sessions. -By default it will run every 600 secs (ie 10 mins). +By default it will run appproximately every 600 secs (ie 10 mins). As a rule of thumb, you should ensure that the xref:ops-session-base-scavenge[scavenge] interval is shorter than the `` of your sessions to ensure that they are promptly scavenged. On the other hand, if you have a backend store configured for your sessions, xref:ops-session-base-scavenge[scavenging] too frequently can increase the load on it. @@ -53,7 +53,13 @@ TIP: Don't forget that the `` is specified in web.xml in _minut ==== Session Scavenging The `HouseKeeper` is responsible for the periodic initiation of session scavenge cycles. -The `jetty.sessionScavengeInterval.seconds` property in `start.d/sessions.ini` controls the periodicity of the cycle. +The `jetty.sessionScavengeInterval.seconds` property in `$jetty.base/start.d/sessions.ini` controls the periodicity of the cycle. + +[NOTE] +==== +The HouseKeeper semi-randomly adds an additional 10% to the configured `sessionScavengeInterval`. +This is to prevent multiple nodes in a cluster that are all started at once from syncing up scavenge cycles and placing extra load on the configured persistence mechanism. +==== A session whose expiry time has been exceeded is considered eligible for scavenging. The session might be present in a `SessionCache` and/or present in the session persistence/clustering mechanism. diff --git a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-architecture.adoc b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-architecture.adoc index 5f7e761e019..d2bf8849dd2 100644 --- a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-architecture.adoc +++ b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-architecture.adoc @@ -31,8 +31,7 @@ SessionData:: encapsulates the attributes and metadata associated with a `Sessio SessionDataStore:: is responsible for creating, storing and reading `SessionData` CachingSessionDataStore:: is an L2 cache of `SessionData` - -Visually the session architecture can be represented like this: +The session architecture can be represented like so: [plantuml] ---- diff --git a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessioncache.adoc b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessioncache.adoc new file mode 100644 index 00000000000..3b7e70d911d --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessioncache.adoc @@ -0,0 +1,47 @@ +// +// ======================================================================== +// 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-sessioncache]] +==== Session Components: The SessionCache + +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`. + +Jetty provides two `SessionCache` implementations: the link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCache.html[DefaultSessionCache] and the link:{JDURL}/org/eclipse/jetty/server/session/NullSessionCache.html[NullSessionCache]. + +[[pg-server-session-hash]] +===== The DefaultSessionCache +The `DefaultSessionCache` retains `Session` objects in memory in a cache and has a number of configuration options to control cache behavior. +It is suitable for non-clustered and clustered deployments with a sticky load balancer, as well as clustered deployments with a non-sticky load balancer, with some caveats. + +[[pg-server-session-null]] +===== The NullSessionCache +The `NullSessionCache` does not actually cache any objects: each request uses a fresh `Session` object. +It is suitable for clustered deployments without a sticky load balancer and non-clustered deployments when purely minimal support for sessions is needed. + +``SessionCache``s always write out a Session to the link:{JDURL}/org/eclipse/jetty/server/session/SessionDataStore.html[SessionDataStore] whenever the last request for the `Session` exits. + +They can also be configured to do an immediate, eager write of a freshly created session. +This can be useful if you are likely to experience multiple, near simultaneous requests referencing the same session, e.g. with HTTP/2 and you don't have a sticky load balancer. +Alternatively, if the eager write is not done, application paths which create and then invalidate a session within a single request never incur the cost of writing to persistent storage. + +Additionally, if the `EVICT_ON_INACTIVITY` eviction policy is in use, you can xref:#pg-server-session-sessioncache[configure] the `DefaultSessionCache` to force a write of the `Session` to the `SessionDataStore` just before the `Session` is evicted. + +See xref:pg-server-session-sessioncache[the L1 Session Cache] for more information. diff --git a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-components.adoc b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessiondatastore.adoc similarity index 52% rename from jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-components.adoc rename to jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessiondatastore.adoc index 99c2f79f97b..08bcfc3c236 100644 --- a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-components.adoc +++ b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessiondatastore.adoc @@ -16,79 +16,8 @@ // ======================================================================== // -[[pg-server-session-components]] -==== Session Components - -===== SessionIdManager - -There is a maximum of one `SessionIdManager` per `Server` instance. -Its purpose is to generate fresh, unique session ids and to coordinate the re-use of session ids amongst co-operating contexts. - -The `SessionIdManager` is agnostic with respect to the type of clustering technology chosen. - -Jetty provides a default implementation - the link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionIdManager.html[DefaultSessionIdManager] - which should meet the needs of most users. -If you do not explicitly configure a `SessionIdManager`, then when the `SessionHandler` starts, it will use an instance of the `DefaultSessionIdManager`. - -====== Using the DefaultSessionIdManager - -TODO -- description of what the SessionHandler.doStart() does to create a DefaultSessionIdManager if none configured -- code example of setting up the DefaultSessionIdManager - -====== Implementing a Custom SessionIdManager - -If the `DefaultSessionIdManager` does not meet your needs, you can extend it, or implement the `SessionIdManager` interface directly. - -When implementing a `SessionIdManager` pay particular attention to the following: - -* the `getWorkerName()` method must return a name that is unique to the `Server` instance. -The `workerName` becomes important in clustering scenarios because sessions can migrate from node to node: the `workerName` identifies which node was last managing a `Session`. -* the contract of the `isIdInUse(String id)` method is very specific: a session id may _only_ be reused _iff_ it is already in use by another context. -This restriction is important to support cross-context dispatch. -* you should be _very_ careful to ensure that the `newSessionId(HttpServletRequest request, long created)` method does not return duplicate or predictable session ids. - -[[pg-server-session-housekeeper]] -===== HouseKeeper - -There is a maximum of one link:{JDURL}/org/eclipse/jetty/server/session/HouseKeeper.html[HouseKeeper] per `SessionIdManager`. -Its purpose is to periodically poll the link:{JDURL}/org/eclipse/jetty/server/session/SessionHandler.html[SessionHandlers] to clean out expired sessions. -This operation is usually referred to as "scavenging" expired sessions. - -====== Using the HouseKeeper - -TODO -- description of the SessionHandler.doStart() creating a HouseKeeper -- code example of setting up the HouseKeeper -- configuring the scavenge interval - -===== SessionCache - -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`. - -Jetty provides two `SessionCache` implementations: the link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionCache.html[DefaultSessionCache] and the link:{JDURL}/org/eclipse/jetty/server/session/NullSessionCache.html[NullSessionCache]. - -====== Using the DefaultSessionCache -The `DefaultSessionCache` retains `Session` objects in memory in a cache and has a number of configuration options to control cache behavior. -It is suitable for non-clustered and clustered deployments with a sticky load balancer, as well as clustered deployments with a non-sticky load balancer, with some caveats. - -====== Using the NullSessionCache -The `NullSessionCache` does not actually cache any objects: each request uses a fresh `Session` object. -It is suitable for clustered deployments without a sticky load balancer and non-clustered deployments when purely minimal support for sessions is needed. - -``SessionCache``s always write out a Session to the link:{JDURL}/org/eclipse/jetty/server/session/SessionDataStore.html[SessionDataStore] whenever the last request for the `Session` exits. - -They can also be configured to do an immediate, eager write of a freshly created session. -This can be useful if you are likely to experience multiple, near simultaneous requests referencing the same session, e.g. with HTTP/2 and you don't have a sticky load balancer. -Alternatively, if the eager write is not done, application paths which create and then invalidate a session within a single request never incur the cost of writing to persistent storage. - -Additionally, if the `EVICT_ON_INACTIVITY` eviction policy is in use, you can xref:#pg-server-session-sessioncache[configure] the `DefaultSessionCache` to force a write of the `Session` to the `SessionDataStore` just before the `Session` is evicted. - -See xref:pg-server-session-sessioncache[the L1 Session Cache] for more information. - -===== SessionDataStore +[[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`. diff --git a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessionidmgr.adoc b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessionidmgr.adoc new file mode 100644 index 00000000000..cf8bea3a032 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/session-sessionidmgr.adoc @@ -0,0 +1,87 @@ +// +// ======================================================================== +// 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-sessionidmgr]] +==== Session Components: The SessionIdManager + +There is a maximum of one `SessionIdManager` per `Server` instance. +Its purpose is to generate fresh, unique session ids and to coordinate the re-use of session ids amongst co-operating contexts. + +The `SessionIdManager` is agnostic with respect to the type of clustering technology chosen. + +Jetty provides a default implementation - the link:{JDURL}/org/eclipse/jetty/server/session/DefaultSessionIdManager.html[DefaultSessionIdManager] - which should meet the needs of most users. +If you do not explicitly configure a `SessionIdManager`, then when the `SessionHandler` starts, it will use an instance of the `DefaultSessionIdManager`. + +[[pg-server-session-defaultidmgr]] +===== The DefaultSessionIdManager + +At startup, if no instance of the `HouseKeeper` has been explicitly set, the `DefaultSessionIdManager` will create one. + +Also at startup, the `workerName` is determined. +The `workerName` must be unique per `Server`, and identifies the server in a cluster. +If a `workerName` has not been explicitly set, then the value is derived as follows: + ++node[JETTY_WORKER_NAME]+ + +where `JETTY_WORKER_NAME` is an environment variable whose value can be an integer or string. +If the environment variable is not set, then it defaults to `0`, yielding the default `workerName` of `"node0"`. + +The `DefaultSessionIdManager` uses `SecureRandom` to generate unique session ids. + +The `SessionHandler` class, which is used by both the `ServletContextHandler` and the `WebAppContext` classes, will instantiate a `DefaultSessionIdManager` on startup if it does not detect one already present for the `Server`. + +Here is an example of explicitly setting up a `DefaultSessionIdManager` in code: + +[source,java,indent=0] +---- +include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java[tags=default] +---- + +===== Implementing a Custom SessionIdManager + +If the `DefaultSessionIdManager` does not meet your needs, you can extend it, or implement the `SessionIdManager` interface directly. + +When implementing a `SessionIdManager` pay particular attention to the following: + +* the `getWorkerName()` method _must_ return a name that is unique to the `Server` instance. +The `workerName` becomes important in clustering scenarios because sessions can migrate from node to node: the `workerName` identifies which node was last managing a `Session`. +* the contract of the `isIdInUse(String id)` method is very specific: a session id may _only_ be reused _iff_ it is already in use by another context. +This restriction is important to support cross-context dispatch. +* you should be _very_ careful to ensure that the `newSessionId(HttpServletRequest request, long created)` method does not return duplicate or predictable session ids. + +[[pg-server-session-housekeeper]] +===== Session Components: The HouseKeeper + +There is a maximum of one link:{JDURL}/org/eclipse/jetty/server/session/HouseKeeper.html[HouseKeeper] per `SessionIdManager`. +Its purpose is to periodically poll the link:{JDURL}/org/eclipse/jetty/server/session/SessionHandler.html[SessionHandlers] to clean out expired sessions. +This operation is usually referred to as "scavenging" expired sessions. +The scavenging interval is configured by the `setIntervalSec(long)` method. +The default value is ``600``sec, ie ``10``mins. + +[IMPORTANT] +==== +The HouseKeeper semi-randomly adds an additional `10%` of the configured `intervalSec`. +This is to help prevent sync-ing up of servers in a cluster that are all restarted at once, and slightly stagger their scavenge cycles to ensure any load on the persistent storage mechanism is spread out. +==== + +This code example shows how to configure a `HouseKeeper`, along with a `DefaultSessionIdManager`: + +[source,java,indent=0] +---- +include::../../{doc_code}/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java[tags=housekeeper] +---- diff --git a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/sessions.adoc b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/sessions.adoc index 452f63ad82b..2cb88d3c248 100644 --- a/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/sessions.adoc +++ b/jetty-documentation/src/main/asciidoc/programming-guide/server/sessions/sessions.adoc @@ -22,6 +22,6 @@ Sessions are a concept within the Servlet API which allow requests to store and retrieve information across the time a user spends in an application. include::session-architecture.adoc[] -include::session-components.adoc[] - - +include::session-sessionidmgr.adoc[] +include::session-sessioncache.adoc[] +include::session-sessiondatastore.adoc[] diff --git a/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java b/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java new file mode 100644 index 00000000000..891eba98320 --- /dev/null +++ b/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/server/session/SessionDocs.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// 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 +// ======================================================================== +// + +package org.eclipse.jetty.docs.programming.server.session; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.session.DefaultSessionIdManager; +import org.eclipse.jetty.server.session.HouseKeeper; + +public class SessionDocs +{ + public void minimumDefaultSessionIdManager() + { + //tag::default[] + Server server = new Server(); + DefaultSessionIdManager idMgr = new DefaultSessionIdManager(server); + //you must set the workerName unless you set the env viable JETTY_WORKER_NAME + idMgr.setWorkerName("3"); + server.setSessionIdManager(idMgr); + //end::default[] + } + + public void defaultSessionIdManagerWithHouseKeeper() + { + try + { + //tag::housekeeper[] + Server server = new Server(); + DefaultSessionIdManager idMgr = new DefaultSessionIdManager(server); + idMgr.setWorkerName("7"); + server.setSessionIdManager(idMgr); + + HouseKeeper houseKeeper = new HouseKeeper(); + houseKeeper.setSessionIdManager(idMgr); + //set the frequency of scavenge cycles + houseKeeper.setIntervalSec(600L); + idMgr.setSessionHouseKeeper(houseKeeper); + //end::housekeeper[] + } + catch (Exception e) + { + e.printStackTrace(); + } + } +}