AMQP

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 17 juni 2020; kontroller kräver 107 redigeringar .

AMQP (Advanced Message Queuing Protocol)  är ett öppet applikationslagerprotokoll för att skicka meddelanden mellan systemkomponenter. Huvudtanken är att enskilda delsystem (eller oberoende applikationer) kan utbyta meddelanden godtyckligt genom en AMQP-mäklare som utför routing , eventuellt garanterar leverans, distribution av dataflöden, prenumeration på önskade typer av meddelanden.

Protokollarkitekturen utvecklades av John O'Hara från JP Morgan Chase & Co [1] .

Protokoll

AMQP bygger på tre koncept:

  1. Meddelande (meddelande) - en enhet av överförd data, dess huvuddel (innehåll) tolkas inte av servern på något sätt, strukturerade rubriker kan bifogas meddelandet.
  2. Utbytespunkt - meddelanden skickas till den. Växeln distribuerar meddelanden till en eller flera köer . Samtidigt lagras inte meddelanden vid utbytespunkten. Utbytespoäng är av tre typer:
    • fanout - meddelandet överförs till alla köer som är kopplade till det;
    • direkt - meddelandet skickas till kön med ett namn som matchar routingnyckeln (routingnyckeln) (routingnyckeln anges när meddelandet skickas);
    • ämne - något mellan fanout och direkt, meddelandet skickas i köer där masken för routingnyckeln matchar till exempel app.notification.sms # - alla meddelanden som skickas med nycklar som börjar med app.notification.sms kommer att levereras till kön.
  3. Kö - meddelanden lagras här tills de hämtas av klienten. Klienten hämtar alltid meddelanden från en eller flera köer.


Protokollet kan delas in i två lager:

  1. Funktionellt lager - definierar en uppsättning kommandon som utför arbete på uppdrag av applikationen.
  2. Transport Layer - hanterar förfrågningar från applikationen till servern och servern till applikationen, hanterar kanalmultiplexering, inramning, kodning, hjärtslag, datapresentation, felhantering.


Exempel på kö:

Protokollet är inte begränsat till dessa tre typer. De ges som exempel på implementering.

Terminologi

Exchange

Tar emot meddelanden från leverantören och dirigerar dem till meddelandekön enligt fördefinierade kriterier. Sådana kriterier kallas bindningar. Utbyte är en mekanism för meddelandeförhandling och routing. Baserat på meddelandena och deras parametrar (bindningar) fattar de ett beslut om omdirigering till en kö eller annan växel. Spara inte meddelanden.

Termen utbyte betyder algoritm och algoritminstans. De säger också utbytestyp och utbytesinstans.

AMQP definierar en uppsättning standardutbytestyper. Applikationer kan skapa sin egen utbytesinstans.


Varje börs implementerar sin egen routingalgoritm. Det finns flera standardutbytestyper som beskrivs i standardens funktionsspecifikation. Av dessa är två viktiga:

Servern kommer att skapa flera utbyten, inklusive direkt och ämne. De kommer att ha välkända namn och klientapplikationer kommer att kunna arbeta med dem.

Exchange livscykel

Varje AMQP-server skapar i förväg flera instanser av utbyte. Dessa instanser finns när servern körs och kan inte förstöras. AMQP-applikationer kan också skapa sina egna börser. AMQP använder inte skapa-metoden för detta, istället deklareras instansen, vilket följer logiken: "skapa om inte skapat, fortsätt annars". Man kan säga att skapandet av utbyte är idempotent . Förmodligen kommer applikationer att skapa utbyten efter behov, och sedan förstöra dem som onödiga. AMQP tillhandahåller en metod för att förstöra utbytet.

Routing Key

I allmänhet undersöker utbytet meddelandets egenskaper, rubrikfälten och innehållet i dess kropp, och bestämmer med hjälp av dessa och eventuellt data från andra källor hur meddelandet ska dirigeras. I de flesta enkla fall överväger utbyte ett nyckelfält, som vi kallar Routing Key . Routing Key är en virtuell adress som Exchange-servern kan använda för att bestämma om ett meddelande ska skickas. För punkt-till-punkt routing är routingnyckeln vanligtvis namnet på meddelandekön. För pub-sub routing är routingnyckeln vanligtvis värdet av ämneshierarkin (ämne - se publikation/subscruber). I mer komplexa fall kan routingnyckeln kombineras med routing av meddelandehuvudfält och/eller meddelandeinnehåll.

Meddelandekö

När en klientapplikation skapar en meddelandekö kan den ange följande egenskaper:

Ett meddelandes livscykel

Ett AMQP-meddelande består av en uppsättning egenskaper och icke-offentligt innehåll. Ett nytt meddelande skapas av producenten med hjälp av AMQP klient-API. Producenten lägger till innehåll i meddelandet och ställer eventuellt in några meddelandeegenskaper. Producenten markerar meddelandet med routinginformation som ser ut som en adress, men kan vara vad som helst. Producenten skickar sedan meddelandet till utbyte . När ett meddelande kommer till servern dirigerar exchange (vanligtvis) det till en uppsättning köer som också finns på servern. Om meddelandet inte är routbart kan Exchange släppa det eller returnera det till applikationen. Producenten bestämmer hur man ska hantera meddelanden som inte kan dirigeras.

Ett meddelande kan finnas i många meddelandeköer. Servern kan hantera detta på olika sätt, som att kopiera meddelandet med referensräkning etc. Detta påverkar inte interoperabiliteten. Men när ett meddelande dirigeras till flera meddelandeköer är det identiskt i varje meddelandekö. Det finns ingen unik identifierare här för att skilja mellan olika kopior.

När ett meddelande kommer till meddelandekön försöker det omedelbart leverera det till konsumenten via AMQP. Om detta inte är möjligt lagras meddelandet i meddelandekön (i minnet eller på disk på begäran av producenten ) och väntar på att konsumenten ska vara redo. Om det inte finns någon konsument kan kön skicka ett meddelande till producenten via AMQP (igen, om producenten bett om det).

När meddelandekön kan leverera ett meddelande till konsumenten tar den bort meddelandet från dess interna lagring. Detta kan ske omedelbart eller efter att konsumenten erkänner att han har slutfört sitt jobb framgångsrikt, behandlat meddelandet. Konsumenten väljer själv hur och när meddelanden "kvitteras". konsumenten kan också avvisa meddelandet (negativ bekräftelse).

Producentmeddelanden och konsumentbekräftelser grupperas i transaktioner. När en applikation spelar båda rollerna, vilket ofta är fallet, gör den ett blandat jobb med att skicka meddelanden och skicka bekräftelser, och sedan begå eller återställa transaktionen.

Leveransen av meddelanden från servern till konsumenten är icke-transaktionell.

Producent

Producer är en klientapplikation som publicerar meddelanden för utbyte .

I analogi med e-postenheten kan man se att producenten inte skickar meddelanden direkt till kön (meddelandekö). Alla andra beteenden skulle bryta abstraktionen i AMQ-modellen. Detta skulle likna livscykeln för ett e-postmeddelande: lösa e-postmeddelandet, kringgå MTA:s routingtabeller och slå direkt i brevlådan. Detta skulle göra det omöjligt att infoga mellanliggande filtrering och bearbetning som skräppostdetektering.

AMQ-modellen använder samma princip som e-postsystemet: alla meddelanden skickas till en enda växel eller MTA , som inspekterar meddelanden baserat på regler och information som är gömd för avsändaren, och dirigerar dem till distributionspunkter som också är dolda från avsändare. (och dirigerar dem till utlämningsställen som också är dolda för avsändaren - här är distributionsställen utlämningsställen från dokumentationen).

konsument

Konsument är klientapplikationen som tar emot meddelanden från meddelandekön.

Vår e-postanalogi börjar gå sönder när vi tittar på konsumenten (mottagarna). E-postklienter är passiva - de kan läsa brevlådor, men de har ingen effekt på hur dessa brevlådor fylls i. Med AMQP kan konsumenten också vara passiv, precis som e-postklienter. Det vill säga att vi kan skriva en applikation som lyssnar på en specifik meddelandekö och helt enkelt bearbetar den inkommande informationen. I det här fallet måste meddelandekön vara klar innan applikationen startar och måste vara "bifogad" till den.

Konsumenten har också följande egenskaper:

Det är som att ha ett e-postsystem som på protokollnivå kan:

Automatiskt läge

De flesta integrationsarkitekturer behöver inte denna nivå av komplexitet. De flesta AMQP-användare behöver grundläggande funktionalitet direkt. AMQP tillhandahåller detta på följande sätt:

