Hi,
On some applications we have:
- quite low number of users most of the time
- high number of users twice a year
These applications store quite a lot of information in session.
To cope with the surge of users, we would need to:
- either increase mx (Java max memory)
- or use short session timeout (lifetime)
- or use horizontal scaling (k8s... but we currently have no such solutions)
The best solution for us would be a "maxActiveSessions" setting which would set
a high bound to the number of sessions,
but compared to current implementation, it would allow new sessions and expire
old sessions.
We mostly achieved this with a cron (1) calling a script (2): it uses
tomcat-manager to force a shorter lifetime when there is a lot of sessions.
Since it would be nicer to have this behavior directly in tomcat, I did it
using a small class extending StandardManager (2).
I wonder if this could be useful to other users?...
cu.
(1) */10 * * * * ~/tomcat/expire-if-too-many-sessions student-info 4000 8
(2) script "expire-if-too-many-sessions":
--------------
webapp=$1
max_sessions=$2
idle=$3
nb_sessions=`curl -s --user "$user" "$url/manager/text/list" | grep "$webapp" |
awk -F: '{print $3}'`
if [ $nb_sessions -gt $max_sessions ]; then
echo "too many sessions ($nb_sessions > $max_sessions). telling tomcat to expire
$webapp sessions inactive more than $idle"
out=`curl -s --user "$user"
"$url/manager/text/expire?path=/$webapp&idle=$idle"`
if echo $out | grep -q '^OK'; then
:
else
echo "error expiring: $out"
fi
fi
-------------
(3)
-------------
protected int maxActiveSessionsGoal = -1;
/**
* If you have too many sessions, you may memory overflow.
* This setting will expire old sessions to keep sessions memory usage low.
* -1 is no limit
*/
public void setMaxActiveSessionsGoal(int max) {
maxActiveSessionsGoal = max;
}
public void processExpires() {
super.processExpires();
if (maxActiveSessionsGoal >= 0) {
var nb = getActiveSessions();
if (nb > maxActiveSessionsGoal) {
expireNbOldSessions(nb - maxActiveSessionsGoal);
}
}
}
private void expireNbOldSessions(int nbToRemove) {
var time = sessions.values().stream()
.mapToLong(Session::getLastAccessedTimeInternal).sorted()
// we want the nbToRemove-th element in the array
.skip(nbToRemove).findFirst()
.orElse(0);
if (time == 0) {
log.error("internal error expireNbOldSessions");
return;
}
log.info("To achieve maxActiveSessionsGoal (" + maxActiveSessionsGoal + ") for " +
getContext().getBaseName() + ", we will expire sessions older than " + new Date(time) + " (" + nbToRemove +
" sessions)");
for (Session session : findSessions()) {
if (session.getLastAccessedTimeInternal() < time) {
session.expire();
}
}
}
-------------
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]