Introduktion
Det visade sig att jag pĂ„ min nuvarande arbetsplats behövde bekanta mig med denna teknologi. Jag börjar med en liten bakgrund. Vid vĂ„rt senaste möte meddelade vĂ„rt team att vi behövde skapa en integration med ett vĂ€lkĂ€nt system. Med integration menas att detta vĂ€lkĂ€nda system kommer att skicka förfrĂ„gningar via HTTP till en specifik endpoint, och vi, som kanske förvĂ„nande Ă€r, skickar tillbaka svar i form av SOAP-meddelanden. Det verkar ganska enkelt och trivialt. DĂ€rför behöver viâŠ
Uppgift
Skapa 3 tjÀnster. Den första Àr en databasuppdateringstjÀnst. Denna tjÀnst, vid mottagande av nya data frÄn det externa systemet, uppdaterar informationen i databasen och genererar en fil i CSV-format för att överföra den till nÀsta system. Endpointen för den andra tjÀnsten - TransporttjÀnsten via FTP - anropas, som tar emot den överförda filen, validerar den och lÀgger den i filarkivet via FTP. Den tredje tjÀnsten - TjÀnsten för dataleverans till konsumenten - arbetar asynkront med de tvÄ första. Den tar emot en förfrÄgan frÄn det externa systemet om att fÄ den fil som nÀmndes ovan, tar den fÀrdiga svarfilen, modifierar den (uppdaterar fÀlten id, description, linkToFile) och skickar svaret som ett SOAP-meddelande. SÄ, i stort sett ser situationen ut sÄ hÀr: De tvÄ första tjÀnsterna börjar arbeta endast nÀr data för uppdatering har kommit. Den tredje tjÀnsten arbetar kontinuerligt eftersom det finns mÄnga informationskonsumenter, omkring 1000 förfrÄgningar om data per minut. TjÀnsterna Àr tillgÀngliga hela tiden och deras instanser finns i olika miljöer, sÄsom test, demo, preprod och prod. Nedan presenteras en översikt över hur dessa tjÀnster fungerar. Jag bör omedelbart pÄpeka att vissa detaljer har förenklats för att undvika onödig komplexitet.

Teknisk fördjupning
NÀr vi planerade lösningen pÄ uppgiften bestÀmde vi oss först för att utveckla applikationer i Java med hjÀlp av Spring-ramverket, en Nginx-lastbalanserare, en Postgres-databas och andra tekniska och mindre tekniska komponenter. Eftersom tiden för att utveckla den tekniska lösningen tillÀt oss att övervÀga andra angreppssÀtt, föll blicken pÄ den trendiga teknologin Apache NIFI, som Àr populÀr inom vissa kretsar. Jag vill genast nÀmna att denna teknologi gjorde att vi upptÀckte dessa tre tjÀnster. I den hÀr artikeln kommer jag att beskriva utvecklingen av en filtransporttjÀnst och en dataleveranstjÀnst till konsumenten; om artikeln uppskattas kommer jag Àven att skriva om tjÀnsten för att uppdatera data i databasen.
Vad Àr det?
NIFI Ă€r en distribuerad arkitektur för snabb parallel loading och bearbetning av data, med ett stort antal plugins för kĂ€llor och transformationer, versionhantering av konfigurationer och mycket mer. En trevlig bonus Ă€r att den Ă€r mycket enkel att anvĂ€nda. Triviala processer som getFile, sendHttpRequest och andra kan visualiseras som rutor. Varje ruta representerar en viss process, vars interaktion kan ses i bilden nedan. Mer detaljerad dokumentation om hur man konfigurerar processerna Ă€r skriven , för dem som talar ryska â . I dokumentationen beskrivs det utmĂ€rkt hur man packar upp och startar NIFI, samt hur man skapar processer, som ocksĂ„ Ă€r rutorna.
Idén att skriva artikeln föddes efter lÄngvariga sökningar och strukturerande av den erhÄllna informationen till nÄgot begripligt, samt en önskan att underlÀtta livet för framtida utvecklare.
Exempel
Ett exempel pÄ hur kvadrater interagerar med varandra har granskats. Den övergripande schemat Àr ganska enkelt: Vi fÄr en HTTP-förfrÄgan (teoretiskt med en fil i förfrÄgan. För att demonstrera NIFIs möjligheter startar förfrÄgan i detta exempel en process för att hÀmta en fil frÄn den lokala filhanteraren), dÀrefter skickar vi tillbaka ett svar om att förfrÄgan har mottagits, samtidigt som processen för att hÀmta filen frÄn filhanteraren startar och dÀrefter flyttas den via FTP. Det Àr vÀrt att pÄpeka att processerna interagerar med varandra genom sÄ kallade flowFiles. Detta Àr en grundlÀggande enhet i NIFI, som lagrar attribut och innehÄll. InnehÄllet Àr de data som representeras av flödesfilen. Med andra ord, om du har fÄtt en fil frÄn en kvadrat och överför den till en annan, kommer innehÄllet att vara din fil.