Som ett resultat tillåter den underliggande bindningen producenten att skicka meddelanden direkt till meddelandekön, och på så sätt emulera det enklaste schemat för att skicka ett meddelande till en mottagare som folk skulle förvänta sig av en traditionell mellanprogramvara.

Basbindningen hindrar inte användningen av meddelandekön i mer komplexa konstruktioner. Det låter dig använda AMQP utan en specifik förståelse av bindnings- och utbytesmekanismerna.

AMQP Command Architecture

Avsnittet beskriver processen för interaktion mellan applikationen och servern

Protokollkommandon (klasser och metoder)

Middleware är komplext, och när de utformade protokollstrukturen försökte dess skapare tämja denna komplexitet. Deras tillvägagångssätt var att modellera ett traditionellt API baserat på klasser som innehåller metoder, där varje metod gör exakt en sak och gör det bra. Detta resulterar i en stor uppsättning kommandon, men en som är relativt lätt att förstå.

AMQP-kommandon är grupperade i klasser. Varje klass täcker ett specifikt funktionsområde. Vissa klasser är valfria - varje peer implementerar de klasser som den måste stödja.

Det finns två olika dialogmetoder:

För att förenkla metodbearbetningen definierar vi separata svar för varje synkron begäran. Det vill säga att en metod inte används för att svara på två olika förfrågningar. Detta innebär att en peer, när den skickar en synkron förfrågan, kan acceptera och behandla inkommande metoder tills ett av de giltiga synkrona svaren tas emot. Detta skiljer AMQP från mer traditionella RPC-protokoll.

En metod definieras formellt som en synkron begäran, synkront svar (på en specifik begäran) eller asynkront. Slutligen definieras varje metod formellt som klientsida (d.v.s. server-klient) eller serversida (klient-server).

Mappa AMQP till Middleware API

AMQP är designat för att vara jämförbart med API:et för mellanprogram. Matchningsprocessen är något intellektuell, d.v.s. förstår att inte alla metoder och inte alla argument är vettiga för applikationen, men det är också mekaniskt, d.v.s. genom att sätta vissa regler kan alla metoder matchas utan manuellt ingripande.

Fördelarna med detta är att genom att lära sig semantiken i AMQP, kommer utvecklare att hitta samma semantik som tillhandahålls i vilket ramverk de än använder.

Ett exempel på metoden Queue.Declare:

. deklarera = min . auto - radera = TRUE exklusiv = FALSK

Den kan konverteras till en nätverksram:

+--------+--------+-----------+------------+------- ----+ | | förklara | min . | 1 | 0 | +--------+--------+-----------+------------+------- ----+ klass metodnamn auto - radera exklusiv _

Eller i en API-metod på hög nivå

. Deklarera ( "my.queue" , ​​TRUE , FALSE );

Asynkron metodmatchningslogik i pseudokod:

skicka metod till servern

Synkron metodmatchningslogik i pseudokod:

skicka begäran till servern _ upprepa vänta svar från servern om respons är en asynkron metod processmetod ( vanligtvis , levererat eller returnerat innehåll ) _ annan hävda att metoden är ett giltigt svar begäran avsluta upprepa slut - om avsluta - upprepa

Det är värt att notera att för de flesta applikationer kan mellanprogram vara helt dold i de tekniska lagren i systemet, och att själva API:et som används är mindre viktigt än att mellanvaran är robust och funktionell.

Aviseringar saknas

Det chattiga protokollet är långsamt. Vi använder aktivt asynkron i de fall det finns ett prestandaproblem. Det är vanligtvis där vi skickar innehåll från en peer till en annan. Vi skickar metoder så snabbt som möjligt utan att vänta på bekräftelser. Vid behov implementerar vi fönster och strypning på en högre nivå, till exempel konsumentnivå.

Protokollet avstår från meddelanden, eftersom implementerar en påståendemodell för alla händelser. Antingen lyckas det eller så kastas ett undantag? som stänger en kanal eller anslutning.

Det finns inga aviseringar i AMQP. En lyckad händelse - tyst, ett misslyckande - förklarar sig själv. När en applikation behöver explicit spårning av framgångar och misslyckanden bör den använda transaktioner.

Anslutningsklass

Anslutningen är designad för att vara hållbar och hantera många kanaler.

Anslutningens livscykel
  • Klienten öppnar en TCP/IP-anslutning till servern och skickar ett protokollhuvud. Detta är den enda information som är tillgänglig för att skickas av klienten som inte är formaterad som en metod.
  • Servern svarar med en protokollversion och andra egenskaper, inklusive listan över säkerhetsmekanismer som den stöder (Startmetoden)
  • Klienten väljer en säkerhetsmekanism (Start-Ok).
  • Servern initierar en autentiseringsprocess som använder SASL- modellen , den skickar en utmaning (Secure) till klienten.
  • Klienten skickar ett autentiseringssvar (Secure-Ok). Till exempel, genom att använda den "vanliga" autentiseringsmekanismen, innehåller svaret ett användarnamn och lösenord.
  • Servern upprepar utmaningen (Secure) eller fortsätter till förhandlingar genom att skicka en uppsättning parametrar, inklusive maximal ramstorlek (Tune).
  • Klienten accepterar eller sänker dessa parametrar (Tune-Ok).
  • Klienten öppnar formellt en anslutning och väljer en virtuell värd (Öppen).
  • Servern bekräftar valet av virtuell värd (Open-Ok).
  • Nu använder klienten anslutningen som den vill.
  • En nod (klient eller server) stänger anslutningen (Stäng).
  • Den andra noden skickar data om att stänga anslutningen (Close-Ok).
  • Servern och klienten stänger de uttag som motsvarar anslutningen.

Information utbyts inte mot fel av ofullständigt öppnade anslutningar. Värden som stötte på felet bör stänga uttaget utan ytterligare meddelande.

Kanalklass

AMQP är ett flerkanalsprotokoll. Kanaler ger möjlighet att multiplexa en tung TCP/IP-anslutning till flera lätta anslutningar. Detta gör protokollet mer "brandväggsvänligt" eftersom portanvändningen är förutsägbar. Det betyder också att trafikformning och andra QoS-funktioner för nätverk enkelt kan användas.

Kanaler är oberoende av varandra och kan utföra olika funktioner samtidigt med andra kanaler, medan den tillgängliga bandbredden är uppdelad på samtidiga uppgifter.

Det förväntas och uppmuntras att flertrådiga klientapplikationer ofta använder "kanal-per-tråd"-modellen för att underlätta utvecklingen. Men att öppna flera anslutningar till en eller flera AMQP-servrar från en enda klient är också helt acceptabelt. Livscykeln för en kanal är som följer:

  • Klienten öppnar en ny kanal (Öppen)
  • Servern bekräftar öppningen av kanalen (Open-Ok)
  • Klienten och servern använder kanalen som de vill.
  • En av noderna (klient eller server) stänger kanalen (Stäng)
  • Den andra noden bekräftar kanalens stängning (Stäng-Ok)

Exchange-klassen

Tillåter en app att hantera utbytesinstanser på servern. Denna klass tillåter ett program att skriva sitt eget meddelandehanteringsskript utan att förlita sig på någon konfiguration.

Obs: De flesta applikationer behöver inte denna komplexitetsnivå, och äldre mellanprogram kommer sannolikt inte att stödja denna semantik.

Exchange livscykel
  • Klienten ber servern att se till att utbyte finns (Declare). Klienten kan specificera detta enligt följande: "skapa utbytet om det inte finns" eller "varna mig, men skapa det inte om det inte finns".
  • Klienten publicerar meddelanden att utbyta
  • Kunden kan besluta att ta bort utbytet (Ta bort)

Köklass

Köklassen tillåter en applikation att hantera meddelandeköer på en server. Detta är ett grundläggande steg i nästan alla applikationer som tar emot meddelanden, åtminstone för att verifiera att den förväntade meddelandekön faktiskt existerar.


Köns livscykel

Protokollet tillhandahåller två kölivscykler:

  • Hållbara meddelandeköer - används av flera konsumenter och existerar oavsett närvaron av konsumenter som kan ta emot meddelanden
  • Tillfälliga meddelandeköer - privata köer för en specifik konsument. Kön raderas när det inte finns några konsumenter.


Hållbar meddelandekö livscykel
  • Klienten deklarerar en meddelandekö (Deklarera med "passivt" argument)
  • Servern bekräftar att kön finns (Declare-Ok)
  • Klienten läser meddelanden från kön
Livscykel för tillfälliga meddelandeköer
  • Klienten skapar en meddelandekö (Deklarera ofta utan ett könamn, så servern ger den ett namn). Servern bekräftar skapandet (Declare-Ok)
  • Klienten initierar konsumenten för den skapade kön.
  • Klienten stoppar konsumenten antingen explicit eller genom att stänga kanalen och/eller anslutningen
  • När den sista konsumenten försvinner från meddelandekön och efter en artig timeout tar servern bort meddelandekön

