Beeklaan 444 2562 BK Den Haag www.darwin-it.nl
[email protected] KvK 27283780 ING 65.35.40.663
Mar tien van den Akker Technical Architect
Ban de batch Java-projecten beginnen bij Oracle eindelijk wat te worden met JDeveloper en ADF. Toch is Designer/Developer volgens de Rad-race van een paar jaar geleden nog het meest productief. Ook SOA en integratie-projecten komen nu eindelijk van de grond. Toch worden er nog volop batches geprogrammeerd: zowel in onderhoudstrajecten als in nieuwbouw. Waarom? Bij veel integratie- en performance-trajecten kom ik batches tegen. Veel van de gegevens worden niet real-time, maar batch-gewijs met behulp van bestanden uitgewisseld. Vaak zie je dat in de loop van de dag mutaties in een interface bestand worden gelogd die 's nachts worden verwerkt. Dan moet voor alle niet verwerkte records alle bijbehorende gegevens bij elkaar geselecteerd worden en verwerkt, wat behoorlijk wat performance kan kosten. Nog vervelender wordt het als er direct op het datamodel alle gemuteerde gegevens na de laatste batch run bij elkaar worden geraapt. Zelden wordt de wens gesignaleerd of de noodzaak ervaren om dit dan real-time te gaan doen. Waarom zou je InterConnect of BPEL PM gebruiken terwijl de gegevens in de doel-applicatie niet direct nodig zijn? Waarom InterConnect en niet SQL*Loader? Organisaties denken vaak heel conventioneel en batch gewijs, totdat het nacht-window vol zit. Eind 2003 was ik bij een architectuur-sessie bij een klant en zij hadden enorm veel nachtelijke batches (rond de 90 meen ik). Dit werd (terecht) als een probleem ervaren. Een andere reden waarom voor batches wordt gekozen, is de schijnbare zekerheid dat er toch nooit meer dan drie interfaces nodig zullen zijn. Als na die batch interfaces ineens toch een vierde of vijfde nodig is dan kijk je niet zo gauw om naar InterConnect. Daarbij wordt er vaak aan het eind van het project over batches nagedacht of als een separaat traject. Terwijl dit misschien meer geïntegreerd moet worden in de basisfunctionaliteit. Hieronder volgt een aantal afwegingen om het toch anders te doen.
Stel niet uit... Het is zo'n wc-tegeltjestekst: "Stel niet uit tot morgen wat je vandaag kunt doen". Maar veel organisaties maken er van "Stel uit tot vannacht, wat je niet meteen hoeft te doen". Je kan er wat mij betreft ook van maken: "als we de gegevens realtime oversturen, hoeven we het niet 's nachts in een batch te doen". Ik denk dat voor integratie geldt: dat wat je direct kunt doen, kun je ook beter direct doen. Op het moment dat de mutatie wordt gedaan, heb je alle te versturen gegegevens bij elkaar. Het belangrijkste gegeven daarbij is de primary-key van de te versturen tupel. Je hoeft niet uit te zoeken welk record je moet versturen: op dat moment weet je het nog. Dat is een belangrijk gegeven dat eigenlijk 'bewust vergeten' wordt. En 's avonds in de batch moet je dan gaan uitzoeken: "oh ja, welke mutaties zijn er nu ook al weer gedaan en moet ik verwerken?".
Als de ontvangende partij de gegevens niet real-time kan verwerken, dan kun je de gegevens natuurlijk nog steeds real-time versturen en aan de andere kant opvangen in een schaduwtabel. Dan hoef je die alleen maar leeg te lezen en is de versturende partij er in elk geval van af. Dat deden we bijvoorbeeld bij een thuiszorg organisatie. Een aantal applicaties daar deed alleen aan volledige imports. Dus verstuurden we real-time de gegevens met InterConnect naar een jdbc-adapter, die de mutaties in een staging-tabel plaatst. Vanuit die staging-tabel verplaatsen we elk record op basis van een Unique Key meteen naar een schaduwtabel. Die schaduwtabel omvat dan alle voor die applicatie in aanmerking komende records met de laatste gegevens. Vervolgens hoeft er alleen maar een dump van die tabel gemaakt te worden om die vervolgens in te lezen in de applicatie. Alle benodigde gegevens staan dan al in het juiste formaat bij elkaar.
Loskoppeling InterConnect zorgt bij dit soort toepassingen ook voor los-koppeling/abstractie. De bron-applicatie hoeft geen weet te hebben van doel-applicaties waar de informatie naar toe moet. Je zou ook kunnen zeggen dat de bron-applicatie niet wordt belast door de informatie-behoefte van een doelapplicatie. De bron-applicatie levert de mutatie in zijn eigen formaat met alle beschikbare gegevens aan. Transfomaties naar het formaat van de doelapplicaties kun je in de Hub doen en je kunt meerdere applicaties op dezelfde events abonneren. Dat scheelt je in onderhoud op de interfaces en het houdt de bron-applicaties schoon en eenduidig. Dat wil zeggen: geen vervuiling door functionaliteit die niet in het belang van de bron-applicatie is. Het biedt daarbij ook de mogelijkheid geleidelijk applicaties te vervangen. Immers, als je een nieuw systeem module voor module implementeert, wil je deel-functionaliteit geleidelijk vervangen. Door de abstractie worden de afhankelijkheden weggenomen en hoef je niet een interface compleet opnieuw te bouwen. Je hoeft feitelijk alleen een nieuwe koppeling tussen de nieuwe module en InterConnect te bouwen. Voor een verdere loskoppeling kun je ook nog naar Oracle Workflow grijpen. Daarin zit het zogenaamde Business Event System (BES). Dat is een slimme gebeurtenis-georienteerde architectuur gebaseerd op Advanced Queuing. In HTML schermen kun je events definieren en daarop workflowprocessen en/of PL/SQL-functies abonneren. Dit is allemaal heel declaratief. Je kunt meerdere subscripties definieren op een event en de volgorde van uitvoer daarvan opgeven. Ook kun je events propageren naar andere systemen. Dit klinkt heel simpel en dat is het ook. Mocht je om voorbeelden verlegen zitten, neem dan maar contact met me op. Als je de events hebt gedefinieerd, moet je alleen op de juiste momenten in je applicatie dat event 'raisen'. Daarvoor bestaan Java en PL/SQL APIs. Je geeft daarbij het ID van de betreffende tupel mee en in het workflow-proces of de PL/SQL-functie doe je de verwerking voor dat ID. Die functie wordt door de Workflow listeners uitgevoerd in de achtergrond (database job-scheduler), dus je applicatie en/of de eind-gebruiker merkt daar niets of nauwelijks wat van. De E-Business Suite maakt hier ook gebruik van. Op alle mutatie-momenten wordt een overeenkomstig event ge-'raise'-d. Je hoeft jou eigen code daar alleen maar op te abonneren. Hierdoor zijn triggers op de Apps-tabellen niet meer
nodig. Misschien is het bijvoorbeeld in een CDM-Ruleframe project een idee om op werkelijk elke create en update event een overeenkomstig Business-event te raisen. Abonneer daar een default null-functie op en je hebt met weinig inspanning een hook voor elk denkbare functionaliteit die je daar zonder wijziging van je Business Rules declaratief op kunt abonneren. Alle controle-business-rules bouw je in als echte CDM-Ruleframe rules, maar elke externe verwerking die op zo'n event moet worden uitgevoerd, laat je door BES uitvoeren. In een ontwikkeltraject heeft dat als belangrijk voordeel dat als die externe verwerking 'invalid' raakt, dan heeft dat geen gevolgen voor de applicatie zelf.
Maar het gaat toch om heel, heel veel rijen Als het echter gaat om dagelijks milioenen rijen, dan zou je eens naar Oracle Warehouse Builder kunnen kijken. Dat is oorspronkelijk bedoeld voor ETL (Extract Transform Load)/DWH (Data warehousing), maar kan ook prachtig voor batch-interfaces en migraties gebruikt worden. In OWB kun je de bron van je data definiëren, transformaties definiëren en het doel-datamodel aangeven. Vervolgens genereert OWB de optimale code voor het hele gebeuren. En dit kun je gepland laten uitvoeren. Warehouse builder heeft zelfs Workflow-integratie: het kan workflow-processen genereren die de transformaties in de juiste volgorde uit kan voeren.
Batch processen in Workflow Batch-processen zijn op zich nog niet zo heel erg. Soms zijn ze zelfs noodzakelijk. Als bijvoorbeeld een loterij-trekking wordt gedaan, dan kan dat pas na de sluitingstermijn en gaat dat over alle tot dan toe verkochte loten. Een lot wordt pas na de verkoop-sluiting in de trekking opgenomen. Batches worden echter heel vaak compleet uitgeprogrammeerd in grote lappen code. En die moeten dan sequentieel worden uitgevoerd. Vaak worden ze dan met SQL*Plus-scripts aangeroepen. Logging is daarbij een crime of er is enorm veel geïnvesteerd in een ingenieus logging-systeem. Maar ook herstartbaarheid is vaak ver te zoeken. Als een batch programma stuk loopt na 4 uur draaien, dan heb je een leuke uitdaging in een batchwindow van 8 uur. SQL*Plus is nou ook niet zo'n heel briljante tool om stabiel productieprocessen te ondersteunen, als je het mij vraagt. Als er maar iets fout gaat, gooit SQL*Plus de handen in de lucht en weg is-ie. Heb je afhankelijkheden tussen interface-batch-onderdelen, kun je onderdelen onderkennen die parallel kunnen lopen, denk dan ook eens aan Oracle Workflow. Daar kun je delen die parallel kunnen lopen of die pas kunnen lopen als een ander deel succesvol heeft gelopen mooi uitmodelleren. Knip batchprocessen in compacte modules op en knoop ze middels workflowprocessen aan elkaar. Laat workflow de afhankelijkheden en de beslismomenten regelen. Door meerdere background engines in te laten lopen in de job-scheduler van de database kun je prachtig load-balancen. Sommige background engines kun je specifiek inschakkelen voor zware jobs om andere vrij te houden voor lichte delen. Hierdoor kun je batch-onderdelen die naast elkaar kunnen lopen ook als gevorkte takken uit-modelleren en vervolgens samen laten komen op het moment dat
een volgend batch-onderdeel van een of meer gevorkte processen afhankelijk van is. Je ziet dat mooi terug in het model. Verder kun je automatisch error processen af laten schieten bij het optreden van excepties. De systeembeheerder kan dan een notificatie krijgen met een linkje naar het proces dat een error heeft en specifiek onderdeel laten herstarten. De systeembeheerder krijgt het proces-model te zien met een groene lijn door alle activiteiten die succesvol zijn doorlopen en een rood-vierkant om de stukgelopen activiteit. De foutmelding kan hij opvragen, het probleem eventueel op (laten) lossen en de activiteit opnieuw laten uitvoeren, waarna het proces verder loopt. Erg handig als het midden in de nacht optreedt, drie uur voor dat het systeem weer live gebracht moet worden. Allemaal out-of-the-box. En gratis bij de database. Dat is wel wat goedkoper dan een Third-party Job Scheduler. Als je het slim opzet, kun je een zichzelf herstartend workflow-proces maken dat op het juiste tijdstip (bijvoorbeeld 's avonds om 23:00) de batch-processen start.
Conclusie Zo'n beetje het slechtste ontwerp-argument dat ik kan verzinnen is "omdat we dat altijd zo doen". Gangbare redenen om te kiezen voor batch-interfaces zijn niet altijd de meest verstandige of zijn minimaal het heroverwegen waard. Om redenen van • • • • •
performance, beperkte batch-window, onderhoudbaarheid, flexibiliteit of geleidelijke transities als applicaties in nabije toekomst worden vervangen
kan het volgens mij toch interessant zijn om batch-interfaces om te zetten naar ESB of BPEL PM. Mocht je er toch op uitkomen om batches te bouwen, dan kan Warehouse Builder of Oracle Data Integrator nog de nodige abstractie en flexibiliteit met betrekking tot transformaties bieden. En Workflow biedt de nodige functionaliteit met betrekking tot load-balancing, error-handling en herstartbaarheid. Ik denk dat er in architecturen naar gestreefd moet worden de noodzaak voor batches te minimaliseren. Als batches toch wenselijk zijn, denk dan goed na over de opzet. Zwengel de batchontwerp-discussies aan, liefst aan het begin van het project en misschien biedt dit artikel een houvast voor dit soort discussies. Dit artikel schreef ik een jaar of 4 geleden, ik dacht in 2005. Toen was InterConnect nog actueel, hadden we nog geen Oracle ESB en was de End of Lifetime van Workflow nog niet uitgesproken. De constateringen aan het begin van dit artikel gelden helaas nog steeds en de principes later gaan ook nog op. Daar waar InterConnect is genoemd zou ik nu Oracle ESB of Oracle Service Bus inzetten. Ook als het gaat om het Workflow Business Event System moet je nu denken aan een
Oracle ESB oplossing, in combinatie met Oracle Advanced Queueing en de SoaSuite AQ-Adapter. Martien van den Akker Technical Architect