Som ni kan se av denna bild illustreras den allmÀnna processen. HandleHttpRequest tar emot förfrÄgningar, ReplaceText genererar svarets kropp, HandleHttpResponse returnerar svaret. FetchFile hÀmtar en fil frÄn filsystemet och överför den till kvadraten PutSftp, som placerar filen pÄ FTP, pÄ den angivna adressen. LÄt oss nu titta nÀrmare pÄ denna process.
I detta fall Àr request början pÄ allt. LÄt oss se pÄ dess konfigurationsparametrar.

HÀr Àr allt ganska trivialt, förutom StandartHttpContextMap - detta Àr en typ av tjÀnst som möjliggör att skicka och ta emot förfrÄgningar. Mer detaljerat och till och med med exempel kan man se -
DÀrefter kommer vi att titta pÄ konfigurationsparametrarna för ReplaceText-kvadraten. HÀr Àr det viktigt att notera ReplacementValue - det som kommer att ÄtervÀnda till anvÀndaren som ett svar. I instÀllningarna kan vi justera loggnivÄn, loggar kan ses {vart vi packade upp nifi}/nifi-1.9.2/logs, dÀr finns ocksÄ parametrarna failure/success - baserat pÄ dessa parametrar kan vi justera processen som helhet. Det vill sÀga, vid framgÄngsrik behandling av texten - kommer processen för att skicka svar till anvÀndaren att kallas, annars loggar vi helt enkelt den misslyckade processen.

I egenskaperna för HandleHttpResponse finns det inte mycket intressant förutom statusen vid framgÄngsrik skapande av ett svar.

Vi har diskuterat förfrÄgan och svaret - lÄt oss gÄ vidare till att hÀmta filen och placera den pÄ FTP-servern. FetchFile hÀmtar filen enligt den angivna sökvÀgen i instÀllningarna och överför den till nÀsta process.

Och sedan placeras filen i fillagret av rutan PutSftp. Konfigurationsparametrarna kan vi se nedan.

Det Àr vÀrt att notera att varje ruta Àr en separat process som mÄste startas. Vi har tittat pÄ det enklaste exemplet som inte krÀver nÄgon avancerad anpassning. LÄt oss nu se en nÄgot mer komplex process dÀr vi skriver lite pÄ Groovy.
Ett mer komplext exempel
TjÀnsten för att överföra data till konsumenten blev nÄgot mer komplicerad tack vare processen att modifera SOAP-meddelandet. Den övergripande processen visas i bilden nedan.

HÀr Àr idén inte sÀrskilt komplicerad heller: vi fick en förfrÄgan frÄn konsumenten om att de behövde data, vi skickade tillbaka ett svar om att vi mottagit meddelandet, startade processen för att hÀmta svaret, redigerade det med viss logik och skickade sedan filen till konsumenten i form av ett SOAP-meddelande pÄ servern.
Jag tycker inte att vi behöver beskriva de rutor vi sett ovan igen â vi gĂ„r direkt till de nya. Om du behöver redigera en fil och vanliga rutor som ReplaceText inte passar, mĂ„ste du skriva ditt eget skript. Detta kan göras med rutan ExecuteGroovyScript. InstĂ€llningarna för den presenteras nedan.