AMQP implementerar ämnesprenumerationsmekanismen i form av meddelandeköer. Detta möjliggör intressanta strukturer där ett abonnemang kan lastbalanseras över en pool av samarbetande abonnentapplikationer.

Prenumerationslivscykel
  • Klienten skapar en meddelandekö (Declare), servern bekräftar (Declare-Ok)
  • Klienten matchar meddelandekön med utbytesämnet (Bind) och servern bekräftar matchningen (Bind-Ok)
  • Klienten använder meddelandekön enligt beskrivningen ovan

Grundklass

Basklassen implementerar meddelandefunktionerna som beskrivs i denna specifikation. Den stöder följande semantik:

  • Skicka meddelanden från klient till server som sker asynkront (Publicera)
  • Starta och stoppa konsumenter (konsumera, avbryta)
  • Skicka meddelanden från server till klient som sker asynkront (leverera, returnera)
  • Meddelandebekräftelse (Ack, Reject)
  • Få meddelanden från kön på ett synkront sätt (Get)

Transaktionsklass

AMQP stöder två typer av transaktioner:

  1. Automatiska transaktioner, där varje publicerat meddelande och bekräftelse behandlas som en autonom transaktion.
  2. Lokala servertransaktioner där servern buffrar publicerade meddelanden och bekräftelser och utför dem på begäran av klienten.

Klassen Transaction (“tx”) ger applikationer tillgång till den andra typen av transaktioner, lokala servertransaktioner. Klassens semantik är som följer:

  1. Applikationen begär servertransaktioner i varje kanal där den vill ta emot sådana transaktioner (Välj)
  2. Applikation som fungerar (Publicera, Ack)
  3. Applikationen utför commit- eller rollback-arbete (Commit, Roll-back)
  4. Applikationen fortsätter att fungera

Transaktioner handlar om innehållspublicering och bekräftelser, inte leverans. Därför återställer inte återställningen och utlöser återleverans. Kunden kan kvittera dessa meddelanden i nästa transaktion.

Transportarkitektur AMQP

Det här avsnittet förklarar hur kommandon mappas till protokollet på trådnivå .

Beskrivning

AMQP är ett binärt protokoll. Informationen är organiserad i ramar av olika slag. Ramar innehåller protokollmetoder och annan information. Alla ramar har samma generella format: ramhuvud, nyttolast och bildslut. Ramens nyttolastformat beror på ramtypen.

På transportnivån antas användningen av TCP / IP-stacken eller analoger.

Inom en enda uttagsanslutning kan det finnas flera oberoende kontrollflöden, så kallade kanaler. Varje bildruta är numrerad med ett kanalnummer. Genom att interfoliera sina ramar delar de olika kanalerna denna koppling. För varje given kanal exekveras ramar i en strikt sekvens som kan användas för att driva en protokollanalysator (vanligtvis en tillståndsmaskin).

Vi bygger ramar med en liten uppsättning datatyper som bitar, heltal, strängar och fälttabeller. Ramfält är tätt packade utan att göra dem långsamma eller svåra att analysera. Det är relativt enkelt att skapa ett ramlager mekaniskt från protokollspecifikationer.

Trådnivåformatering är designad för att vara skalbar och mångsidig nog att användas i godtyckliga högnivåprotokoll (inte bara AMQP). Vi räknar med att AMQP kommer att expandera, förbättra och på annat sätt förändras över tiden, och trådnivåformatet kommer att stödja detta.

Datatyper

AMQP-datatyper som används i ramar:

  • Heltal (från 1 till 8 oktetter) används för att representera storlekar, magnituder, gränser etc. Heltal är alltid osignerade och kan vara feljusterade inom en ram.
  • bitar
  • Korta strängar som används för att lagra korta textegenskaper. Korta strängar är begränsade till 255 oktetter och kan tolkas utan risk för buffertspill. (Jag misstänker att vi talar om en oktett i 255 tillstånd och inte om 255 oktetter)
  • Långa strängar som används för att lagra delar av binär data
  • Tabellfält som innehåller namn-värdepar. Fältvärden skrivs in som strängar, heltal, etc.

Protokollförhandling

Klienten och servern förhandlar fram ett protokoll. Detta innebär att när en klient ansluter erbjuder servern vissa alternativ som klienten kan acceptera eller ändra. När båda är överens om resultatet anses kopplingen upprättad. Förhandling är användbart eftersom det låter dig ställa in anslutningsförinställningar.

Samordning sker på ett antal aspekter:

  • Det aktuella protokollet och dess version. En server KAN hantera flera protokoll på en enda port.
  • Krypteringsargument och autentisering av båda sidor. Det är en del av det funktionella lagret i protokollet.
  • Maximal ramstorlek, antal kanaler och andra operativa begränsningar

Överenskomna gränser kan tillåta båda parter att i förväg tilldela nyckelbuffertar, vilket undviker dödläge. Varje inkommande ram följer antingen de förhandlade gränserna och är därför säker, eller överskrider dem, i vilket fall den andra sidan har misslyckats och måste inaktiveras. Detta stämmer mycket väl överens med AMQP:s filosofi om "det fungerar antingen som det ska eller så fungerar det inte alls".

Båda noderna förhandlar gränser till det lägsta överenskomna värdet enligt följande:

  • Servern MÅSTE tala om för klienten vilka gränser den erbjuder.
  • Klienten svarar och KAN minska anslutningsgränserna

Ramavgränsning

TCP/IP-stack - fungerar med strömmar, den har ingen inbyggd ramavgränsningsmekanism. Befintliga protokoll löser detta problem på flera olika sätt:

  • Skickar en ram per anslutning. Det är enkelt men långsamt
  • Lägga till en ramavgränsare till en ström. Det är enkelt men gör analysen långsam
  • Räkna ramstorlek och skicka storlek före varje ram. Det är enkelt och snabbt, och detta tillvägagångssätt är implementerat i AMQP.


Bildad i detalj

Alla ramar består av en rubrik (7 oktetter), en godtycklig nyttolast och en "end of frame"-oktett som upptäcker felaktiga ramar:

0 1 3 7 storlek + 7 storlek + 8 +------+--------+-------------+ +-----------+ +--- --------+ | typ | kanal | storlek | | nyttolast | | ram - slut | +------+--------+-------------+ +-----------+ +--- --------+ oktett kort lång storlek oktetter oktett

Ramen läses så här:

  1. Läs rubrik och kontrollera ramtyp och kanal
  2. Beroende på typen av ram läses data från nyttolasten och bearbetas
  3. Läsramslut.

I realistiska implementeringar när det gäller prestanda kommer vi att använda "read-ahead buffering" eller "gathering reads" för att undvika att göra tre separata systemanrop för att läsa en ram.

Metodramar

Metodramar bär protokollkommandon på hög nivå (som vi kallar "metoder"). En metodram innehåller en instruktion. Metodens nyttolast har följande format:

0 2 4 +----------+------------+-------------- - - | klass - id | metod - id | argument ... +----------+------------+-------------- - - kort kort ...

Metodramen hanteras så här:

1. Läsa nyttolastmetodens ram.

2. Dess uppackning i en struktur. Denna metod har alltid samma struktur, så du kan snabbt packa upp den

3. Kontrollera att denna metod är tillåten i det aktuella sammanhanget.

4. Kontrollera att metodargumenten är giltiga.

5. Utförande av denna metod.

Metodens ramkropp är konstruerad som en lista med AMQP-datafält (bitar, heltal, strängar och strängtabeller). Rangeringskoden genereras trivialt direkt från protokollspecifikationer och kan vara mycket snabb.

Innehållsramar

Innehåll är applikationsdata som vi överför från klient till klient via AMQP-servern. Innehållet är, grovt sett, en uppsättning egenskaper plus en binär del av datan. Uppsättningen av tillåtna egenskaper definieras av basklassen, och de bildar "innehållsrubrikramen". Data kan vara av vilken storlek som helst och delas upp i flera (eller många) block, som vart och ett bildar ett "innehållskroppsskelett".

Om vi ​​tittar på ramarna för en viss kanal när den sänds över tråden, kan vi se något i stil med detta:

