Hændelsesdrevet arkitektur øger omkostningseffektiviteten af de anvendte ressourcer, fordi de kun bruges i det øjeblik, hvor de er nødvendige. Der er mange muligheder for at implementere dette og ikke oprette yderligere cloud-enheder som arbejdsapplikationer. Og i dag vil jeg ikke tale om FaaS, men om webhooks. Jeg viser et selvstudieeksempel på håndtering af hændelser ved hjælp af webhooks til objektlagring.
Et par ord om objektopbevaring og webhooks. Objektlagring giver dig mulighed for at gemme alle data i skyen i form af objekter, tilgængelige via S3 eller en anden API (afhængig af implementering) via HTTP/HTTPS. Webhooks er generelt tilpassede HTTP-tilbagekald. De udløses typisk af en hændelse, såsom kode, der bliver skubbet til et lager, eller en kommentar, der bliver postet på en blog. Når en hændelse opstår, sender oprindelsesstedet en HTTP-anmodning til den URL, der er angivet for webhook. Som et resultat kan du få hændelser på ét websted til at udløse handlinger på et andet (wiki). I det tilfælde, hvor kildestedet er et objektlager, fungerer hændelser som ændringer af dets indhold.
Eksempler på simple tilfælde, hvor sådan automatisering kan bruges:
Oprettelse af kopier af alle objekter i et andet skylager. Kopier skal oprettes med det samme, når filer tilføjes eller ændres.
Automatisk oprettelse af en række miniaturer af grafiske filer, tilføjelse af vandmærker til fotografier og andre billedændringer.
Meddelelse om ankomsten af nye dokumenter (for eksempel uploader en distribueret regnskabstjeneste rapporter til skyen, og økonomisk overvågning modtager meddelelser om nye rapporter, kontrollerer og analyserer dem).
Lidt mere komplekse sager involverer for eksempel generering af en anmodning til Kubernetes, som opretter en pod med de nødvendige containere, sender opgaveparametre til den, og efter behandling kollapser containeren.
Som et eksempel vil vi lave en variant af opgave 1, når ændringer i Mail.ru Cloud Solutions (MCS) objektlagringsbøtten synkroniseres i AWS objektlagring ved hjælp af webhooks. I et rigtigt belastet tilfælde bør asynkront arbejde udføres ved at registrere webhooks i en kø, men til træningsopgaven vil vi udføre implementeringen uden dette.
Arbejdsplan
Interaktionsprotokollen er beskrevet detaljeret i Guide til S3 webhooks på MCS. Arbejdsplanen indeholder følgende elementer:
Forlagstjeneste, som er på S3-lagersiden og udgiver HTTP-anmodninger, når webnhook udløses.
Webhook modtagende server, som lytter til anmodninger fra HTTP-udgivelsestjenesten og udfører passende handlinger. Serveren kan skrives på ethvert sprog; i vores eksempel vil vi skrive serveren i Go.
Et særligt træk ved implementeringen af webhooks i S3 API er registreringen af webhook-modtagelsesserveren på udgivelsestjenesten. Især skal webhook-modtagende server bekræfte abonnementet på meddelelser fra publiceringstjenesten (i andre webhook-implementeringer er bekræftelse af abonnement normalt ikke påkrævet).
Følgelig skal webhook-modtagende server understøtte to hovedoperationer:
svare på forlagstjenestens anmodning om at bekræfte registreringen,
behandle indkommende begivenheder.
Installation af en webhook-modtageserver
For at køre webhook-modtagelsesserveren skal du bruge en Linux-server. I denne artikel bruger vi som eksempel en virtuel instans, som vi implementerer på MCS.
Lad os installere den nødvendige software og starte webhook-modtagelsesserveren.
ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install git
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
bc dns-root-data dnsmasq-base ebtables landscape-common liblxc-common
liblxc1 libuv1 lxcfs lxd lxd-client python3-attr python3-automat
python3-click python3-constantly python3-hyperlink
python3-incremental python3-pam python3-pyasn1-modules
python3-service-identity python3-twisted python3-twisted-bin
python3-zope.interface uidmap xdelta3
Use 'sudo apt autoremove' to remove them.
Suggested packages:
git-daemon-run | git-daemon-sysvinit git-doc git-el git-email git-gui
gitk gitweb git-cvs git-mediawiki git-svn
The following NEW packages will be installed:
git
0 upgraded, 1 newly installed, 0 to remove and 46 not upgraded.
Need to get 3915 kB of archives.
After this operation, 32.3 MB of additional disk space will be used.
Get:1 http://MS1.clouds.archive.ubuntu.com/ubuntu bionic-updates/main
amd64 git amd64 1:2.17.1-1ubuntu0.7 [3915 kB]
Fetched 3915 kB in 1s (5639 kB/s)
Selecting previously unselected package git.
(Reading database ... 53932 files and directories currently installed.)
Preparing to unpack .../git_1%3a2.17.1-1ubuntu0.7_amd64.deb ...
Unpacking git (1:2.17.1-1ubuntu0.7) ...
Setting up git (1:2.17.1-1ubuntu0.7) ...
Gå til den spand, som vi vil konfigurere webhooks til, og klik på gearet:
Gå til fanen Webhooks, og klik på Tilføj:
Udfyld felterne:
ID — navnet på webhook.
Hændelse - hvilke hændelser der skal overføres. Vi har indstillet transmissionen af alle hændelser, der opstår, når du arbejder med filer (tilføje og slette).
URL — webhook, der modtager serveradresse.
Filterpræfiks/suffiks er et filter, der giver dig mulighed for kun at generere webhooks for objekter, hvis navne matcher bestemte regler. For at webhook kun skal udløse filer med filtypenavnet .png, skal du f.eks Filtersuffiks du skal skrive "png".
I øjeblikket understøttes kun porte 80 og 443 til at få adgang til webhook-modtagelsesserveren.
Lad os klikke Tilføj krog og vi vil se følgende:
Krog tilføjet.
Den webhook-modtagende server viser i sine logfiler forløbet af hook-registreringsprocessen:
Funktionerne HmacSha256 og HmacSha256hex er implementeringer af HMAC-SHA256 og HMAC-SHA256 krypteringsalgoritmer med output som en streng af hexadecimale tal til beregning af signaturen.
main er hovedfunktionen, behandler kommandolinjeparametre og registrerer URL-handlere.
Kommandolinjeparametre accepteret af serveren:
-port er den port, som serveren vil lytte til.
-adresse - IP-adresse, som serveren vil lytte til.
-script er et eksternt program, der kaldes for hver indkommende hook.
Lad os se nærmere på nogle af funktionerne:
//Webhook
func Webhook(w http.ResponseWriter, req *http.Request) {
// Read body
body, err := ioutil.ReadAll(req.Body)
defer req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// log request
log.Printf("[%s] incoming HTTP request from %sn", req.Method, req.RemoteAddr)
// check if we got subscription confirmation request
if strings.Contains(string(body),
""Type":"SubscriptionConfirmation"") {
SubscriptionConfirmation(w, req, body)
} else {
GotRecords(w, req, body)
}
}
Denne funktion bestemmer, om der er modtaget en anmodning om bekræftelse af registrering eller en webhook. Som følger af dokumentation, hvis registreringen bekræftes, modtages følgende Json-struktur i Post-anmodningen:
POST http://test.com HTTP/1.1
x-amz-sns-messages-type: SubscriptionConfirmation
content-type: application/json
{
"Timestamp":"2019-12-26T19:29:12+03:00",
"Type":"SubscriptionConfirmation",
"Message":"You have chosen to subscribe to the topic $topic. To confirm the subscription you need to response with calculated signature",
"TopicArn":"mcs2883541269|bucketA|s3:ObjectCreated:Put",
"SignatureVersion":1,
"Token":«RPE5UuG94rGgBH6kHXN9FUPugFxj1hs2aUQc99btJp3E49tA»
}
Afhængigt af anmodningen skal du derfor forstå, hvordan du behandler dataene. Jeg valgte posten som en indikator "Type":"SubscriptionConfirmation", da det er til stede i anmodningen om abonnementsbekræftelse og ikke er til stede i webhook. Baseret på tilstedeværelsen/fraværet af denne post i POST-anmodningen, går yderligere udførelse af programmet enten til funktionen SubscriptionConfirmation, eller ind i funktionen GotRecords.
Vi vil ikke overveje abonnementsbekræftelsesfunktionen i detaljer; den implementeres i overensstemmelse med principperne angivet i dokumentation. Du kan se kildekoden til denne funktion på projekt git repositories.
GotRecords-funktionen analyserer en indgående anmodning og kalder for hvert Record-objekt et eksternt script (hvis navn blev videregivet i parameteren -script) med parametrene:
spand navn
objekt nøgle
handling:
kopi - hvis i den oprindelige anmodning EventName = ObjectCreated | PutObject | PutObjectCopy
slet - hvis i den oprindelige anmodning EventName = ObjectRemoved | Slet objekt
Hvis der således ankommer en krog med en Post-anmodning, som beskrevet ovenfor, og parameteren -script=script.sh, så kaldes scriptet som følger:
script.sh bucketA some-file-to-bucket copy
Det skal forstås, at denne webhook-modtageserver ikke er en komplet produktionsløsning, men et forenklet eksempel på en mulig implementering.
Eksempel på arbejde
Lad os synkronisere filerne fra hovedbøtten i MCS til backup-bøtten i AWS. Den primære bucket hedder myfiles-ash, den backup kaldes myfiles-backup (bucket-konfiguration i AWS er uden for denne artikels omfang). Følgelig, når en fil placeres i hovedbøtten, skal dens kopi vises i backup-en, og når den slettes fra den primære, skal den slettes i backup-en.
Vi vil arbejde med buckets ved hjælp af awscli-værktøjet, som er kompatibelt med både MCS cloud storage og AWS cloud storage.
ubuntu@ubuntu-basic-1-2-10gb:~$ sudo apt-get install awscli
Reading package lists... Done
Building dependency tree
Reading state information... Done
After this operation, 34.4 MB of additional disk space will be used.
Unpacking awscli (1.14.44-1ubuntu1) ...
Setting up awscli (1.14.44-1ubuntu1) ...
Lad os konfigurere adgang til S3 MCS API:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile mcs
AWS Access Key ID [None]: hdywEPtuuJTExxxxxxxxxxxxxx
AWS Secret Access Key [None]: hDz3SgxKwXoxxxxxxxxxxxxxxxxxx
Default region name [None]:
Default output format [None]:
Lad os konfigurere adgang til AWS S3 API:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws configure --profile aws
AWS Access Key ID [None]: AKIAJXXXXXXXXXXXX
AWS Secret Access Key [None]: dfuerphOLQwu0CreP5Z8l5fuXXXXXXXXXXXXXXXX
Default region name [None]:
Default output format [None]:
Lad os tjekke adgangene:
Til AWS:
ubuntu@ubuntu-basic-1-2-10gb:~$ aws s3 ls --profile aws
2020-07-06 08:44:11 myfiles-backup
For MCS, når du kører kommandoen, skal du tilføje —endpoint-url:
Lad os se, hvordan det virker. igennem MCS webgrænseflade tilføj test.txt-filen til myfiles-ash-bøtten. Konsollogfilerne viser, at der blev foretaget en anmodning til webhook-serveren:
2020/07/06 09:43:08 [POST] incoming HTTP request from
95.163.216.92:56612
download: s3://myfiles-ash/test.txt to ../../../tmp/myfiles-ash/test.txt
upload: ../../../tmp/myfiles-ash/test.txt to
s3://myfiles-backup/test.txt
Lad os tjekke indholdet af myfiles-backup-bøtten i AWS:
Nu vil vi via webgrænsefladen slette filen fra myfiles-ash-bøtten.
Serverlogfiler:
2020/07/06 09:44:46 [POST] incoming HTTP request from
95.163.216.92:58224
delete: s3://myfiles-backup/test.txt
Spandens indhold:
ubuntu@ubuntu-basic-1-2-10gb:~/s3-webhook$ aws s3 --profile aws ls
myfiles-backup
ubuntu@ubuntu-basic-1-2-10gb:~$
Filen er slettet, problemet er løst.
Konklusion og ToDo
Al kode brugt i denne artikel er i mit depot. Der er også eksempler på scripts og eksempler på optælling af signaturer til registrering af webhooks.
Denne kode er intet andet end et eksempel på, hvordan du kan bruge S3 webhooks i dine aktiviteter. Som jeg sagde i begyndelsen, hvis du planlægger at bruge sådan en server i produktionen, skal du i det mindste omskrive serveren til asynkront arbejde: registrere indgående webhooks i en kø (RabbitMQ eller NATS), og derfra parse dem og behandle dem med arbejderansøgninger. Ellers, når webhooks kommer massivt, kan du støde på mangel på serverressourcer til at fuldføre opgaver. Tilstedeværelsen af køer giver dig mulighed for at distribuere serveren og arbejderne samt løse problemer med gentagne opgaver i tilfælde af fejl. Det er også tilrådeligt at ændre logningen til en mere detaljeret og mere standardiseret.