Preskoči na sadržaj
Blog

Tri razloga zašto je vaš račun za cloud veći nego što treba

Tri nalaza nisu bila povezana: nešto pogrešno procijenjeno, nešto pokvareno i nešto napravljeno naopako. Samo jedan od njih bio je optimizacija. Druga dva bila su greške koje su, mjesec za mjesecom, plaćali ljudi koji nisu imali razloga da gledaju.

Izdavanje dokumenata8 min čitanja

Prvo što smo na tom projektu uradili bilo je da pročitamo račun. Ne backlog, ne repozitorij — fakturu. Iznosio je oko 24.000 dolara mjesečno za sistem koji, kad smo razumjeli saobraćaj, nije imao razloga koštati više od nekoliko hiljada. Šest mjeseci kasnije bio je oko 2.000 dolara, i nijedna funkcionalnost nije uklonjena da bi se do toga došlo.

Sistem izdaje pasoše i lične karte za nacionalno tijelo za identitet. Agenti izlaze na teren kod podnosilaca zahtjeva koji nemaju internet vezu, pa se zahtjev, fotografije i biometrija snimaju na službenom telefonu i šalju kad se veza pojavi. Taj detalj je bitan za ono što slijedi: u ovom sistemu je gotovo svaki zahtjev upload.

Od nas niko nije tražio da smanjimo račun. To nije bilo u opsegu posla. Ali faktura je jedini dokument u projektu s kojim se niko ne može prepirati, i to što smo je pročitali prvu reklo nam je više o stanju sistema nego što bi rekla sedmica sastanaka.

Pročitajte račun prije nego pročitate backlog

Račun je mjerenje onoga što sistem stvarno radi, koje je uzela strana bez ikakvog udjela u priči. Code review vam kaže šta kôd piše. Monitoring vam kaže šta je tim odlučio da nadgleda. Faktura vam kaže gdje su vrijeme i propusni opseg mašine zaista otišli, uključujući i dijelove kojih se niko ne sjeća da je gradio.

To je ujedno i najbrži način da se problemi razvrstaju po vrsti. Grupišite račun po servisu i po okruženju, pa po svakoj stavci postavite jedno pitanje: je li ovo cijena posla ili cijena greške? Na ovom projektu su tri stavke odgovorile „greška“, i svaka je bila druge vrste.

Uzrok jedan: sve je bilo za jedan broj preveliko

Instance, baza, workeri — sve izdašno dodijeljeno, po procjeni napravljenoj prije nego što je sistem imao korisnike. Ovo je najčešći uzrok i najmanje zanimljiv, jer nije ničija greška. Infrastrukturu dimenzionišete u trenutku kad nemate podataka, a pošten izbor je predimenzionisati. Ono što krene po zlu jeste to što se procjena nikad ne preispita kad stvarne brojke postoje.

Predimenzionisanje ima svoj potpis: iskorištenost koja nije samo niska nego ravna. Mašina koja radi stvaran posao ima oblik svog dana. Mašina koja je prevelika ima ravnu liniju na 8% sa izbočinom kad se pokrene dnevni posao.

Dva pravila kojih se držimo prije nego ičemu promijenimo veličinu. Gledajte sedmice, ne sate — jedno prometno popodne nije plan kapaciteta. I razdvojite vrhove po uzroku: na ovom sistemu je flota bila dimenzionisana za istovremenost uploada, a ne za propusnost zahtjeva, što znači da je mašina bila velika zbog bafera držanih u memoriji, a ne zbog računanja. Ta razlika odlučuje hoćete li smanjiti kapacitet ili promijeniti arhitekturu, a ovdje je odgovor ispao — oboje.

Uzrok dva: petlje koje niko nije primijetio

Ovaj nije optimizacija. To je greška koja je radila u produkciji, neprekidno trošila računarske resurse, i bila na fakturi svakog mjeseca a da niko iznos nije povezao sa kvarom.

Oblik je bio poznat: posao koji sam sebe ponovo zakazuje i nema završno stanje. Otprilike ovako, u grubim crtama —

// ponavljanje bez uslova za kraj i bez dead letter reda
async function processPending() {
  const jobs = await db.jobs.findPending();

  for (const job of jobs) {
    try {
      await handle(job);
      await db.jobs.markDone(job.id);
    } catch (err) {
      // nazad u pending, zauvijek, bez brojača pokušaja
      await db.jobs.markPending(job.id);
    }
  }

  setTimeout(processPending, 1000);
}

Posao koji nikad ne može uspjeti — neispravan zapis, dokument koji više ne postoji, treća strana koja vraća trajnu grešku — ponavlja se sto hiljada puta dnevno. Košta računanje, košta konekcije prema bazi, i košta prikupljanje logova, što je na dovoljno velikoj petlji stavka koja najviše boli. Izvana ništa nije pokvareno. API odgovara. Niko ne otvara tiket. Faktura tiho raste.

Potpis na računu je suprotan prvom uzroku: trošak koji ne prati upotrebu. Ako je grafikon jednako visok u četiri ujutro kao i u podne, radi nešto što ne pokreću korisnici. To je pitanje koje vrijedi postaviti o svakoj ravnoj liniji na fakturi — ne „možemo li ovo pojeftiniti“ nego „šta je ovo, tačno“.

