# Tomcat: Sessions bleiben zu lange erhalten



## tme (13. Jan 2010)

Hallo,

wir haben eine J2EE-Applikation auf einem Tomcat-Server zu laufen. User machen per Browser Webrequests, die durch mehrere Listener laufen. Einer dieser Listener wurde eingerichtet, um die Sessions zu zählen und Informationen über Zahlen und Daten Sessions vorzuhalten.

Wir hatten Probleme mit der Menge an Sessions. Wir haben daraufhin den Session-Timeout des Tomcat-Servers von 30 auf 10 Minuten reduziert:


```
web.xml:        <session-timeout>10</session-timeout>
```

Wenn wir jetzt in unserem Programm die Liste der Sessions durchgehen, fällt auf, dass viele Sessions existieren, die Idle-Zeiten von mehr als 600 Sekunden vorweisen.

Haben wir die Einstellung "session-timeout" falsch verstanden?

Danke.


----------



## SlaterB (13. Jan 2010)

was stellst du dir denn vor, soll nach den 600 Sekunden passieren?
und passiert dies vielleicht jetzt schon nur später? wann denn dann, nach wieviel Sekunden?

vielleicht ist die Session für den Webserver schon geschlossen, nur kannst du das nicht erkennen wie auch immer du derzeit nachschaust,
vielleicht wird sie gerade nicht geschlossen, weil du sie in einer Liste hälst (das wäre sicher ungewöhnliches Pech)

oder beschreibst du oben eine Auswertung von neuen Requests, wobei nur nachgeschaut wird, ob in der Session eine entsprechende Information gesetzt ist?
dann schon systematisches Vorgehen versucht, neuer Request nach 500 Sekunden, 550, 600, 650, ..
nach wieviel Sekunden ist sie weg, ist das immer so oder wechselhaft?

verwendest du/ ihr HttpSessionListener mit sessionDestroyed() oder ähnliches?
Servlet: session listener : SessionServletsJava

(bis auf Fragen leider keine direkten Informationen  )

edit:
im gelinkten Beispiel steht 
setMaxInactiveInterval(),
das schon benutzt und/ oder mit getMaxInactiveInterval() die bisherige Einstellung geprüft?
: Interface HttpSession


----------



## FArt (14. Jan 2010)

Ein Timeout-Parameter legt in der Regel fest, wie lang eine Session garantiert zur Verfügung steht, nicht nach welcher Zeit sie garantiert nicht mehr existiert. Dem Container ist überlassen, ob die Session u.U. noch länger existiert, das hängt von der Implementierung ab. In der Spec ist das nicht spezifiziert.


----------



## tme (14. Jan 2010)

Hallo Slater,

danke für die Antwort.



SlaterB hat gesagt.:


> was stellst du dir denn vor, soll nach den 600 Sekunden passieren?



Bei uns hängen einige Daten nur an der Session, wie ein temporärer Warenkorb, ein Phantomnutzer (unangemeldet) oder ein echter Nutzer (angemeldet), Benutzerrechte, Preise usw. Wir sehen zu Spitzenzeiten Ca. 4000 Sessions auf dem System, was so ungefähr ein Wert ist, bei dem unser Server manchmal in die Knie geht.

Wir würden gerne, dass das Session-Objekt nach dieser Zeit invalid wird. Ein Nutzer, der also mit dieser Session im Shop unterwegs ist und X Sekunden (in unserem Falle also 600) keinen neuen Request produziert, soll abgemeldet werden, also die Objekte, die mit seiner Session verbunden sind, verworfen werden.



SlaterB hat gesagt.:


> und passiert dies vielleicht jetzt schon nur später? wann denn dann, nach wieviel Sekunden?



Nunja, nachdem ich viele zusätzliche Einstellungen für die Protokollierung der Ausführung des GC bereits integriert habe, ist zu den Spitzenzeiten zu sehen, dass der GC vergeblich versucht, Objekte zu collecten (ca. alle 7.5 Sekunden crawlt er 4.5GB Objekte durch). Wir vermuten stark, dass es sich bei einem Großteil um Sessions handeln, die vom Nutzer her bereits invalid sind, also z.B. ein geschlossener Browsertab nach Bestellungen oder Leute, die den Shop offen haben und dann in die Mittagspause gehen.



SlaterB hat gesagt.:


> vielleicht ist die Session für den Webserver schon geschlossen, nur kannst du das nicht erkennen wie auch immer du derzeit nachschaust, vielleicht wird sie gerade nicht geschlossen, weil du sie in einer Liste hälst (das wäre sicher ungewöhnliches Pech)



Letzteres würde ich ausschließen wollen, da nicht oft jemand die Liste der Sitzungen prüft.



SlaterB hat gesagt.:


> verwendest du/ ihr HttpSessionListener mit sessionDestroyed() oder ähnliches?



Genau diese, also sessionCreated() und sessionDestroyed() werden über die Listener aufgerufen und tätigen die Einträge in eine ArrayList.



SlaterB hat gesagt.:


> im gelinkten Beispiel steht
> setMaxInactiveInterval(),
> das schon benutzt und/ oder mit getMaxInactiveInterval() die bisherige Einstellung geprüft?
> : Interface HttpSession



Guter Hinweis. Besteht also dann unsererseits ein Verständnisproblem über den Mechanismus, der Sessions invalidiert? Wir waren der Meinung, dies würde der Tomcat über seine Listenerchain aktivieren und entsprechend nach dem eingestellten Intervall deaktivieren, wobei die Session dann aus der ArrayList entfernt wird und vom GC geholt werden kann.

Wie würde denn dann die von dir genannte Einstellung mit der Einstellung in der Tomcat-Konfiguration zusammenarbeiten? Bedeuten die Einstellungen unterschiedliche Dinge? Ist die Einstellung der Tomcat-Konfiguration gar der Default-Wert für die Session, welcher jedoch mit der von dir genannten Funktion übersteuert werden kann?

Danke.


----------



## SlaterB (14. Jan 2010)

ich kann dazu leider nix genaues sagen, aktuell nicht mal ausprobieren, bin da nich drin,
nur allgemeine Hinweise:
immer noch offene Frage: werden denn die Sessions überhaupt irgendwann zerstört, das sollte sich doch prüfen lassen,
wieviel Sekunden sind es dann, immer gleich oder unterschiedlich, Statistik aufstellen

> Letzteres würde ich ausschließen wollen, da nicht oft jemand die Liste der Sitzungen prüft.

prüfen an sich mag nicht wichtig sein, aber die Sessions sind doch wohl die ganze Zeit in irgendwelchen Listen?
na auch egal, daran kann es ja nicht liegen,

aber diese Liste kann man als Vorteil nutzen, irgendein Thread durchläuft die alle 10 Sek., 
wenn er bei einer Session eine Idle-Zeit von > 600 feststellt, dann sperrt er diese Session, löscht alle zugehörigen Daten, setzt eine Information 'vorerst Ende' usw.,
ganz egal welchen Status Tomcat für diese Session vorsieht,

interessant wirds, wenn der User dann doch noch mal wiederkommt und Tomcat die alte Session weiterverwendet, 
alle Programmteile müssen dann damit umgehen können, dass das mehr oder weniger eine ganz neue frische Session ist,
auch wenn es ein Objekt ist, welches schon mal da war,
sollte möglich sein, wenn die Session quasi leer ist, geht höchstens um die SessionId, hashCode(),
ich finde darauf sollte man sich eh nicht verlassen, was der Server macht ist eh eine Blackbox, der könnte glatt offiziell beendete Session-Objekte später für andere User wiederverwenden 
nur selber gesetzte Daten zählen

edit: allerdings kommt man dann nicht (immer) bei offiziellen Methoden wie sessionCreated()/ Destored() vorbei,
daher evtl. nicht so leicht umsetztbar, das Session-Handling müsste allgemein bei jedem Request passieren

-------

siehe auch Antwort von FArt


----------



## FArt (15. Jan 2010)

Analysiere mal die Logfiles. Dort wirst du sehen, wann Tomcat eine Session erstellt, wann er sie löscht usw.
Dann ist auch eindeutig zu sehen, wie viele Sessions "zu Spitzenzeiten" aktiv sind (und dann wohl auch nötig sind). Ich gehe davon aus, dass Tomcat die Sache mit den Sessions und Timeouts drauf hat ;-)