[ metod ] [ metod ] [ header ] [ body ] [ body [ metod ] ...

Vissa metoder (som Basic.Publish , Basic.Deliver , etc.) definieras formellt som innehållsbärande. När en peer skickar en sådan metodram, följer den alltid den med en innehållsrubrik och med eller utan några innehållskroppsramar. Innehållsramhuvudet har följande format:

0 2 4 12 14 +----------+--------+-----------+----------------+ ------------- - - | klass - id | vikt | kroppsstorlek | _ egendomsflaggor | _ fastighetslista ... _ +----------+--------+-----------+----------------+ ------------- - - kort kort lång lång kort återstod ...

Vi placerar innehållskroppen i separata ramar (snarare än att inkludera den i en metod) så att AMQP kan stödja "nollkopiering"-metoder där innehållet aldrig raderas eller kodas. Vi lägger innehållsegenskaper i sin egen ram så att mottagarna selektivt kan kassera innehåll de inte vill bearbeta.

Heartbeat Frames

Heartbeat är en teknik designad för att åsidosätta en av funktionerna i TCP/IP, nämligen dess förmåga att återhämta sig från en bruten fysisk anslutning, först efter en ganska lång timeout. I vissa scenarier behöver vi veta mycket snabbt om peeren är nere eller inte svarar av andra anledningar (till exempel fastnar den i en loop). Eftersom hjärtslag kan göras på en låg nivå kommer vi att implementera detta som en speciell typ av ram som byts ut mellan noder i transportlagret, snarare än som en klassmetod.

Felhantering

AMQP använder undantag för felhantering. Alla operativa fel (meddelandekö hittades inte, otillräckliga åtkomsträttigheter, etc.) kommer att utlösa ett kanalundantag. Alla strukturella fel (dåligt argument, dålig metodsekvens, etc.) resulterar i ett anslutningsundantag. Undantaget stänger kanalen eller anslutningen och returnerar en svarskod och svarskropp till klientapplikationen. Vi använder en 3-siffrig svarskod plus svarstexttextschemat som används i HTTP och många andra protokoll.


Stänga kanaler och anslutningar

Anslutningen eller kanalen sägs vara "öppen" för klienten när den skickar ett Open, och för servern när den skickar ett Open-Ok. Från och med nu måste en peer som vill stänga en kanal eller anslutning göra det med hjälp av handskakningsprotokollet, som beskrivs här.

Att stänga en kanal eller anslutning av någon anledning - normal eller exceptionell - måste göras försiktigt. Plötsliga stängningar upptäcks inte alltid snabbt, och efter ett undantag kan vi förlora felsvarskoder. Den korrekta designen är att manuellt förhandla om stängningen så att kanalen/anslutningen stängs först efter att vi är säkra på att den andra sidan är medveten om situationen.

När en peer bestämmer sig för att stänga en kanal eller anslutning skickar den stängningsmetoden. Den mottagande noden måste svara på stängningen med ett Close-Ok, och sedan kan båda sidor stänga sin kanal eller anslutning. Observera att om peers ignorerar Close, kan ett dödläge uppstå om båda peers skickar Close samtidigt.


AMQP Client Architecture

Det är möjligt att läsa och skriva AMQP-ramar direkt från applikationen, men det skulle vara dålig design. Även den enklaste AMQP-konversationen är mycket mer komplex än till exempel HTTP, och applikationsutvecklare behöver inte förstå saker som binära ramformat för att skicka ett meddelande till en meddelandekö. Den rekommenderade AMQP-klientarkitekturen består av flera abstraktionsnivåer:

  1. Fraiming Layer - tar AMQP-protokollmetoder i något språkformat (strukturer, klasser, etc.) och serialiserar dem som ramar på trådnivå. Ramskiktet kan genereras mekaniskt från AMQP-specifikationer (som är definierade i ett protokollmodelleringsspråk, implementerat i XML och specifikt designat för AMQP).
  2. anslutningshanterarskikt - läser och skriver AMQP-ramar och hanterar den övergripande anslutnings- och sessionslogiken. I detta lager kan vi kapsla in hela logiken för att öppna en anslutning och session, felhantering, skicka och ta emot innehåll och så vidare. Stora delar av detta lager kan göras automatiskt från AMQP-specifikationer. Till exempel definierar specifikationer vilka metoder som bär innehåll, så logiken "skicka en metod och sedan valfritt skicka innehåll" kan skapas mekaniskt.
  3. API Layer - tillhandahåller ett specifikt API för att arbeta med applikationer. API-lagret kan återspegla någon befintlig standard, eller så kan det tillhandahålla AMQP-metoder på högre nivå genom att skapa en mappning som beskrivits tidigare. AMQP-metoderna är utformade för att göra denna kartläggning enkel och användbar. Själva API-lagret kan bestå av flera lager, till exempel en högre nivå API byggd ovanpå AMQP Method API.

Dessutom finns det vanligtvis någon nivå av I/O, som kan vara mycket enkel (Synchronous socket read and write) eller komplex (helt asynkron flertrådad I/O). Detta diagram visar den allmänna rekommenderade arkitekturen:

+------------------------+ | ansökan | +-----------+-------------+ | +------------------------+ +---| API -lager |---- Klient- API -lager -----+ | +-----------+------------+ | | | | | +------------------------------+ +----------------+ | | | Anslutningshanterare + ----+ Framing Layer | | | +-----------+------------+ +-------+ | | | | | +------------------------------+ | +---| Asynkront I / O -lager |------------------------+ +-----------+-------------+ | ------- - - - - Nätverk - - - - -------

När vi i det här dokumentet talar om "klient-API" menar vi alla lager under applikationen (i/o, framing, anslutningshanterare och API-lager. Vi brukar tala om "klient-API" och "applikation" som två separata saker där applikationen använder klient-API:et för att prata med mellanprogramservern.

Funktionsspecifikation

Serverfunktionsspecifikation

Meddelanden och innehåll

Ett meddelande är den atomära bearbetningsenheten i ett routing- och middleware-kösystem. Meddelanden innehåller innehåll som består av en innehållsrubrik som innehåller en uppsättning egenskaper och en innehållskropp som innehåller ett ogenomskinligt block med binär data.

Ett meddelande kan motsvara många olika applikationsenheter:

  • Programlagermeddelande
  • Skickar fil
  • dataströmsram

Meddelanden kan vara permanenta. Ett beständigt meddelande lagras säkert på disken och levereras garanterat även vid ett större nätverksavbrott, serverfel, spill osv.

Meddelanden kan ha företräde. Ett meddelande med hög prioritet skickas före meddelanden med lägre prioritet som väntar i samma meddelandekö. När meddelanden behöver släppas för att bibehålla en viss servicekvalitet, kommer servern först att släppa meddelanden med låg prioritet.

Servern FÅR INTE ändra innehållet i meddelanden som den tar emot och skickar till konsumentapplikationer. Servern KAN lägga till information till innehållsrubriker, men den FÅR INTE ta bort eller ändra befintlig information.

Virtuella värdar

En virtuell värd är en del av data på en server, en administrativ bekvämlighet som kommer att visa sig användbar för dem som vill tillhandahålla AMQP som en tjänst på en delad infrastruktur.

Den virtuella värden innehåller sitt eget namnområde, uppsättning utbyten, meddelandeköer och alla relaterade objekt. Varje anslutning måste vara associerad med en virtuell värd.

Klienten väljer den virtuella värden i metoden Connection.Open efter autentisering. Detta innebär att serverns autentiseringsschema är gemensamt för alla virtuella noder på den servern. Det auktoriseringsschema som används kan dock vara unikt för varje virtuell värd. Detta bör vara användbart för en delad värdinfrastruktur. Administratörer som kräver olika autentiseringsscheman för varje virtuell värd måste använda separata servrar

Alla kanaler inom en anslutning fungerar med samma virtuella värd. Det finns inget sätt att kontakta en annan virtuell värd på samma anslutning, och det finns inget sätt att byta till en annan virtuell värd utan att tappa anslutningen och börja om.

Protokollet erbjuder inga mekanismer för att skapa eller konfigurera virtuella värdar - detta görs på ett ospecificerat sätt inom servern och är helt implementeringsberoende.

Utbyten

Exchange är en meddelandedirigeringsagent inuti en virtuell värd. Exchange-instansen (som vi vanligtvis refererar till som en "exchange") tar emot meddelanden och routinginformation - främst routingnyckeln - och skickar antingen meddelandena till meddelandeköer eller till interna tjänster. Utbytena namnges på en per virtuell värdbasis.

Applikationer är fria att skapa, dela och förstöra utbytesinstanser inom deras behörighet.

Utbyten kan vara permanenta, tillfälliga eller automatiskt raderade. Permanenta utbyten finns tills de tas bort. Tillfälliga utbyten existerar tills servern stängs av. Automatiskt borttagna utbyten finns tills de inte längre används.

Servern tillhandahåller en specifik uppsättning utbytestyper. Varje utbytestyp implementerar en specifik mappning och algoritm, som definieras i nästa avsnitt. AMQP föreskriver ett litet antal bytestyper och rekommenderar några fler. Dessutom kan varje serverimplementering lägga till sina egna utbytestyper.

En växel kan dirigera ett enda meddelande till flera meddelandeköer parallellt. Detta skapar flera meddelandeinstanser som konsumeras oberoende av varandra.

Direktbytestypen

direktbytestyp fungerar så här:

  1. Meddelandekön mappas till utbytesservern med hjälp av routingnyckeln K.
  2. Utgivaren skickar ett utbytesmeddelande med routingnyckeln R.
  3. Meddelandet skickas till meddelandekön om K = R.

Servern MÅSTE implementera en direkt echange och MÅSTE fördefiniera i varje virtuell värd minst två direkta växlar: en som heter amqp.direct och en utan ett publikt namn som fungerar som standardväxel för att hantera offentliga metoder.

Observera att meddelandeköer kan kontaktas med vilket giltigt routingnyckelvärde som helst, men oftast kommer meddelandeköer att kontaktas med sitt eget namn som routingnyckel.

I synnerhet SKA alla meddelandeköer automatiskt bindas till en växel utan ett offentligt namn, med användning av meddelandekönamnet som routingnyckel.

Fanout Exchange Type

Fanout Exchange fungerar så här:

  1. Meddelandekön är bunden till utbytesservern utan några argument.
  2. utgivare skickar ett meddelande att utbyta.
  3. Meddelandet skickas till meddelandekön utan villkor.

Fanout Exchange är trivialt att designa och implementera. Denna typ av utbyte, och det fördeklarerade namnet amq.fanout , krävs.

Ämnesbytestypen

Ämnesutbyte fungerar så här:

  1. Meddelandekön är bunden till utbytesservern med hjälp av P-routningsmönstret.
  2. Utgivaren skickar ett utbytesmeddelande med routingnyckeln R.
  3. Meddelandet skickas till meddelandekön om R matchar P.

Routingnyckeln som används för ämnesutbyte måste bestå av ord separerade med punkter. Minsta ordstorlek är 0 tecken. Varje ord kan innehålla bokstäverna AZ och az, samt siffrorna 0-9.

Routningsmönstret följer samma regler som routingnyckeln, med tillägget att * matchar ett ord och # matchar noll eller fler ord. Således matchar routningsschemat *.stock.# routingnycklarna usd.stock och eur.stock.db, men inte stock.nasdaq.

Ett föreslaget schema för Topic Exchange är att behålla en uppsättning av alla kända routingnycklar och uppdatera den när utgivare använder nya routingnycklar. Du kan definiera alla bindningar för en given routingnyckel och på så sätt snabbt hitta meddelandeköerna för ett meddelande. Denna typ av utbyte är valfritt.

Servern måste implementera ämnesutbytestypen, i vilket fall servern först måste deklarera minst ett ämnesutbyte med namnet amq.topic i varje virtuell värd.

Typen Headers Exchange

header exchange-typ fungerar så här:

  1. Meddelandekön är bunden att utbyta med en argumenttabell som innehåller rubrikerna som ska matchas för denna bindning, och eventuellt de värden de ska innehålla. Routingnyckeln används inte.
  2. Utgivaren skickar ett meddelande till börsen, där headers-egenskapen innehåller en tabell med namn och värden.
  3. Meddelandet skickas till kön om headers-egenskapen matchar argumenten som kön var associerad med.

Matchningsalgoritmen styrs av ett speciellt bindningsargument som skickas som ett namn-värdepar i argumenttabellen. Detta argument kallas "X-match". Det kan ta ett av två värden, som dikterar hur andra namnvärdespar i tabellen hanteras under matchning:

  • "all" innebär att alla andra par måste matcha rubrikegenskapen för meddelandet för att detta meddelande ska omdirigeras (AND)
  • 'any' innebär att meddelandet ska omdirigeras om något av fälten i headers-egenskapen matchar ett av fälten i argumenttabellen (OR)

Ett fält i bindningsargumenten matchar ett fält i meddelandet om följande villkor är sant: antingen har fältet i bindningsargumenten inget värde och fältet med samma namn finns i meddelandehuvuden, eller om fältet i bindningen argument har ett värde och fältet med samma namn finns i rubrikmeddelandena och har samma betydelse.

Alla fält som börjar med 'x -' förutom 'X-match' är reserverade för framtida användning och kommer att ignoreras

Servern MÅSTE implementera Headers Exchange Type, och servern MÅSTE fördeklarera minst en Headers Exchange Type som heter amq.match i varje virtuell värd.

Systemutbytestypen

Systemutbytestypen fungerar så här:

  1. Utgivaren skickar ett meddelande att utbyta med routingnyckeln S.
  2. Systemväxeln skickar den till systemtjänsten S.

Systemtjänster som börjar med "amq." reserverad för AMQP. Alla andra namn kan användas. Denna typ av utbyte är valfritt.

Anpassade utbytestyper

Alla anpassade utbytestypnamn måste börja med "x -". Utbytestyper som inte börjar med "x -" är reserverade för framtida användning i AMQP-standarden.

Meddelandeköer

En meddelandekö är en namngiven FIFO som innehåller meddelanden från applikationer. Applikationer är fria att skapa, dela, använda och förstöra meddelandeköer inom deras behörighet.

Observera att när det finns flera läsare från en kö, eller klienttransaktioner, eller använder prioritetsfält, eller använder meddelandeväljare, eller implementeringsspecifik leveransoptimering, kanske kön inte har riktiga FIFO-egenskaper. Det enda sättet att garantera FIFO är att bara ha en konsument ansluten till kön. I dessa fall kan kön beskrivas som "svag-FIFO".

Meddelandeköer kan vara permanenta, tillfälliga eller automatiskt raderade. Beständiga meddelandeköer finns tills de tas bort. Tillfälliga meddelandeköer finns tills servern stängs av. Autodelete-köer varar tills de inte längre används.

Meddelandeköer lagrar sina meddelanden i minnet, på disken eller någon kombination av de två. Meddelandeköer namnges baserat på den virtuella värden.

Meddelandeköer innehåller meddelanden och distribuerar dem till en eller flera konsumentkunder. Ett meddelande som skickas till en meddelandekö skickas aldrig till mer än en klient om det inte har avvisats

En meddelandekö kan innehålla olika typer av innehåll samtidigt och oberoende. Det vill säga, om huvudinnehållet och filinnehållet skickas till samma meddelandekö, kommer de att levereras till konsumerande applikationer oberoende på begäran.

Bindningar

Bindning är kopplingen mellan meddelandekö och datautbyte. Bindningen definierar routingargumenten som talar om för växeln vilka meddelanden kön ska ta emot. Applikationer skapar och förstör bindningar efter behov för att styra flödet av meddelanden till deras meddelandeköer. Livslängden för en bindning beror på de meddelandeköer som de är definierade för - när en meddelandekö förstörs förstörs även dess bindning. Den specifika semantiken för Queue.Bind-metoden beror på utbytestypen.

Konsumenter - konsumenter

Vi använder termen konsument för att hänvisa till både klientapplikationen och den enhet som kontrollerar hur en viss klientapplikation tar emot meddelanden från meddelandekön. När en klient "startar en konsument" skapar den en konsumentenhet på servern. När en klient "avbryter en konsument" förstör den konsumentenheten på servern. Konsumenter tillhör samma klientkanal och tvingar meddelandekön att skicka meddelanden till klienten asynkront.

Servicekvalitet

Kvaliteten på tjänsten avgör hastigheten med vilken meddelanden skickas. Kvaliteten på tjänsten beror på vilken typ av innehåll som distribueras. I allmänhet använder QoS konceptet "förhämtning" för att indikera hur många meddelanden eller hur många oktetter av data som kommer att skickas innan klienten bekräftar meddelandet. Målet är att skicka meddelandedata i förväg för att minska latensen.

Acknowledgements

En bekräftelse är en formell signal från en klientapplikation till meddelandekön att den framgångsrikt har bearbetat ett meddelande. Det finns två möjliga valideringsmodeller:

  1. Automatisk - där servern tar bort innehållet från meddelandekön så snart det levereras till applikationen (med hjälp av Deliver- eller Get-Ok-metoderna).
  2. Explicit - där klientapplikationen måste skicka Ack-metoden för varje meddelande eller batch av meddelanden som den har bearbetat

Klientlager kan själva implementera explicita bekräftelser på olika sätt, till exempel direkt efter att ha tagit emot ett meddelande eller när en applikation indikerar att den har behandlat det. Dessa skillnader påverkar inte AMQP eller interoperabilitet.

flödeskontroll

Flödeskontroll är en nödprocedur som används för att stoppa flödet av meddelanden från en peer. Det fungerar på samma sätt mellan klient och server och implementeras av kommandot Channel.Flow. Flödeskontroll är den enda mekanismen som kan stoppa en överproduktiv utgivare. En konsument kan använda en mer elegant mekanism för förhämtning av fönster om den använder bekräftelser (vilket vanligtvis innebär att använda transaktioner).

Namnkonvention

Dessa konventioner reglerar namngivningen av AMQP-enheter. Servern och klienten måste respektera dessa konventioner:

  • Anpassade utbyten måste börja med prefixet "x-".
  • Standardutbytesinstanser måste börja med prefixet "amq".
  • Standardsystemtjänster måste börja med prefixet "amq".
  • Standardmeddelandeköer måste börja med prefixet "amq".

Specifikation av AMQP-kommandon (klasser och metoder)

Anteckningar

AMQP-metoder kan definiera minimivärden (som antalet konsumenter i en meddelandekö) av kompatibilitetsskäl. Dessa minimivärden definieras i beskrivningen av varje klass.

Överensstämmande AMQP-implementeringar bör implementera ganska generösa värden för sådana fält, minimivärdena är endast avsedda att användas på de minst kapabla plattformarna.

Grammatik använder denna notation:

  • 'S:' indikerar data eller metod som skickas från servern till klienten;
  • 'C:' indikerar data eller metod som skickas från klienten till servern;
  • +villkor eller +(...) uttryck betyder "1 eller flera instanser";
  • *villkor eller *(...) uttryck betyder "noll eller fler instanser".

Vi definierar metoder som:

  • synkron begäran ("syn request"). Den sändande värden måste vänta på en specifik svarsmetod, men kan implementera detta asynkront;
  • synkront svar ("syn svar för XYZ");
  • asynkron begäran eller svar ("asynkron")

Teknisk specifikation

Portnummer definierade av IANA

Standard AMQP-portnumret har tilldelats av IANA som 5672 för både TCP och UDP. UDP-port reserverad för användning i framtida multicast-implementationer

Trådnivåformat för AMQP

Officiellt grammatikprotokoll

Vi tillhandahåller en komplett grammatik för AMQP (detta tillhandahålls som referens, och du kanske är mer intresserad av att följa avsnitten som beskriver de olika typerna av ramar och deras format):

amqp = protokoll - header * amqp - enhet protokoll - header = bokstavlig - AMQP- protokoll - id - protokoll - version literal - AMQP = % d65 .77.81.80 ; "AMQP" protokoll - id = % d0 ; Måste vara 0 protokoll - version = % d0.9.1 ; _ 0-9-1 metod = metod - ram [ innehåll ] metod - ram = % d1 ram - egenskaper metod - nyttolast ram - slut ram - egenskaper = kanal nyttolast - storlek kanal = kort - uint ; icke - noll nyttolast - storlek = lång - uint metod - nyttolast = klass - id metod - id * amqp - fält class - id = % x00 .01 - % xFF . FF metod - id = % x00 .01 - % xFF . FF amqp - fält = BIT / OCTET / kort - uint / lång - uint / lång - lång - uint / kort - sträng / lång - sträng / tidsstämpel / fält - tabell kort - uint = 2 * OCTET lång - uint = 4 * OCTET lång - lång - uint = 8 * OCTET kort - sträng = OCTET * sträng - char ; längd + innehåll sträng - char = % x01 .. % xFF lång - sträng = lång - uint * OCTET ; längd + innehåll timestamp = long - long - uint ; 64 - bitars POSIX fält - tabell = lång - uint * fält - värde - par fält - värde - par = fält - namnfält - värde _ fält - namn = kort - sträng fält - värde = 't' booleskt / 'b' kort - kort - int / 'B' kort - kort - uint / 'U' kort - int / 'u' kort - uint / 'I' long - int / 'jag' lång - uint / 'L' lång - lång - int / 'l' long - long - uint / 'f' flyta / 'd' dubbelt / 'D' decimal - värde / 's' kort - sträng / 'S' lång - sträng / 'A' fält - array / 'T' tidsstämpel / 'F'- fält - tabell / 'V' ; inget fält boolean = OCTET ; 0 = FALSK , annars SANT kort - kort - int = OCTET kort - kort - uint = OCTET kort - int = 2 * OCTET lång - int = 4 * OCTET lång - lång - int = 8 * OCTET flyta = 4 * OCTET ; IEEE -754 dubbel = 8 * OCTET ; rfc1832 XDR dubbel decimal - värde = skala lång - uint skala = OCTET ; antal decimalsiffror _ _ fält - array = long - int * fält - värde ; rad värden _ ram - slut = % xCE innehåll = % d2 innehåll - rubrik * innehåll - brödtext innehåll - rubrik = ram - egenskaper header - nyttolast ram - slut header - nyttolast = innehåll - klassinnehåll - viktinnehåll - kropp - storlek _ _ egenskap - flaggar egenskap - lista innehåll - klass = oktett innehåll - vikt = % x00 innehåll - kropp - storlek = lång - lång - uint egenskap - flaggor = 15 * BIT % b0 / 15 * BIT % b1 egenskap - flaggor egenskap - lista = * amqp - fält innehåll - kropp = % d3 ram - egenskaper kropp - nyttolast ram - slut kropp - nyttolast = * OCTET hjärtslag = % d8 % d0 % d0 frame - end


Vi använder den utökade BNF-syntaxen som definieras i IETF RFC 2234. Sammanfattningsvis:

  • Namnet på regeln är bara själva namnet
  • Terminaler anges med ett eller flera numeriska tecken, med bastolkningen av dessa tecken betecknade som "d" eller "x"
  • En regel kan definiera en enkel ordnad sträng av värden genom att lista en sekvens av regelnamn
  • Ett intervall av alternativa numeriska värden kan specificeras kompakt genom att använda ett bindestreck ( " - " ) för att indikera intervallet
  • Element inom parentes behandlas som ett enda element vars innehåll är strikt ordnat.
  • Element separerade med ett snedstreck ( " / " ) är alternativ.
  • Operatorn * som föregår ett element indikerar upprepning. Lång form: "<a>*< b>element", där <a> och <b> är valfria decimalvärden, minst <a> och högst <b> elementförekomster.
Protokollrubrik

Klienten måste starta en ny anslutning genom att skicka protokollhuvudet. Detta är en 8 oktettsekvens:

+---+---+---+---+----+---+---+---+ | 'A' | 'M' | 'Q' | 'P' | 0 | 0 | 9 | 1 | +---+---+---+---+----+---+---+---+ 8 oktetter

Protokollhuvudet består av de stora bokstäverna "AMQP" följt av konstanten %d0 följt av:

  1. Huvudversionen av protokollet som används i enlighet med avsnitt 1.4.2. (av. dokumentation version 0-9-1)
  2. Mindre version av protokollet som används i enlighet med avsnitt 1.4.2. (av. dokumentation version 0-9-1)
  3. Protokollrevision används i enlighet med avsnitt 1.4.2. (av. dokumentation version 0-9-1)

Protokollförhandlingsmodellen är kompatibel med befintliga protokoll som HTTP, som initierar en anslutning med en konstant textsträng, och med brandväggar, som tittar på början av ett protokoll för att avgöra vilka regler som ska gälla för det.

Klienten och servern förhandlar om protokollet och versionen enligt följande:

  • Klienten öppnar en ny socket-anslutning till AMQP-servern och skickar ett protokollhuvud.
  • Servern antingen accepterar eller avvisar protokollhuvudet. Om den avvisar protokollhuvudet, skriver den en giltig protokollrubrik till socket och stänger sedan socket.
  • Annars lämnar den sockeln öppen och implementerar protokollet på lämpligt sätt.

Exempel:

Klienten skickar : Servern svarar : AMQP % d0 .0.9.1 Anslutning . startmetoden _ AMQP % d0 .1.0.0 AMQP % d0 .0.9.1 < Stäng anslutning > HTTP AMQP % d0.0.9.1 < Stäng anslutning > _

Principer för implementering av protokollet:

  • Servern kan acceptera icke-AMQP-protokoll såsom HTTP
  • Om servern inte känner igen de första 5 oktetterna med data på socket, eller inte stöder den specifika protokollversionen som klienten begär, måste den skriva en giltig protokollhuvud till socket och sedan spola socket (för att säkerställa att klienten applikationen tar emot data) och stäng sedan anslutningen med uttaget. Servern kan skriva ut ett diagnostiskt meddelande i felsökningssyfte.
  • En klient kan bestämma serverns protokollversion genom att försöka ansluta till dess högsta version som stöds och återansluta till en lägre version om den får sådan information tillbaka från servern.
  • Klienter och servrar som implementerar flera versioner av AMQP MÅSTE använda alla åtta oktetter i protokollhuvudet för att identifiera protokollet.


Grundläggande ramformat

Alla ramar börjar med en 7-oktettshuvud som består av ett typfält (oktett), ett kanalfält (kort heltal) och ett längdfält (långt heltal):

0 1 3 7 storlek + 7 storlek + 8 +------+---------+--------+ +---------+ +------ -----+ | typ | kanal | storlek | | nyttolast | | ram - slut | +------+---------+--------+ +---------+ +------ -----+ oktett kort lång ' storlek ' oktetter oktett

AMQP definierar följande ramtyper:

  • Typ = 1, "METHOD": metodram.
  • Typ = 2, "HEADER": ram för innehållsrubrik
  • Typ = 3, "BODY": innehållsbrödram.
  • Typ = 4, "HEARTBEAT": hjärtslagsram.

Kanalnumret är 0 för alla ramar som är globala för anslutningen och 1-65535 för ramar som refererar till specifika kanaler.

Storleksfältet är storleken på nyttolasten, exklusive end-of-frame-oktetten. Medan AMQP antar ett tillförlitligt anslutet protokoll, använder vi slutet av ramen för att upptäcka inramningsfel orsakade av felaktiga klient- eller serverimplementationer.

Principer för implementering av protokollet:

  • End-of-frame-oktetten måste alltid ha det hexadecimala värdet %xCE.
  • Om en peer tar emot en ram med en typ som inte är en av dessa definierade typer, bör den behandla detta som ett fatalt protokollfel och stänga anslutningen utan att skicka ytterligare data om det.
  • När en kamrat läser en ram måste den kontrollera att slutet av ramen är giltig innan den försöker avkoda ramen. Om slutet av ramen inte är giltigt bör det behandla detta som ett allvarligt protokollfel och stänga anslutningen utan att skicka ytterligare data om det. Den bör logga information om problemet, eftersom detta indikerar ett fel i implementeringen av serverns eller klientens ramkod.
  • En kamrat FÅR INTE skicka ramar som är större än den förhandlade storleken. En peer som tar emot en ram som är för stor MÅSTE signalera ett anslutningsundantag med en 501 (ramfel) svarskod.
  • Kanalnumret måste vara noll för alla hjärtslagsramar och för metod-, rubrik- och bodyramar som refererar till Connection-klassen. En peer som tar emot ett kanalnummer som inte är noll för en av dessa ramar MÅSTE signalera ett anslutningsundantag med en 503 (kommando ogiltig) svarskod.
Metod Nyttolaster

Metodramkroppar består av en oföränderlig lista av datafält som kallas "argument". Alla metodkroppar börjar med klass- och metodidentifierare:

0 2 4 +----------+------------+-------------- - - | klass - id | metod - id | argument ... +----------+------------+-------------- - - kort kort ...

Principer för implementering av protokollet:

  • Klass-id och metod-id är konstanter definierade i AMQP-klass- och metodspecifikationerna.
  • Argument är en uppsättning AMQP-fält specifika för varje metod
  • Värdeklassidentifieraren %x00.01 till %xEF.FF är reserverad för standard AMQP-klasser.
  • Klass-ID:n från %xF0.00 till %xFF.FF (%d61440-%d65535) kan användas när de implementeras för icke-standardiserade tilläggsklasser.
AMQP-datafält

AMQP har två nivåer av datafältsspecifikation: inbyggda datafält som används för metodargument och datafält som skickas mellan applikationer i fälttabeller. Fälttabeller innehåller en upphöjd uppsättning av inbyggda datafält.

Heltal

AMQP definierar följande inbyggda heltalstyper:

  • Osignerad oktett (8 bitar).
  • Korta heltal utan tecken (16 bitar).
  • Långa heltal utan tecken (32 bitar).
  • Långa långa heltal utan tecken (64 bitar).

Heltal och stränglängder är alltid osignerade och lagras i nätverksbyteordning. Vi försöker inte optimera fallet där två låg-höga system (t.ex. två Intel-processorer) pratar med varandra.

Principer för implementering av protokollet:

  • Designers bör inte anta att de heltal som kodas i en ram är inriktade på minnesordsgränser.
Bits

AMQP definierar sin egen typ av bitfält. Bitarna ackumuleras till hela oktetter. När två eller flera bitar berörs i en ram, kommer de att packas i en eller flera oktetter, med början med den lägsta biten i varje oktett. Det finns inget krav på att alla bitvärden i en ram ska vara sammanhängande, men detta görs vanligtvis för att minimera ramstorlekar.

Strängar

AMQP-strängar har variabel längd och representeras av en heltalslängd följt av noll eller fler datoktetter. AMQP definierar två inbyggda radtyper:

  • Korta strängar lagrade som en 8-bitars heltalslängd utan tecken följt av noll eller fler oktetter med data. Korta strängar kan innehålla upp till 255 oktetter UTF-8-data, men kan inte innehålla binära nolloktetter.
  • Långa strängar lagrade som en 32-bitars heltalslängd utan tecken följt av noll eller fler oktetter med data. Långa strängar kan innehålla vilken data som helst
Tidsstämplar

Tidsstämplar lagras i 64-bitars POSIX time_t-format med en precision på en sekund. Genom att använda 64 bitar undviker vi framtida inpackningsproblem associerade med 31-bitars och 32-bitars time_t-värden.

Tabellmarginaler

Tabellfält är långa strängar som innehåller packade namn-värdepar. Namnvärdespar kodas som en kort sträng som anger namnet och en oktett som anger värdetypen, följt av själva värdet. Giltiga fälttyper för tabeller är tillägg av de ursprungliga typerna heltal, bit, sträng och tidsstämpel, och visas i grammatiken. Heltalsfält med flera oktetter lagras alltid i nätverksbyteordning.

Principer för implementering av protokollet:

  • Fältnamn måste börja med bokstaven "$" eller "#" och får fortsätta med bokstäverna "$" eller "#", siffror eller understreck, upp till en maximal längd på 128 tecken.
  • Servern MÅSTE validera fältnamnen, och när den får ett ogiltigt fältnamn MÅSTE den signalera ett anslutningsundantag med en 503 (syntaxfel) svarskod.
  • Decimalvärden är inte utformade för att stödja flyttalvärden, utan för att stödja affärsvärden med fasta punkter som valutakurser och belopp. De är kodade som en oktett som representerar antalet platser följt av ett förtecknat långt heltal. Oktett "decimaler" - ej signerad.
  • Dubblettfält är olagligt. Beteendet för en peer med avseende på en tabell som innehåller dubbletter av fält är odefinierat.
Beskärning av innehåll

Vissa specifika metoder (Publicera, Leverera, etc.) bearbetar innehållet. Se kapitlet "Funktionella specifikationer" för specifikationerna för varje metod. Metoder som bearbetar innehåll gör det ovillkorligt.

Innehållet består av en lista med 1 eller flera ramar enligt följande:

  1. Exakt en ram för innehållsrubrik som tillhandahåller egenskaper för innehållet.
  2. Alternativt, en eller flera innehållsbrödramar

Innehållsramar på en viss kanal är strikt sekventiella. Det vill säga, de kan blandas med ramar för andra kanaler, men inga två innehållsramar från samma kanal kan blandas och kan inte "överlappa" varandra, och innehållsramar för samma innehåll kan inte blandas med metodramar på samma kanal ... (orig. Innehållsramar på en specifik kanal är strikt sekventiella. Det vill säga, de kan blandas med ramar för andra kanaler, men inga två innehållsramar från samma kanal får blandas eller överlappas, inte heller får innehållsramar för ett enda innehåll vara blandat med metodramar på samma kanal.)

Observera att alla ramar som inte innehåller innehåll uttryckligen markerar slutet på innehållet. Även om storleken på innehållet är välkänd från innehållsrubriken (och därmed antalet innehållsramar), tillåter detta avsändaren att avbryta innehållet utan att behöva stänga kanalen.

Principer för implementering av protokollet:

  • En kamrat som tar emot ofullständigt eller dåligt formaterat innehåll bör skicka ett anslutningsundantag med en 505 (oväntad ram) svarskod. Detta inkluderar saknade innehållsrubriker, felaktiga klass-ID:n i innehållsrubriker, saknade innehållskroppsramar, etc.
Innehållstitel

Innehållets nyttolasthuvud har följande format:

0 2 4 12 14 +----------+--------+-----------+----------------+ ------------- - - | klass - id | vikt | kroppsstorlek | _ egendomsflaggor | _ fastighetslista ... _ +----------+--------+-----------+----------------+ ------------- - - kort kort lång lång kort återstod ...

Principer för implementering av protokollet:

  • Klass-ID:t måste matcha klass-ID:t för metodramen. Peer måste svara på en ogiltig klassidentifierare genom att skicka ett anslutningsundantag med en 501 (ramfel) svarskod.
  • Viktfältet används inte och måste vara noll.
  • Kroppsstorlek är ett 64-bitars värde som anger den totala storleken på innehållskroppen, vilket är summan av kroppsstorlekarna för följande bildrutor i innehållskroppen. Noll indikerar inga ramar för innehållet.
  • Egenskapsflaggor är en uppsättning bitar som indikerar närvaron eller frånvaron av varje egenskapsvärde i sekvensen. Bitarna är ordnade från högsta till lägsta. Bit 15 pekar på den första egenskapen.
  • Egenskapsflaggor kan ange fler än 16 egenskaper. Om den sista biten (0) är satt betyder det att den följs av ett annat egenskapsflaggfält. Det finns många fastighetsflaggor.
  • Egenskapsvärden är klassspecifika AMQP-datafält.
  • Bitegenskaper indikeras endast av motsvarande egenskapsflagga (1 eller 0) och finns aldrig i egenskapslistan.
  • Kanalnumret i innehållsramar får inte vara noll. En kamrat som tar emot ett kanalnummer noll i en innehållsram MÅSTE signalera ett anslutningsundantag med en 504 (kanalfel) svarskod.
Innehållstext

Innehållskroppens nyttolast är ett "ogenomskinligt" binärt block som slutar med en ramslutoktett:

+----------------------------+ +-----------+ | Ogenomskinlig binär nyttolast | | ram - slut | +----------------------------+ +-----------+

Innehållskroppen kan delas upp i så många ramar som behövs. Den maximala ramnyttolasten förhandlas fram av båda peers under anslutningsförhandling.

Principer för implementering av protokollet:

  • Peer måste bearbeta innehållet som är uppdelat i flera ramar, lagra dessa ramar som en enda uppsättning och antingen återsända dem som de är, dela upp dem i mindre ramar eller slå samman dem till ett enda block för leverans till applikationen.
hjärtslagsramar

Hjärtslagsramar berättar för mottagaren att avsändaren fortfarande lever. Frekvensen och timingen för Heartbeat-ramar förhandlas under anslutningsinstallationen.

Principer för implementering av protokollet:

  • Hjärtslagsramar måste ha ett kanalnummer på noll. En kamrat som tar emot en ogiltig Heartbeat-ram MÅSTE skicka ett anslutningsundantag med en 501 (Frame Error) svarskod.
  • Om kamraten inte stöder Heartbeat, MÅSTE den kassera Heartbeat-ramen utan att signalera något fel eller fel.
  • Klienten bör börja skicka Heartbeat efter att ha mottagit Connection.Tune-metoden och börja övervaka Heartbeat efter att ha tagit emot Connection.Open. Servern bör börja skicka och övervaka Heartbeat efter att ha mottagit Connection.Tune-Ok
  • Noden måste göra allt för att skicka Heartbeat med vissa intervall. Hjärtslag kan skickas när som helst. Varje oktett som skickas är en giltig Heartbeat-ersättning, så Heartbeats bör endast skickas om AMQP-trafik utan Heartbeat inte skickas under mer än ett Heartbeat-intervall. Om peeren upptäcker ingen inkommande trafik (d.v.s. mottagna oktetter) under två eller flera hjärtslagsintervall, MÅSTE den stänga anslutningen utan att ringa Connection.Close/Close-Ok handskakning och logga felet
  • Hjärtslag ska fortsätta tills uttaget stängs, inklusive under och efter anslutning. Stäng/Stäng-Ok handskakning

Kanalmultiplexering

AMQP tillåter kamrater att skapa flera oberoende kontrollflöden. Varje kanal fungerar som en virtuell anslutning som delar ett uttag:

ramar ramar ramar ramar +-----------+------------+------------+------------+ | kanal | kanal | kanal | kanal | +-----------+------------+------------+------------+ | uttag | +------------------------------------------------ ----+

Principer för implementering av protokollet:

  • En AMQP-peer KAN stödja flera kanaler. Det maximala antalet kanaler bestäms när en anslutning förhandlas, och en peer kan förhandla om detta antal upp till 1.
  • Varje kamrat MÅSTE balansera trafiken på alla öppna kanaler på ett rättvist sätt. Denna balansering kan göras per bildruta eller baserat på mängden trafik per kanal. En kamrat FÅR INTE tillåta en mycket upptagen kanal för att begränsa framstegen för en mindre upptagen kanal.

Garanterad synlighet

Servern måste säkerställa att klientens observationer av serverns tillstånd är konsekventa.

Följande exempel visar vad klientobservation betyder i detta sammanhang:

  • Klient 1 och klient 2 är anslutna till samma virtuella värd
  • Klient 1 deklarerar en kö
  • Klient 1 får Declare.Ok
  • Kund 1 berättar för klient 2 om det
  • Klient 2 gör en passiv deklaration av samma kö

Synlighetsgarantin säkerställer att klient 2 ser kön

Stänga kanalen

Servern kommer att betrakta kanalen som stängd om något av följande inträffar:

  • Antingen stänger kamraten kanalen eller föräldraanslutningen med handskakningen Close/Close-Ok
  • Antingen kastar kamraten ett undantag på kanalen eller föräldraanslutningen.
  • Antingen stänger noden den överordnade anslutningen utan Close/Close-Ok-handskakning

När servern stänger en kanal markeras alla obekräftade meddelanden på kanalen för återleverans. När servern stänger en anslutning tar den bort alla automatiskt borttagna enheter som hör till den anslutningen.

Innehållssynkronisering

I vissa fall påverkar synkrona förfrågningssvarsmetoder asynkron leverans av innehåll över samma kanal, inklusive:

  • Metoder Basic.Consume och Basic.Cancel som startar och stoppar flödet av meddelanden från meddelandekön
  • Basic.Recover-metoden som begär återleverans av meddelanden till kanalen
  • Queue.Bind, Queue.Unbind och Queue.Purge metoder som påverkar flödet av meddelanden som riktas till meddelandekön

Principer för implementering av protokollet:

  • Effekterna av begäran-svar ska inte vara synliga på kanalen före svarsmetoden och bör vara synliga efter den.

Content Order Guarantee

Ordningen i vilken metoder passerar genom en kanal är stabil: metoder tas emot i samma ordning som de skickas. I transportskiktet tillhandahålls detta av TCP/IP-protokollet. Dessutom bearbetas innehållet stabilt av servern. Framför allt kommer innehåll som följer samma sökväg inom servern att förbli beställt. För innehåll med en given prioritet som passerar genom en enda väg, definierar vi innehållsbehandlingsvägen som bestående av en inkommande kanal, en växel, en kö och en utgående kanal.

Principer för implementering av protokollet:

  • Servern MÅSTE bevara ordningen för innehåll som passerar genom en enda innehållsbehandlingsväg, såvida inte återleveransfältet har ändrats i metoderna Basic.Deliver eller Basic.Get-Ok och i enlighet med reglerna som definierar villkoren under vilka fältet kan ställas in.

Felhantering

Undantag

Genom att använda standardprogrammeringsmodellen "undantag" signalerar AMQP inte framgång, bara misslyckande. AMQP definierar två nivåer av uteslutningar:

  1. Kanaluteslutningar. De stänger kanalen som orsakade felet. Kanalundantag beror vanligtvis på "mjuka" fel som inte påverkar resten av applikationen.
  2. Undantag för anslutning . De stänger socket-anslutningen och beror vanligtvis på "hårda" fel, som indikerar ett programmeringsfel, dålig konfiguration eller annan händelse som kräver uppmärksamhet.

Vi dokumenterar formellt påståendena i definitionen av varje klass och metod.

Svarskodsformat

AMQP-svarskoder följer definitionen av "svarskodens allvarlighetsgrad och teori" i IETF RFC 2821.

Implementeringar

Funktioner i AMQP-protokollet

  • Strängar i AMQP är skiftlägeskänsliga
  • Versioneringskonvention - versionsnumret består av två eller tre siffror: major.minor.revision I det här fallet är revision valfri. Siffror kan ha värden från 0 till 99. Siffror från 100 och uppåt är reserverade för internt bruk. Version 1.1 motsvarar version 1.1.0

Anteckningar

  1. Mot en handelsvara Enterprise Middleware . Hämtad 14 juni 2010. Arkiverad från originalet 5 mars 2010.

Litteratur

  • Emrah Ayanoglu; Yusuf Aytas; Dotan Nahum. Mastering RabbitMQ. - Packt Publishing, 2016. - 286 sid. — ISBN 978-1-78398-153-3 .

Länkar