Popravka nije manja instanca. To je brojač pokušaja, završno stanje i mjesto na koje neuspjesi odlaze.

const MAX_ATTEMPTS = 5;

async function handleJob(job) {
  try {
    await handle(job);
    return db.jobs.markDone(job.id);
  } catch (err) {
    const attempts = job.attempts + 1;

    if (attempts >= MAX_ATTEMPTS || isPermanent(err)) {
      // prestaje koštati i počinje biti vidljivo
      return db.jobs.markFailed(job.id, err.message);
    }

    return db.jobs.retryIn(job.id, attempts, backoff(attempts));
  }
}

Važna linija je markFailed. Red bez stanja neuspjeha ne uklanja neuspjeh, nego ga pretvara u ponavljajući trošak. Eksponencijalni backoff ograničava brzinu; ograničenje broja pokušaja ograničava ukupno; zapis u stanju neuspjeha je nešto što operater može vidjeti, a to je i poenta. Radije bismo imali pedeset zapisa u stanju neuspjeha i jedan alarm nego petlju koja je nevidljiva svuda osim na fakturi.

Uzrok tri: svaki bajt je prolazio kroz backend

Svaki uploadovani fajl — fotografija lica, fotografija dokumenta — putovao je sa telefona u Node proces i odatle u object storage. U sistemu u kojem gotovo svaki zahtjev nosi sliku, ovo nije bila hrapavost na arhitekturi. To jeste bila arhitektura, i bila je najveća pojedinačna stavka na računu.

Provlačenje fajlova kroz vlastiti server košta četiri stvari odjednom: memoriju za bafere, propusni opseg za bajtove koji putuju dvaput, veličinu instance biranu prema istovremenosti uploada umjesto prema poslu, i dostupnost — jer uploadi i API pozivi dijele iste workere, pa nalet sporih uploada na lošoj mobilnoj vezi natjera brze endpointe da čekaju u redu iza njih.

Prelazak na pre-signed uploade u potpunosti izbacuje bajtove iz putanje zahtjeva. Sama izmjena je mala; posao dizajna je odluka gdje žive validacija i autorizacija kad vaš server fajl više nikad ne vidi. O tome smo pisali zasebno, sa kodom i sa zamkama: direktni upload na S3, i gdje provjere idu poslije.

Zašto je redoslijed bio bitan

Sve se ovo desilo prije nego što smo napravili ijednu funkcionalnost. To je bilo namjerno, i to je isti sud koji uopšteno primjenjujemo na naslijeđene sisteme: stabilizuj ono što postoji prije nego mu dodaješ. Sistem koji tiho traći osam puta više nego što košta govori vam nešto o tome kako se njime upravljalo, a taj kontekst vrijedi imati prije nego se obavežete na plan.

Postoji i praktičan argument. Popravljanje računa je u prvim sedmicama kupilo povjerenje, brojkom koju niko nije morao uzeti na vjeru. Svaki arhitektonski razgovor poslije toga kretao je sa drugog mjesta.

I redoslijed je zaštitio posao: da smo prvo gradili funkcionalnosti, upload putanja bi se ugradila u još tri toka, a uzrok tri bi od dvodnevne izmjene postao migracija.

Šta bismo uradili drugačije

Stavite brojku na svaki uzrok, ne na ukupno. Znamo da je račun pao sa oko 24.000 dolara na oko 2.000 dolara. Ne možemo vam reći koliko je od toga bila promjena veličine, koliko petlje, a koliko uploadi. Tri odvojena mjerenja koštala bi nas po jedan sat i učinila bi ovaj članak boljim — a, korisnije, rekla bi klijentu kojoj klasi grešaka je njegov sistem najskloniji.

Alarm na trošak po okruženju, od prvog dana. Ne mjesečno upozorenje o budžetu na nalogu, koje stiže nakon što je novac potrošen, nego dnevni alarm na anomaliju po okruženju. Petlje su se mogle otkriti bilo kojeg dana od šest mjeseci koliko su radile; ništa ih nije nadgledalo.

Označite resurse tagovima da račun može odgovarati na pitanja. Grupisanje po servisu vam kaže da je računanje skupo. Grupisanje po okruženju i po funkcionalnosti vam kaže koji je dio proizvoda skup, a to je pitanje koje svako zaista i ima.

Ako iz ovoga treba ponijeti jednu stvar: razdvojite te tri vrste. Nešto pogrešno procijenjeno je odluka koju treba preispitati. Nešto pokvareno je kvar sa cijenom na sebi. Nešto napravljeno naopako je arhitektonska izmjena sa rokom na sebi, jer popravka postaje skuplja sa svakom funkcionalnošću koja se na nju osloni.

Ovo je nastalo iz gradnje nacionalnog sistema za izdavanje ličnih karata i pasoša, gdje je isti pregled našao i uploade koji idu kroz backend i petlje koje niko nije primijetio. Pročitajte studiju →

Srodno
Cijeli blog →

Sumnjate da vam je AWS račun prevelik?

Pregled infrastrukture, tri do pet konkretnih nalaza, bez obaveza. Odgovaramo u roku od jednog radnog dana.

Kontaktirajte nas

Sistemi koji ne smiju stati — od arhitekture do produkcije.

© 2026 Micro Tech, Sarajevo