Wenn wirklich so viele Sessions nötig sind, musst du nicht am Timeout drehen sondern die Webapplikation skalieren. Eine einfache Lösung wären zwei Tomcats mit einem Apache und ModJK davor.
Man kann auch Tomcat so konfigurieren, dass er eine Session nach kurzer Zeit passiviert (persistiert) und aus dem Speicher entfernt, da viele Sessions oft lange Zeit keine Request beantworten (das sind glaube ich Konfigurationsparameter, die irgendwas mit IDLE heißen) und nur relativ wenige Sessions tatsächlich aktiv sein müssen. Wie sinnvoll das ist hängt aber stark von der Applikation ab (also wie sie verwendet wird) und wie viele Daten an einer Session hängen (Overhead durch Marshalling/Unmarshalling).


----------



## maki (15. Jan 2010)

> Wir vermuten stark, dass es sich bei einem Großteil um Sessions handeln, die vom Nutzer her bereits invalid sind, also z.B. ein geschlossener Browsertab nach Bestellungen oder Leute, die den Shop offen haben und dann in die Mittagspause gehen.


Vermuten = Raten

Ist gar nicht nötig mit den heutigen Tools, von VisualVM & anderen allgemeinen JMX Tools bis hin zu LambdaProbe, welches speziell für Tomcat entworfen wurde und in der Lage ist Fragen wie "Wie viele Sessions sind noch offen, wie groß sind diese und welche Objekte stecken da drin" direkt zu beantworten.


----------



## FArt (15. Jan 2010)

maki hat gesagt.:


> Vermuten = Raten


Yepp. Aber das ist mit Kanonen auf Spatzen geschossen, noch dazu weißt zu zwar dann, wie viele Sessionobjekte irgendwo rumkugeln, aber nicht unbedingt in welchem Teil ihres Lebenszyklus sie sich im Container befinden.

Die erste Disziplin sollte Logfiles lesen sein.


----------



## maki (15. Jan 2010)

> Yepp. Aber das ist mit Kanonen auf Spatzen geschossen,


In Prodktion gehört bei mir LamdbaProbe dazu wenn Tomcat verwendet wird, sonst tappt man im Dunkeln imho 



> noch dazu weißt zu zwar dann, wie viele Sessionobjekte irgendwo rumkugeln, aber nicht unbedingt in welchem Teil ihres Lebenszyklus sie sich im Container befinden.


http://www.lambdaprobe.org/d/screenshots/full/sessions.png
Finde die übersicht eigentlich sehr ausführlich


----------



## FArt (15. Jan 2010)

Ich meinte natürlich die Tools wie JVisualVM und andere JMX Tools (und Profiler).

Lambdaprobe ist gut, aber dennoch erst die zweite Disziplin... IMHO....


----------



## maki (15. Jan 2010)

Ok, sehe ich ein 

Logs sind nunmal auch in der Lage Dinge zu dokumenteiren die "nicht gerade jetzt" passiert sind, da nutzen JMX Tools wenig.


----------



## Java.getSkill() (17. Jan 2010)

Eine noobbemerkung, aber kannst du, wenn du die liste durchgehst und bei jeder session nachfragst, wie lange sie inaktiv ist, nicht einfach 


```
session.invalidate()
```

machen?


----------



## tme (19. Jan 2010)

Java.getSkill() hat gesagt.:


> Eine noobbemerkung, aber kannst du, wenn du die liste durchgehst und bei jeder session nachfragst, wie lange sie inaktiv ist, nicht einfach
> 
> 
> ```
> ...



Huhu und danke für die Antwort,

derzeit suche ich noch nach einem Automatismus, mit dem die Sessions entfernt werden können. Ich gehe davon aus, dass ein Mechanismus vom Tomcat wasserdichter sein wird als eine Routine, die ich mir zu diesem Thema aus den Fingern saugen kann.

In jedem Falle ist Probe ein Klasse Tool und hat ersteinmal sehr viel weitergeholfen.

Danke.


----------



## tme (22. Jan 2010)

Die Lösung für das Problem war relativ banal:

Trotz Konfiguration von Tomcat auf ein Timeout von 10 Minuten baute das übernommene Ant-Skript eine spezielle web.xml mit in das .WAR-Archiv, welche noch einen Timeout von 30 Minuten hatte. Dank Probe wurde dieser Umstand klar. Eine Änderung dort hat den gewünschten Effekt gebracht, Sessions werden jetzt kurz nach Ablauf einer Idle-Time von 10 Minuten collected.


----------

