Toon posts:

[j2ee/Tomcat] Meerdere aanvragen 1 pagina te gelijk

Pagina: 1
Acties:

Verwijderd

Topicstarter
Momenteel begeleid ik een migratie traject voor een klant waarbij men een J2EE applicatie omzet van het sterk verouderde Orion naar het nieuwere (en goedkopere) Tomcat.

Hoewel het natuurlijk niet hoort, zit in het design van deze applicatie dat de gebruiker meerdere requesten voor dezelfde pagina tegelijk kan doen. Terwijl op de ene pagina een berekening plaatsvind, kan de gebruiker in een andere tab of window dezelfde pagina nogmaals opvragen.

Nu blijkt dat tomcat per user maar 1 request per enkele jsp pagina tegelijk afhandeld. Als pagina /a.jsp nog aan het executen is, en je doet een 2de request voor /a.jsp dan wacht deze totdat de eerste klaar is. Nu zou je mischien meteen denken: SingleThreadModel, maar dat is hier niet van toepassing. Vanuit verschillende sessies kun je de pagina wel gewoon tegelijk opvragen.

Ik heb het gedrag nagebootst met de meest simpele JSP pagina, alleen een System.out erop en daarna een Thread.sleep(). Hieraan kun je goed zien dat Tomcat wacht met het verwerken van de 2de request voor dezelfde pagina totdat de eerste is afgerond. Als je tegelijk een hele andere pagina opvraagt gaat deze wel gewoon door.

In de J2EE spec (1.4) kan ik niks over dit gedrag vinden. Het lijkt erop dat het of een tekortkoming van tomcat is, of dat het een hidden 'feature' is.

Weet iemand meer hierover?

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Voor zover ik weet hadden de requests ook gewoon parallel naast elkaar uitgevoerd moeten worden.

Wat probeer je trouwens nu te regelen? Is er bv een of ander proces dat geactiveerd moet worden en waarbij je wilt uitsluiten dat het bv meerdere keren gaat draaien?

[ Voor 3% gewijzigd door Alarmnummer op 03-10-2006 07:24 ]


  • flowerp
  • Registratie: September 2003
  • Laatst online: 04-02 02:01
Verwijderd schreef op maandag 02 oktober 2006 @ 22:51:
Nu blijkt dat tomcat per user maar 1 request per enkele jsp pagina tegelijk afhandeld.
Hier ben ik een tijdje geleden ook tegen aan gelopen. Uiteindelijk bleek dit niet aan Tomcat te liggen maar aan de browser!

We kwamen hierachter toen we op een gegeven moment Tomcat in debug mode hadden draaien en zagen dat het in de native socketAccept (uit java.net) call lag. Die reageerde meteen op een andere page maar niet op de page die reeds aan het executen was.

Ik werk eigenlijk nooit met Windows, en gebruik voor het testen van de web applicaties voornamelijk Firefox en daarnaast Opera. Ik heb toen even op Windows met Internet Explorer getest, en toen bleek ik -wel- twee maal dezelfde pagina tegelijk te kunnen aanvragen. Omdat we al zo lang aan het zoeken waren destijds hebben we het niet nog verder onderzocht, het is dus een beperking van Firefox of mischien wel van de combinatie Firefox/Tomcat.

Nog een aardig weetje: bij het opvragen van een 3de andere pagina terwijl unieke pagina 1 en 2 nog executen gebeurd er ook niks bij Firefox/Tomcat. De aanvraag van de 3de pagina komt pas door als 1 van de andere 2 de response heeft gecommit. Dit zit waarschijnlijk in het http protocol wat default het aantal connections van client (browser) naar server limiteerd op 2 of 4.

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Verwijderd

Topicstarter
Alarmnummer schreef op dinsdag 03 oktober 2006 @ 07:23:
Wat probeer je trouwens nu te regelen? Is er bv een of ander proces dat geactiveerd moet worden en waarbij je wilt uitsluiten dat het bv meerdere keren gaat draaien?
Zoiets ja. Men had gebruik gemaakt van een statefull object (is eigen pleonasme, een object heeft eigenlijk per definitie state ;) ) dat niet thread safe is. In de oude situatie had men dit opgelost door op de JSP pagina een synchronize ( objectInKwestie) { ... } te zetten.

In de nieuwe situatie wordt het object verwerkt door een (custom made) JSF component. Vanwege de lifecycle fases van JSF (oa de aparte restore tree en render fase) is er geen eenduidig block om synchronized te gebruiken, zeker niet per component. JSF loopt namelijk per fase al je componenten af. Als je per fase een synchronize gebruikt heb je kans dat er net tussen twee fases iets er tussen glipt, en dat mag natuurlijk niet.

Nu zie ik globaal 2 oplossingen: een lock gebruiken; als JSF in de eerste fase bij mijn component kom lock ik het object, en in de laatste fase unlock ik het. De andere oplossing is het object zoveel mogelijk threadsafe te maken en de delen die niet threadsafe kunnen (iterators bijvoorbeeld) te clonen. Bij alle 2 de aanpakken zitten hele subtiele haken en ogen.

Ik ben echter begonnen met de eerste aanpak, en toen ik dat wilde testen bleek het dus dat Tomcat al de pagina voor me leek te locken waarop ik deze post maakte ;)
Hier ben ik een tijdje geleden ook tegen aan gelopen. Uiteindelijk bleek dit niet aan Tomcat te liggen maar aan de browser!
Meteen snel getest en het klopt! Het is inderdaad Firefox. Bij IE worden de pagina's wel gewoon parallel uitgevoerd. Vaag zeg, maar goed ik kan iniedergeval even verder rommelen :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op woensdag 04 oktober 2006 @ 19:57:
[...]


