Performanceproblem bei JavaAgent

  • Mahlzeit,


    ich hoffe mal das wird auch hier behandelt, denn wirklich viele Posts über Java habe ich hier nicht gefunden...


    Das Problem ist folgendes:
    Ich habe einen Agenten geschrieben, der in einer DocumentCollection jedes einzelne Dokument anpackt, speichert und danach in eine andere DB kopiert. Das funktioniert auch eigentlich hervorragend, allerdings scheint sich die Performance exponentiell zu verschlechtern. Grob geschätzt: Jedesmal wenn sich die Anzahl der Dokumente in der DC verdoppelt, dann verzehnfacht sich die Laufzeit des Agenten - und nein, ich arbeite nicht rekursiv, sondern mit einer einfachen Schleife ;) Bis 50 Dokumente kein Problem, bis 100 noch erträglich, bei 200 dauert es ewig, bei 300 oder mehr scheint der Client sich einfach wegzuhängen.


    Abgesehen von der Tatsache, dass es von mir hirnverbrannt ist jedes Dokument einzeln in die DB zu kopieren und es viel performanter wäre die DC komplett rüber zu kopieren (ich habe es irgendwie nicht sinnvoll hinbekommen...), wo könnte in folgendem Code der Hund begraben sein?


    Habt erbarmen mit mir, ich bin eigentlich kein Notes Admin, sondern nur für die externen Mailrelays zuständig - aber die SpamDatenbanken fallen in mein Ressort ;) Daher ist das mein erster wirklicher Agent und mag vielleicht nicht besonders gut geschrieben sein.


    Danke im vorraus,
    Sascha


  • Ich würde mal testen ob das ganze an der Quell oder der Zieldatenbank liegt.


    Füg doch mal Zeitmessungen zwischen die einzelnen Aktionen ein und schau wo genau es sich verschlechtert.

  • Irgendwie vermisse ich in dem Agenten etwas, das dem Agenten sagt, welche Dokumente er bereits einmal behandelt hat - ich meine, daß du vor jedem Holen eines neuen Dokuments aus der collection auf das zuletzt behandelte ein


    agentContext.updateProcessedDoc(doc);


    setzen mußt. Sonst geht er bei jedem Lauf wieder und wieder über alle schon einmal behandelten Dokumente drüber. Und das erklärt das Einbrechen der Zeit für die Ausführung.

  • Zitat


    taurec schrieb:
    Ich würde mal testen ob das ganze an der Quell oder der Zieldatenbank liegt.


    Füg doch mal Zeitmessungen zwischen die einzelnen Aktionen ein und schau wo genau es sich verschlechtert.


    Gute Idee, ich guck mal ob ich das irgendwie hinbekomme. Aber irgendwie kann ich mir das eigentlich nicht vorstellen. Beide DBs laufen auf relativ dicken Maschinen. Jeweils 3,6 GHz Xeon mit 4GB Ram, Last dürfte ungefähr gleich sein.


    Was mir gerade noch so einfällt... haben Notesserver vielleicht soetwas wie eine Floodprotection? In meinem Szenario baue ich ja in sehr kurzer Zeit, sehr viele einzelne Verbindungen zu der DB auf. Fügt der Server der Ziel DB vielleicht einen künstlichen Delay ein um Überlastung zu vermeiden oder ähnliches?


    Zitat


    LN4ever schrieb:
    Irgendwie vermisse ich in dem Agenten etwas, das dem Agenten sagt, welche Dokumente er bereits einmal behandelt hat - ich meine, daß du vor jedem Holen eines neuen Dokuments aus der collection auf das zuletzt behandelte ein


    agentContext.updateProcessedDoc(doc);


    setzen mußt. Sonst geht er bei jedem Lauf wieder und wieder über alle schon einmal behandelten Dokumente drüber. Und das erklärt das Einbrechen der Zeit für die Ausführung.


    Das kann ja nicht sein, oder? Denn alle Dokumente der DC werden am Ende sowieso gelöscht.


    - Ich bearbeite das Dokument und entferne Header
    - dann speichere ich das Dokument
    - dann kopiere ich das Dokument einzeln in die andere DB
    - am Ende lösche ich die ganze DC aus der Quell DB


    Also kann ein Dokument garnicht zweimal angefasst werden meiner Meinung nach.


    Eigentlich wäre es viel geschickter wenn ich die ganze DC auf einmal in die neue DB schieben könnte. Ich gehe auch mal davon aus dass das viel performanter wäre. Aber entweder bin ich total blind, oder das geht nicht... ich tippe ja eher auf ersteres, da ich noch nicht so wirklich erfahren bin in der Agentenprogrammierung.


    Sascha

  • Nein, du baust nur eine Verbindung zur Zieldatenbank auf und über diese werden dann die einzelnen Aktionen abgearbeitet.


    Zu dem UpdateProcessedDocs kann ich dir nur recht geben.
    Das gibt nur Sinn wenn die Dokumente in der QuellDB verbleiben.


    Und nein, es gibt tatsächlich keine Methode eine NotesDocumentCollection auf einmal in eine andere Datenbank zu kopieren

  • Ok, ich habe jetzt noch ein paar extensive Tests gemacht und die Protokollierung auf die Konsole hochgefahren.


    Testweise 600 Dokumente durch den Agenten gejagt:


    - Alle Dokumente wurden bearbeitet
    - Nachdem die Dokumente durch waren, blieb Notes hängen
    - ziemlich genau 10 Minuten nach dem letzten Dokument erschien in der Javakonsole:
    Error cleaning up agent threads
    Error cleaning up agent threads


    Offensichtlich fliegt entweder dc.removeAll(false) auf die Nase, oder der Agent an sich fliegt auf die Nase - vielleicht weil er zuviel Speicher alloziiert oder zuviele Threads startet. Letzteres würde mich allerdings arg wundern.


    removeAll(false) bedeutet ja, dass er keinen forced delete macht. Kann es eventuell sein, dass er da auf irgendeinen Lock stößt und deswegen ewig wartet bis er die Dokumente löschen kann? Auch CTRL-Break bringt den Agenten nicht zum beenden, es bleibt nichts als Notes abzuschießen. Im Taskmanager kommt das übliche "Task reagiert nicht". Notes selber zieht auch keine CPU Last.


    Ich werde versuchen morgen nochmal einige Testläufe mit removeAll(true) zu starten und gucken ob das irgendwas ändert.


    Hat ansonsten vielleicht irgendjemand eine neue Idee bezüglich meiner Beobachtungen?


    Sascha

  • ich würde mal probieren ob es funktioniert, wenn du das Dokument direkt nachdem du es in die andere DB kopiert hast löschst.


    Eventuell allokiert er tatsächlich zuviel Speicher.


    Was auch etwas bringen könnte wäre das Dokument nach Bearbeitung mit Aufruf der Methode recycle explizit freizugeben.

  • So, ich habe den Agenten jetzt mal ein bisschen umgebaut und bin auf den Vorschlag von IBM eingegangen. Allerdings kann ich irgendwie nicht so wirklich sagen ob das geholfen hat.


    Beim ersten Durchlauf war alles super und er hat das erste Mal 800 Dokumente am Stück vertragen. Dann habe ich es direkt mal live getestet und prompt ist er beim 18ten Dokument schon hängen geblieben diesmal. Also habe ich mir gedacht "ok, baust du halt mal debug Meldungen ein". Tja... die nächsten 5 Durchläufe waren dann ohne Probleme. Ich kann es einfach nicht sinnvoll reproduzieren.


    Ich hänge den neuen Code nochmal an, vielleicht fällt ja irgendjemandem noch etwas dazu sein:


  • Zitat


    taurec schrieb:
    Wo genau ist er denn hängengeblieben ?
    An welcher Stelle im Code ?


    Nach dem einfügen der Debugmeldungen ist er ja nicht mehr hängen geblieben, das ist ja das Problem... sonst wäre ich ja schon weiter :/


    Aber jedesmal 800 Dokumente durch die Datenbanken schieben und die dann in den Agenten zu schießen dauert halt ziemlich lange und nach 5 Testläufen musste ich aus Zeitmangel erstmal abbrechen.

  • Zitat


    taurec schrieb:
    Wie wäre es denn wenn du die Recycle Methode dann auch für alle anderen NotesObjekte aufrufst (Database, DocumentCollection,...)


    Das könnte ich ja erst wenn die Dokumente alle durch sind, weil solange brauche ich die ja noch. Aber wie ich weiter oben schon geschrieben habe, ist er ja beim Testlauf vor dem Einfügen der Debugmeldungen einfach bei dem 18ten Dokument hängen geblieben. (Den Start eines Dokumentendurchlaufs hatte ich schon immer in der Konsole, ich habe hinterher nur noch die Meldungen vor den einzelnen Schritten eingefügt)


    Sascha

  • Vielleicht hat es sich ja von den vorigen Läufen aufgeschaukelt und diese 18 Dokumente waren dann der Tropfen der das Fass zum Überlaufen gebracht hat.


    Wirklich testen kannst du es auch nur, wenn du nach der Anpassung und vor dem ersten Lauf erstmal den Server durchstartest um wirklich alle offenen Objekte freizugeben

  • Zitat


    taurec schrieb:
    Vielleicht hat es sich ja von den vorigen Läufen aufgeschaukelt und diese 18 Dokumente waren dann der Tropfen der das Fass zum Überlaufen gebracht hat.


    Ok... das würde aber bedeuten dass Notes beim Beenden des Agenten nicht die Destructors der Objekte aufruft. Und das wäre ganz, ganz böses Mojo! Ich werde mal sehen dass ich da irgendwie Testläufe bekomme, mit denen ich ein reproduzierbares Verhalten hinbekomme.


    Zitat


    Wirklich testen kannst du es auch nur, wenn du nach der Anpassung und vor dem ersten Lauf erstmal den Server durchstartest um wirklich alle offenen Objekte freizugeben


    Öh, wieso den Server? Meinst du den Client? Es ist ja ein clientseitiger Agent, der Dokumente aus der eigenen MailDB in andere DBs verschiebt.


    Sascha

  • Nein ist es nicht, denn es steht auch ganz klar in der Doku drin, daß die recycle Methoden aufgerufen werden müssen und das fehlt in deinem Agenten komplett -> alo noch böseres Mojo, allerdings durch die Programmierung.


    Wenn ein clientseitig ausgeführter Agent Objekte in einer Datenbank referenziert, die auf dem Server liegt, dann müssen diese logischerweise auch auf dem Server angelegt werden

  • Zitat


    taurec schrieb:
    Nein ist es nicht, denn es steht auch ganz klar in der Doku drin, daß die recycle Methoden aufgerufen werden müssen und das fehlt in deinem Agenten komplett -> alo noch böseres Mojo, allerdings durch die Programmierung.


    Ich denke das ist Ansichtssache. Da ich früher auch in Java richtig programmiert habe, bin ich es gewohnt dass Java in der GC selbstständig Destructoren aufruft. Das war und ist der große Vorteil von Java gegenüber den anderen Hochsprachen, wo man manuell Speicher alloziiern und dealloziieren muss. Ist aber jetzt nicht wirklich die wichtige Thematik hier :)


    Zitat


    Wenn ein clientseitig ausgeführter Agent Objekte in einer Datenbank referenziert, die auf dem Server liegt, dann müssen diese logischerweise auch auf dem Server angelegt werden


    Hm, das verstehe ich ehrlich gesagt nicht. Wenn ich auf einem Client mit einem Agenten Speicher alloziiere, dann belegt das auch Speicher auf dem Server? Das ist für mich nicht nachvollziehbar. Der Agent läuft doch lokal in einer Sandbox und das einzige was er mit dem Server macht, ist Daten ziehen und schieben - aber die Verwaltung selbiger passiert doch komplett lokal?


    Sascha

  • Die Aussage trifft auf reine Java Objekte auch zu, aber hier musst du unterscheiden, daß die Notes Klassen nichts anderes sind wie Wrapper für die Notes Objekte und jedesmal wenn du nur Wrapper verwendest muss auch dafür gesorgt werden die im Hintergrund referenzierten Objekte wieder freizugeben.


    Mit den einfachen reinen Java Objekten funktioniert dieser Automatismus schon, aber eben nicht wenn noch andere Background Klassen, die eben mehr als einfache Java Klassen sind, im Spiel sind.


    Wie wäre es wenn du den Agenten einfach erst mal sauber schreibst und schaust ob dann die Probleme überhaupt noch da sind ?