Patroon Aggregatie van gateway

Een gateway gebruiken om verschillende afzonderlijke aanvragen samen te voegen in één aanvraag. Dit patroon is handig wanneer een client meerdere aanroepen naar verschillende back-endsystemen nodig heeft om een bewerking uit te voeren.

Context en probleem

Voor het uitvoeren van een enkele taak heeft een client wellicht meerdere aanroepen naar verschillende back-endservices nodig. Een toepassing die van veel services afhankelijk is om een taak uit te voeren moet bij elke aanvraag resources verbruiken. Wanneer er een nieuwe functie of service aan de toepassing wordt toegevoegd, zijn extra aanvragen nodig, wat leidt tot hogere resourcevereisten en meer netwerkaanroepen. Deze communicatievereisten tussen een client en een back-end kunnen een negatieve invloed hebben op de prestaties en schaal van de toepassing. Microservice-architecturen hebben ertoe geleid dat dit probleem vaker voorkomt, omdat toepassingen die op veel kleinere services zijn gebaseerd van nature meer aanroepen naar verschillende services genereren.

In het volgende diagram verzendt de client aanvragen naar elke service (1,2,3). Elke service verwerkt de aanvraag en stuurt de reactie terug naar de toepassing (4,5,6). Het op deze manier gebruiken van afzonderlijke aanvragen via een mobiel netwerk met hoge latentie is inefficiënt en kan leiden tot verbroken connectiviteit of onvolledige aanvragen. Hoewel elke aanvraag gelijktijdig kan worden uitgevoerd, moet de toepassing gegevens voor elke aanvraag verzenden, wachten op een reactie en de gegevens verwerken, en dat allemaal op afzonderlijke verbindingen, waardoor de kans op fouten wordt vergroot.

Probleemdiagram voor het aggregatiepatroon van de gateway

Oplossing

Gebruik een gateway om de communicatiemogelijkheden tussen de client en de services te verminderen. De gateway ontvangt clientaanvragen, verzendt aanvragen naar de verschillende back-endsystemen, combineert de resultaten en stuurt deze dan terug naar de aanvragende client.

Dit patroon kan het aantal aanvragen van de toepassing naar back-endservices verminderen en de prestaties van toepassingen via netwerken met hoge latentie verbeteren.

In het volgende diagram verzendt de toepassing een aanvraag naar de gateway (1). De aanvraag bevat een pakket aanvullende aanvragen. De gateway scheidt deze van elkaar en verwerkt elke aanvraag door deze naar de relevante service te verzenden (2). Elke service retourneert een antwoord naar de gateway (3). De gateway combineert de antwoorden van elke service en stuurt het antwoord naar de toepassing (4). De toepassing maakt één enkele aanvraag en ontvangt slechts één antwoord van de gateway.

Oplossingsdiagram voor het gatewayaggregatiepatroon

Problemen en overwegingen

  • De gateway mag geen koppeling van services tussen back-endservices inschakelen.
  • De gateway moet zich in de buurt van de back-endservices bevinden om latentie zo veel mogelijk te verminderen.
  • De gatewayservice kan een Single Point of Failure genereren. Zorg ervoor dat de gateway goed is ontworpen om te voldoen aan de beschikbaarheidsvereisten van uw toepassing.
  • De gateway kan een knelpunt genereren. Zorg ervoor dat de gateway voldoende capaciteit heeft om de workload te verwerken en kan worden geschaald met het oog op de door u verwachte groei.
  • Voer belastingtests uit op de gateway zodat er geen trapsgewijze fouten voor services optreden.
  • Implementeer een robuust ontwerp met behulp van technieken zoals bulkheads, uitschakeling van circuits, nieuwe pogingen en time-outs.
  • Als een of meer service-aanroepen te lang duren, is het wellicht mogelijk een gedeeltelijke set gegevens tijdelijk uit te schakelen en te retourneren. Bekijk hoe uw toepassing met dit scenario omgaat.
  • Gebruik asynchrone I/O om ervoor te zorgen dat een vertraging bij de back-end niet leidt tot prestatieproblemen in de toepassing.
  • Implementeer gedistribueerde tracering met behulp van correlatie-id's om elke afzonderlijke aanroep te volgen.
  • Controleer aanvraaggegevens en de grootte van reacties.
  • Overweeg het retourneren van gegevens in de cache als failoverstrategie voor het afhandelen van fouten.
  • U zou een verzamelingsservice achter de gateway kunnen implementeren in plaats van aggregatie in te bouwen in de gateway. Aggregatie van aanvragen heeft waarschijnlijk andere resourcevereisten dan andere services in de gateway en is mogelijk van invloed op de routering en offloading van de gateway.

Wanneer dit patroon gebruiken

Gebruik dit patroon wanneer:

  • Een client moet communiceren met meerdere back-endservices om een bewerking uit te voeren.
  • De client kan gebruikmaken van netwerken met aanzienlijke latentie, zoals mobiele netwerken.

Dit patroon is mogelijk niet geschikt in de volgende gevallen:

  • U het aantal aanroepen tussen een client en een enkele service via meerdere bewerkingen wilt reduceren. In dit scenario is het wellicht beter om een batchbewerking aan de service toe te voegen.
  • De client of de toepassing bevindt zich in de buurt van de back-endservices en latentie is geen belangrijke factor.

Voorbeeld

Het volgende voorbeeld laat zien hoe u een eenvoudige NGINX-service voor gateway-aggregatie kunt maken met behulp van Lua.

worker_processes  4;

events {
  worker_connections 1024;
}

http {
  server {
    listen 80;

    location = /batch {
      content_by_lua '
        ngx.req.read_body()

        -- read json body content
        local cjson = require "cjson"
        local batch = cjson.decode(ngx.req.get_body_data())["batch"]

        -- create capture_multi table
        local requests = {}
        for i, item in ipairs(batch) do
          table.insert(requests, {item.relative_url, { method = ngx.HTTP_GET}})
        end

        -- execute batch requests in parallel
        local results = {}
        local resps = { ngx.location.capture_multi(requests) }
        for i, res in ipairs(resps) do
          table.insert(results, {status = res.status, body = cjson.decode(res.body), header = res.header})
        end

        ngx.say(cjson.encode({results = results}))
      ';
    }

    location = /service1 {
      default_type application/json;
      echo '{"attr1":"val1"}';
    }

    location = /service2 {
      default_type application/json;
      echo '{"attr2":"val2"}';
    }
  }
}