Zoiets ja. Men had gebruik gemaakt van een statefull object (is eigen pleonasme, een object heeft eigenlijk per definitie state ;) ) dat niet thread safe is. In de oude situatie had men dit opgelost door op de JSP pagina een synchronize ( objectInKwestie) { ... } te zetten.
Ik ben net bezig met een paar blogs over hoe je het beste processen (of hoe in ieder geval niet :P ) je langlopende backendprocessen kunt aansturen vanuit bv een client gui. Ik kan nog wel even kijken waar ik wat voorbeelden heb liggen van een presentatie die ik een tijd geleden heb gegeven.

Verwijderd

Topicstarter
Alarmnummer schreef op woensdag 04 oktober 2006 @ 20:01:
[...]

Ik ben net bezig met een paar blogs over hoe je het beste processen (of hoe in ieder geval niet :P ) je langlopende backendprocessen kunt aansturen vanuit bv een client gui. Ik kan nog wel even kijken waar ik wat voorbeelden heb liggen van een presentatie die ik een tijd geleden heb gegeven.
Klinkt interesant. Voor backendprocessen wil ook nog wel eens gewoon een Quartz job schedulen. Deze krijgt dan toegang tot een shared structure waar zowel de draaiende job als de controller achter de gui dingen in kan posten.

Zo heb ik een job die een dataverwerking start en telkens in die shared structure post op welk punt hij zit: "analysis started", "scanner accessed", "started processing", etc. De (web) gui bevat een JSF component dat dmv AJAX telkens een kleine query naar de server stuurt die op z'n beurt weer de laatste messages ophaalt en naar de client stuurt. Omgekeerd kun je ook zo weer controlle naar de job sturen. Zo heb ik nu de opties pauze, resume, stop en goback. Na elke iteratie polled de job even snel de shared structure en kijkt of er al commando's voor hem zijn.

Bij het huidige probleem is dit in z'n geheel niet van toepassing. Het object bevat erg veel state dat eigenlijk gewoon view state is (keuze uit selectie boxen, ingevulde waarden, maar ook de geschiedenis daarvan) alsmede data die gegenereerd is aan de hand van die view state.

Als ik het hele component overnieuw kon maken in JSF zou erg veel hiervan gewoon view state worden (bewaart JSF automatisch voor je). Je zou dan nog wel voorzichtig met de ruwe data om moeten gaan, maar in JSF kijk je dan meestal welke subselectie van de data de view momenteel nodig heeft en cloned die dan ter plekke. Dat heeft dan wel weer als nadeel dat als je bijvoorbeeld een tabel weergeeft (zeg met de Tomahawk table) en je pager zegt dat je 4 pagina's hebt, je na een click voor de volgende page er opeens maar 3 kan hebben.

Maar ja, dit verhaal is dus niet van toepassing omdat het object al bestaat en enkele duizenden regels zeer specialistische code bestaat. Die ga ik zeker niet even in z'n geheel omschrijven ;)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op woensdag 04 oktober 2006 @ 20:30:
[...]


Klinkt interesant. Voor backendprocessen wil ook nog wel eens gewoon een Quartz job schedulen.
Als ik echt controle nodig ben gebruik ik alleen nog de timer functionaliteit van quartz en rest over aan de java.util.concurrent.Executor. Dat zou eventueel nog met een implementatie van quartz zijn TheadPool interface.. maarja.

Ander probleem is trouwens dat quartz een enkele thread gebruikt voor de timer. Als de timer zijn werk niet in de threadpool kan zetten dan blokkeerd de timer. En daar zul je dan ook rekening mee moeten houden: dus ik wil volledige controle over missed deadlines, overload en dat soort meuk. Dan kan ik zelf bepalen of ik de job wil droppen, een error ga opwerpen of iets volledig anders.
Deze krijgt dan toegang tot een shared structure waar zowel de draaiende job als de controller achter de gui dingen in kan posten.
Dat is idd een handige aanpak om je gui-thread te onkoppelen van het proces dat gaat draaien.
Zo heb ik een job die een dataverwerking start en telkens in die shared structure post op welk punt hij zit: "analysis started", "scanner accessed", "started processing", etc. De (web) gui bevat een JSF component dat dmv AJAX telkens een kleine query naar de server stuurt die op z'n beurt weer de laatste messages ophaalt en naar de client stuurt. Omgekeerd kun je ook zo weer controlle naar de job sturen. Zo heb ik nu de opties pauze, resume, stop en goback. Na elke iteratie polled de job even snel de shared structure en kijkt of er al commando's voor hem zijn.
Goed over nagedacht. Ik pas dezelfde structuur ook toe (het lijkt veel op de reactor design pattern). In sommige gevallen maak ik ook toevoegingen voor blokkeren, timeouts voor blokkeren. Maar is volledig afhankelijk van de toepassing wat er nodig is. Je kunt deze aanpak ook gebruiken om bepaalde processen uit te sluiten om concurrent te draaien en verder is het ook handig om het aantal concurrent threads mee te controleren (in jouw geval heb je er 1 maar in sommige gevallen ben je er meer nodig).

[ Voor 13% gewijzigd door Alarmnummer op 04-10-2006 22:49 ]

Pagina: 1