Det finns tvĂ„ alternativ för att ladda upp skriptet i denna ruta. Det första Ă€r att ladda upp en fil med skriptet. Det andra Ă€r att infoga skriptet i scriptBody. SĂ„vitt jag vet stöder rutan executeScript flera programmeringssprĂ„k â ett av dem Ă€r groovy. Jag mĂ„ste tyvĂ€rr göra java-utvecklare besvikna â man kan inte skriva skript i sĂ„dana rutor med java. För den som verkligen vill â behöver man skapa sin egen anpassade ruta och lĂ€gga till den i NIFI-systemet. Hela denna operation Ă„tföljs av ganska lĂ„ngvariga besvĂ€r, vilket vi inte kommer att ta upp i den hĂ€r artikeln. Jag valde sprĂ„ket groovy. Nedan finns en testskript som helt enkelt uppdaterar id:t i SOAP-meddelandet inkrementellt. Det Ă€r viktigt att notera. Du tar filen frĂ„n flowFile och uppdaterar den, glöm inte att lĂ€gga tillbaka den uppdaterade filen. Det Ă€r ocksĂ„ vĂ€rt att notera att inte alla bibliotek Ă€r anslutna. Det kan hĂ€nda att du Ă€ndĂ„ mĂ„ste importera ett av biblioteken. En nackdel Ă€r ocksĂ„ att det Ă€r ganska svĂ„rt att felsöka skriptet i denna ruta. Det finns ett sĂ€tt att ansluta till JVM NIFI och börja felsökningsprocessen. Personligen har jag kört en lokal applikation och imiterat att jag fĂ„r filen frĂ„n sessionen. Jag har ocksĂ„ gjort felsökning lokalt. Fel som dyker upp vid laddning av skriptet Ă€r ganska lĂ€tta att googla och skrivs av NIFI i loggen.
import org.apache.commons.io.IOUtils
import groovy.xml.XmlUtil
import java.nio.charset.*
import groovy.xml.StreamingMarkupBuilder
def flowFile = session.get()
if (!flowFile) return
try {
flowFile = session.write(flowFile, { inputStream, outputStream ->
String result = IOUtils.toString(inputStream, "UTF-8");
def recordIn = new XmlSlurper().parseText(result)
def element = recordIn.depthFirst().find {
it.name() == 'id'
}
def newId = Integer.parseInt(element.toString()) + 1
def recordOut = new XmlSlurper().parseText(result)
recordOut.Body.ClientMessage.RequestMessage.RequestContent.content.MessagePrimaryContent.ResponseBody.id = newId
def res = new StreamingMarkupBuilder().bind { mkp.yield recordOut }.toString()
outputStream.write(res.getBytes(StandardCharsets.UTF_8))
} as StreamCallback)
session.transfer(flowFile, REL_SUCCESS)
}
catch(Exception e) {
log.error("Error during processing of validate.groovy", e)
session.transfer(flowFile, REL_FAILURE)
}Egentligen slutar anpassningen av rutan hÀr. Den uppdaterade filen överförs till en ruta som ansvarar för att skicka filen till servern. Nedan finns instÀllningarna för denna ruta.

Vi beskriver metoden genom vilken SOAP-meddelandet kommer att skickas. Vi anger vart det ska skickas. DÀrefter behöver vi ange att det verkligen Àr SOAP.

Vi lÀgger till flera egenskaper sÄsom vÀrd och ÄtgÀrd (soapAction). Vi sparar och kontrollerar. Mer detaljerat om hur man skickar SOAP-förfrÄgningar kan man se
Vi har undersökt flera anvĂ€ndningsalternativ för NIFI-processer. Hur de interagerar och vilken verklig nytta de ger. De exempel som diskuterats Ă€r testexempel och skiljer sig nĂ„got frĂ„n det som faktiskt finns i produktion. Jag hoppas att denna artikel kommer vara lite anvĂ€ndbar för utvecklare. Tack för uppmĂ€rksamheten. Om det finns nĂ„gra frĂ„gor â skriv. Jag ska försöka svara.
KĂ€lla: habr.com
