Komfortables Job Scheduling auf Basis des Oracle Scheduler Peter Hawelka und Dieter Pfingsten pdv Technische Automation + Systeme GmbH Hamburg Schlüsselworte: Job Scheduler, Job-Scheduling, dbms_Scheduler, Batch, Steams Advanced Queueing Motivation und Übersicht Trotz umfangreicher online-Verarbeitung innerhalb von Benutzerdialogen bleibt die Job-Verarbeitung in datenintensiven Applikationen eine wichtige Komponente auch in modernen komplexen ITSystemen. Die Job-Ablaufsteuerung ist dabei das Instrument zum kontrollierten Ablauf der Hintergrundprozesse einzeln oder logisch verkettet. Der Fehlerbehandlung und dem Wiederaufsetzen von Jobs kommt dabei eine besondere Bedeutung zu. In unserem Vortrag geben wir einen kurzen Überblick, wie wir in einem konkreten Projektumfeld die Oracle-Scheduling-Funktionen der Datenbank für den Aufbau eines leistungsstarken, einfach zu bedienenden Job Scheduler genutzt haben und welche Erweiterungen und Zusatzmodule notwendig waren um die Anforderungen an einen modernen Job Scheduler umzusetzen. Insbesondere stellen wir Ihnen die mit dem Oracle ADF-Framework erstellte Benutzeroberfläche vor und gehen kurz auf die Möglichkeiten ein, die ADF 11g mit seinen Ajax Komponenten zur Erstellung einer modernen WebOberfläche bietet, wie sie sonst nur mittels klassischer Rich-Clients umgesetzt werden konnten. Der hier vorgestellte Job Scheduler soll in einer komplexen, bereits bestehenden, OracleDatenbankanwendung mit Oracle Forms-Clients und einer Internet gestützten B2B-Komponente, sämtliche anfallenden Abläufe zentral steuern und automatisieren. Die abzubildenden Arbeitsabläufe ergeben sich aus den Geschäftsprozessen eines großen Lotterieveranstalters in Hamburg und seinen unabhängigen Vertriebsorganisationen. In der Zentrale werden Gewinnziehungen durchgeführt und die Gewinninformationen und Spielberechtigungen mit den Vertriebsorganisationen ausgetauscht. Kommunikationswege sind der klassische DFÜ-Datenaustausch und die internetgestützte Bereitstellung von B2B-Diensten für die dezentralen Vertriebsorganisationen. Die Motivation, das bisher im Einsatz befindliche Job Scheduling Produkt durch ein nur auf OracleFunktionen basierendes System zu ersetzen war eine geplante Migration der Oracle-Datenbanken in eine virtualisierte Real Application Cluster (RAC) Umgebung. Vorzugsweise sollte in dieser Umgebung auf Third Party - Herstellerprodukte verzichtet werden, soweit dieses wirtschaftlich sinnvoll umgesetzt werden kann. Hieraus ergaben sich teilweise spezielle Anforderungen an die JobScheduler-Funktionen. So sollte die Migration der bestehenden Arbeitsabläufe (Workflows), die in speziellen Datenbankskripten hinterlegt sind, einfach und kostengünstig möglich sein. Die grundlegenden Eigenschaften des Oracle Schedulers mussten daher angepasst werden. Um dieses einfach zu erreichen, entschlossen wir uns, eine weitere API-Schicht über die Oracle Scheduler API zu legen. Diese API stellt nur die Funktionen bereit, die benötigt werden und verbirgt sämtliche zusätzliche Komplexität. Zur Kontrolle des weitgehend automatisch- und ereignisgesteuerten Ablaufs von mehreren hundert Jobs täglich wird ein leistungsfähiger Job-Browser benötigt, der sich vorzugsweise als WebAnwendung in die bestehende IV-Infrastruktur integriert. Hauptmerkmal des Job-Browsers sind die Darstellung von hierarchischen Job-Ablaufketten und die Möglichkeit, Störungen im Ablauf der Jobketten frühzeitig zu erkennen und bearbeiten zu können. Werkzeuge hierfür sind die Darstellung von Ablaufprotokollen, die Filterung von Jobs mittels dynamischer Jobfilter und die Möglichkeit der administrativen Ressourcensteuerung mittels Job-Queues. Es muss beispielsweise möglich sein Wartungsfenster administrativ auch kurzfristig so einzuplanen, dass der Betriebsablauf so wenig wie möglich gestört wird. Das dbms_scheduler Package der Oracle-Datenbank: was kann es und was kann es nicht? Mit der Oracle Datenbank Version 10g wird eine weitgehend überarbeitete API für die in die Datenbank eingebauten Scheduling-Funktionen seitens Oracle bereitgestellt. Diese API, das dbms_scheduler Package, ersetzt das alte dbms_jobs Package und stellt aufgrund seiner vielen Erweiterungen ein stabiles Fundament für einen Job Scheduler dar. Allerdings ist die Bedienung der API aufgrund ihrer Vielfältigkeit nicht ganz einfach und damit die Umsetzung für einen Job Scheduler, so wie er in unserem Projekt benötigt wird, relativ aufwendig. Des Weiteren fehlen Funktionen, die eine einfache Hierarchisierung der Jobabläufe ermöglichen. Die Umsetzung von Job-Queues, so wie diese benötigt werden, kann nicht mit der zur Verfügung stehenden API alleine umgesetzt werden. Ebenso erweist sich das im Enterprise Manager bereitgestellte Web-Interface für die Anforderungen des Kunden als nicht brauchbar. Vielmehr wird eine speziell auf das Job Scheduling zugeschnittene Arbeitsoberfläche benötigt, die einfach und intuitiv bedienbar ist und alle notwendigen Arbeitsfunktionen in Bezug auf die administrative Jobsteuerung und Überwachung bereitstellt. Abb. 1: Schematische Darstellung der Bedienung des Oracle dbms_scheduler Die grundlegende Struktur des Oracle-dbms_scheduler Package kann man sich vereinfacht so vorstellen: Aufgaben werden in Form von Programmen als Datenbankobjekt gespeichert, dem Programm zugeordnet wird sein „Schedule“, der ebenfalls in der Datenbank gespeichert wird. Ein „Schedule“ enthält die Information, wann und wie ein Job die im Programm definierten Aufgaben, ausführen soll. Der Job kann auch als Instanz eines Programms angesehen werden. Für jedes Programm können Argumente definiert werden, über die dem Job Informationen zur Laufzeit mitgegeben werden. Schematisch lassen sich die Beziehungen eines Jobs des Oracle Scheduler wie in der Abbildung 2 gezeigt, darstellen. Abb. 2: Darstellung eines Oracle-dbms_scheduler-Jobs mit seinen Beziehungen Wie die Aufgabe, die ein Job ausführen soll, formuliert werden muss, wird durch den Parameter „program_type“ im Befehl „create_program“ definiert. Ein einfacher „program_type“, um bestehende PL/SQL-Prozeduren auszuführen, ist die „STORED_PROCEDURE“. Das bedeutet, im Programm wird lediglich die „program_action“ mit der Referenz auf ein weiteres Datenbankobjekt, der „Stored Procedure“ hinterlegt. Die Stored Procedure kann nun beliebigen PLSQL-Code enthalten, der die auszuführende Aufgabe hinreichend beschreibt und mit dem Job wird diese Aufgabe dann ausgeführt. Oracles Job-Chains versus Job-Hierachie? Oracle verwaltet die Jobs mit seinen Laufzeitinformationen in zentralen System-Tabellen und stellt mit seinen ALL_SCHEDULER-Views Sichten auf die Programme und Jobs zur Verfügung. Es zeigte sich jedoch, dass für ein Job-Scheduling wesentliche Mechanismen fehlen oder nur schwer zu realisieren sind. Insbesondere lassen sich hierarchische Beziehungen von Jobs, das heißt die dynamische Aufrufgeschichte, wie sie zur Laufzeit ausgeführt wurde, nicht einfach abbilden. Mit dem im Oracle Scheduler bekannten Job-Chains lassen sich nur statische Ablaufketten abbilden. Dieses reicht für unseren Anwendungsfall, wie oben kurz begründet, jedoch nicht aus. Folgende zusätzliche Informationen zu den Jobs müssen verwaltet werden: - Erweiterte Job-Zustandsinformationen (Job-Status) - Erweiterte Parameter zum automatischen Löschen von bereits ausgeführten Jobs, den KeepParametern, die zeitlich oder mengenmäßig definiert werden sollen - Erweiterte Protokollierungsarten und Speicherung aller Protokolle in der Datenbank - Eindeutige Referenz zur Jobinstanz. Job Namen sind einzigartig mit einem Ablauf eines Jobs verbunden. - Ablauf von synchronen und asynchronen Jobs - Anwendungsberechtigungen müssen auch für Jobs gelten - Job-Ressourcenverwaltung mittels Job-Queues Aufbau eines effektiven Job-Scheduler: unser Lösungsansatz Aus der Analyse des zuvor durch ein Drittprodukt bereit gestellten Job-Schedulings ergaben sich die wesentlichen Anforderungen an die zu implementierenden Job-Scheduling-Funktionen, die hier kurz zusammengefasst sind: - - Jobketten müssen hierarchisch verwaltet werden können, d.h. eine einfache Eltern-KindBeziehung der Jobs muss repräsentiert werden. Diese Hierarchien müssen vom Job-Browser entsprechend dargestellt werden können, wobei Hierarchiebäume nur bei Bedarf aufgeklappt dargestellt werden sollen. Jobs werden immer als einmalige Jobinstanz gesehen, damit sämtliche Laufzeitprotokolle und Ausführungsprotokolle eindeutig einem Ablauf zugeordnet werden können und so lange wie gewünscht erhalten bleiben. Ein Mechanismus zum automatischen Löschen nicht mehr benötigter Jobinformationen beendeter Jobs muss implementiert werden, wobei beispielsweise fehlerhaft beendete Jobs zur Fehlerbearbeitung erhalten bleiben sollen, also nicht automatisch gelöscht werden dürfen. Die Job-Ressourcen-Steuerung soll durch Job-Queues erfolgen, so dass Jobs deklarativ zu Gruppen zusammengefasst werden können und hierdurch eine zentrale Ressourcen-Steuerung und Administration erfolgen kann. Differenzierte Anzeige von Jobzuständen, wie beispielsweise der Status, den wartende Jobs aufgrund der Job-Queue Verfügbarkeit annehmen. Hieraus wurde eine Softwarestruktur erarbeitet, die einerseits das Oracle Dbms_Scheduler-Package mit den Oracle Job-Daten und dem Qracle Streams AQ als Basisfunktionalität nutzt, die notwendigen Erweiterungen an Metadaten und Funktionen mittels einer übergeordneten Job-View und einer funktionalen API-Schicht (Job-Scheduler-API) verbindet, so dass eine einfache, leicht bedienbare API und Datenschnittstelle (Job-View) für die Anwendungsprogrammierung bereit steht. ADF Job Browser Anwendungsprogramme - PLSQL Stored Procedure Job View Job-Scheduler API Oracle dbms_scheduler API Job Queues / Events File Watcher Oracle Jobs Metadaten Jobs Oracle Streams AQ Abb. 3: Schematische Darstellung der Job-Scheduler Software Schichten Job-Queues realisiert mit Oracle Streams Advanced Queueing (AQ) Das Oracle Streams AQ ist ein in die Datenbank eingebetteter asynchroner Mechanismus zur Nachrichtenübermittlung, mit dem über die Datenbank Informationen von einem Producer gesendet und von einem oder mehreren Consumern gelesen werden. Für die Nachricht steht eine frei definierbare Nachrichtenstruktur zur Verfügung. Dieser Mechanismus wird zur Interprozesskommunikation vom Oracle Scheduler genutzt. Es liegt daher nahe, diesen Mechanismus auch für die Implementierung der Job-Queues zu nutzen. In unserem Beispiel geschieht dieses im Prinzip in folgender Weise: Basis aller Job-Queues ist eine Queue-Table erzeugt mit Dbms_aqadm.create_queue_table(queue_table_name,payload,..) wobei mit payload der Datentyp der Nachricht definiert wird. Es kann ein DB interner Typ, aber auch ein anwendungsspezifischer Typ sein. Anschließend wird eine Message-Queue definiert und angegeben, wer Nachrichten daraus konsumieren darf: Dbms_aqadm.create_queue(queue_name,queue_table_name,..) Dbms_aqadm.add_subscriber(queue_name,consumer) Um die Anzahl der Message-Queues gering zu halten, haben wir nicht für jede Job-Queue eine eigene Queue eingerichtet, sondern nur eine einzige Queue und die Information über die Zugehörigkeit zur Job-Queue in der Nachricht selbst abgelegt. Eine Nachricht in der Message-Queue repräsentiert ein „Runtoken“ für eine unserer Job-Queues. Die Anzahl der Runtokens einer Job-Queue definiert, wie viele Jobs, die dieser Job-Queue zugeordnet sind, gleichzeitig laufen können. Ein Job fordert nach dem Start zunächst ein „Runtoken“ der JobQueue an. Ist eins vorhanden, wird es konsumiert und am Job-Ende wieder eingestellt. Ist keins vorhanden, wartet der Job, bis ein „Runtoken“ von einem anderen Job zurückgestellt wird. Das Anfordern des Tokens erfolgt über ein PLSQL-Codestück (mit einem Dbms_aq.dequeue(WAIT)) vor der eigentlichen Verarbeitungsroutine. Aber wie stellt man sicher, dass der Job nach seinem Ende, also auch im Fehlerfall oder Abbruch durch Runterfahren der Datenbank sein Token zurückgibt? Den Ansatz mit Event-basierten Jobs, wie sie in Version 10gR2 eingeführt wurden, verwarfen wir zugunsten einer Lösung, die sich besser in unsere Architektur einpasste. Hierbei nutzt man aus, dass der DB-Scheduler die Job-Events wie JOB_SUCCEEDED, JOB_FAILED etc. auch über eine Message-Queue signalisiert. Über eine Callback-Prozedur auf dieser System-Event-Queue kann man dann in jedem Fall das Job-Ende erkennen und das vorher konsumierte „Runtoken“ wieder einstellen. Dbms_scheduler.add_event_queue_subscriber(..) Dbms_aq.register( sys.scheduler$_event_queue, 'plsql://pdv.notify?pr=1',..) Was passiert aber, wenn sehr viele Jobs in einer Job-Queue gleichzeitig gestartet werden, die Anzahl gleichzeitig laufender Jobs stark begrenzt ist? Dann würden alle Jobs erstmal starten, d.h. auch jeweils einen Prozess erzeugen, und auf Runtoken warten. Damit wäre der Server mit wartenden Jobs ausgelastet. Um die Anzahl der wartenden Jobs und damit auch der laufenden Prozesse zu minimieren, muss man sicherstellen, dass ein startender Job, der ein „Runtoken“ anfordern will auch eines erhält. Jobs starten nur, wenn sie auch aktiviert (Dbms_scheduler.enable(job)) sind. Das bedeutet, wenn man den Job-Zustand Enabled/Disabled in Verbindung setzt zur Anforderung eines Runtokens, kann man erreichen, dass nur lauffähige Jobs tatsächlich aktiv sind und einen Prozess erzeugen. Ein einfaches Beispiel soll diese Situation veranschaulichen: 100 Jobs werden gleichzeitig aufgesetzt in einer Job-Queue, die aus Performancegründen den Ablauf von maximal 10 Jobs parallel zulässt. Nach dem Erzeugen der Jobs werden anschließend aber nur 10 tatsächlich auch aktiviert, die restlichen verbleiben inaktiv. Sobald ein Job sich beendet, stellt er sein „Runtoken“ wieder in die Job-Queue und prüft die Job-Queue auf Jobs im Zustand inaktiv. Existiert ein Job, wird er aktiviert. Damit weist die Datenbank maximal 10 Prozesse für diese Job-Queue auf. Die Verarbeitung von Ereignissen – Filewatcher reloaded Das neue Oracle Scheduler-Objekt des Filewatchers wurde erst mit der Version 11gR2 eingeführt, aber die Notwendigkeit der Überwachung von Verzeichnissen bestand schon vorher. So auch in diesem Projekt, wobei es galt, den Mechanismus zur Erfassung und Verarbeitung von File-Events – ausgelöst durch einen Filewatcher – und anwendungsspezifischen Events zu vereinheitlichen. Beim „Filewatcher“ bestand zudem eine Anforderung darin, übertragene Dateien richtig zu erfassen, deren Zeitstempel weit in der Vergangenheit lag (kein „touch“ beim Transfer). Zudem sollte bei einem späteren Upgrade auf Version 11gR2 eine einfache Umstellung auf den darin enthaltenen Filewatcher möglich sein. Auch hier bot sich als Lösung an, die Mittel des Advanced Queuing zu nutzen. Das Auftreten von Events wird über Message-Queues signalisiert. Im Falle des Filewatchers wird über eine Callback-Prozedur der Message-Queue ein Verarbeitungsjob gestartet, der über die Definition des „Filewatchers“ das Programm zur Verarbeitung identifiziert. Ein Beispiel für die Verarbeitung von Ereignissen ist die Synchronisierung von komplexen JobAblauffolgen, deren Abbildung durch Oracle Job-Chains nicht oder nur aufwändig realisierbar ist. In einem einfachen Fall startet ein laufender Job einen weiteren und soll auf dessen Ende warten, bevor er seine Ausführung fortsetzt. Damit er auf das richtige Job-Ende reagieren kann, muss der aufrufende Job dem aufgerufenen mitgeben, welches Synchronisations-Event er erheben soll. Der Job-Browser als ADF Client – Umsetzung und einige Erfahrungen Neben einer einfachen API zur Implementierung und Steuerung von Jobs aus der Programmierung heraus, stand in diesem Projekt auch die Realisierung einer intuitiven, modernen und gleichsam leistungsfähigen Benutzeroberfläche im Vordergrund. Diese sollte so schwach wie möglich mit den speziellen Datenbankfunktionen des Oracle Schedulers und seinen Erweiterungen gebunden werden und so leicht austauschbar bleiben. Als Schnittstelle zur Datenbank fungiert ein View-Objekt, das alle benötigten Daten aus den speziellen SYS.DBA_SCHEULER_Views mit den Erweiterungen zusammenführt. Besonderes Augenmerk galt hier der Performance dieser Schnittstellen-View. Ein weiteres Merkmal für eine effiziente JobÜberwachung und Bearbeitung stellen Filterfunktionen auf die Schnittstellen-View dar. Die Filter werden als einfacher String in einer Datenbank-Tabelle abgelegt und können über einen Funktionsaufruf als Where-Condition vom Client-Modul direkt angewendet werden. Hierdurch lässt sich eine weitgehende Unabhängigkeit des Job-Client von komplexen Datenbankfunktionen erreichen. Als primäre Entwicklungsplattform haben wir uns für das Oracle Application Developer Framework (ADF) 11g entschieden (Rich Faces + Business Components). Ein Prototypansatz mit unterschiedlichen Technologien, wie z.B. Apex 4.0, zeigte, dass die Anforderungen, insbesondere an die hierarchische Darstellung der Jobs, mit ADF am produktivsten umsetzbar sind. Dabei profitiert man von den zahlreichen built-in -Funktionalitäten des ADF. Eine der wesentlichen Komponenten für dieses Projekt ist der sogenannte Tree-Table, da diese den Mittelpunkt der meisten Benutzer-Interaktionen darstellt. Das AD Framework bietet darüber hinaus samt der Datenbankanbindung die weitestgehende Unterstützung und die modernste Umsetzung, was sich auch in der vorgelagerten Prototyp-Phase positiv gezeigt hat. Mit ADF war es möglich ein realistisches Layoutmodell zu erstellen und anhand dessen konnten die Einzelheiten mit den Anwendern leicht abgestimmt werden. Hierdurch wurde von Anfang an eine hohe Akzeptanz erreicht. Des Weiteren kam die „User Customization“ von ADF zum Einsatz, die es ohne großen Programmieraufwand erlaubt, dass der Endanwender die Oberfläche nach seinen Bedürfnissen, z.B. welche Spalten angezeigt werden sollen, konfigurieren kann. Durch Einschalten des MDS-Repository werden die Benutzerkonfigurationen automatisch für jeden Benutzer abgelegt. Der Einsatz von „Regions“ und „Task-Flows“ erlaubt die Umsetzung eines Single-Window-Konzeptes sowie modifizierbarer Wizards für das Einplanen, Ändern und Wiederaufsetzen von Jobs. Die PL/SQL-API wurde über den im JDeveloper enthaltenden JPublisher in Java-Klassen gewandelt und in das Application-Model importiert. Eine Besonderheit liegt darin, dass vor dem Aufruf der APIFunktionen eine Proxy-Connection an die Datenbank durchgeführt wird, um die PL/SQL API unter individueller Benutzerkennung ausführen zu können. Dieses ist insbesondere beim Starten und Wiederaufsetzen von Jobs notwendig, da dieses unter eigener oder sogar unter der Benutzerkennung eines anderen Benutzers geschehen muss. Das Berechtigungskonzept der Anwendung darf in keinem Fall durch die Jobs aufgebrochen werden. Neben vielen Vorteilen zeigt auch ADF, wie jedes andere Framework, seine Schwächen. So verlässt es sich bei der Authentifikation auf den J2EE-Container, sprich dem Oracle Weblogic-Server. Dieser bietet leider keine Möglichkeit eine Authentifikation gegen die Datenbank-User durchzuführen. So muss man hier einen eigenen Login-Provider schreiben, welches schlecht dokumentiert und bei weitem komplizierter ist, als der einfache JAAS Provider, der im OC4J noch ausreichte. Viele kleine oder größere Bugs führen schnell zu länglichen Workarounds. So werden z.B. Fehlermeldungen durch die Komponente, die das automatische Auffrischen der Anzeige ermöglichen soll, mit dem Auffrischen ebenfalls automatisch geschlossen. Die Lösung, die dem Entwickler hier bleibt, ist ein tiefgreifender Eingriff in das vorhandene ADF-Messaging-Konzept. Ein weiteres Beispiel ist die mit Version 11.1.1.3 hinzugekommene Funktion einen „Task-Flow“ als Popup zu definieren, welches den in vorherigen Versionen mühsamen Umweg über die Verwendung von dynamische Regionen und entsprechenden Managed Beans erheblich vereinfacht. Leider führt dieses neue Konzept zu einer spontanen und anhaltenden 100% -igen CPU-Auslastung des WeblogicServers, so dass wir auch hier wieder auf die „herkömmliche“ Art der Implementierung ausweichen mussten. Dieses sind nur einige wenige Beispiele, die den ansonsten positiven Eindruck etwas trüben. Oracle sei angeraten, sich in den nächsten Versionen dringend vermehrt dem Bug-Fixing zu widmen. Abb. 4: Jobmonitor der geplanten und ausgeführten Jobs in einer hierarchischen Darstellung Als Ergebnis bewährt sich der ADF-Job-Browser als performantes Arbeitswerkzeug, mit dem ein schnelles und übersichtliches Arbeiten ermöglicht wird und eine hohe Benutzerakzeptanz erreicht wird. Das vorgestellte Schnittestellenkonzept erlaubt aber auch eine Erstellung des Jobs-Browsers auf einer anderen technologischen Basis, wie APEX, .NET, u.a. wenn dieses in einem speziellen Projektumfeld notwendig oder gewünscht wird. Kontaktadresse: Dr. Peter Hawelka pdv Technische Automation + Systeme GmbH Dorotheenstraße, 64 D-22301 Hamburg Telefon: Fax: E-Mail Internet: +49 (0) 40 69213-266 +49 (0) 40 69213-278 [email protected] www.pdv-tas.de