Programeri često nepotrebno komplikuju tehnička rešenja, a dobar primer za to je arhitektura za URL shortener servise - sisteme koji pretvaraju dugačke internet adrese u kratke, lake za deljenje linkove. Nedavna rasprava na programerskoj zajednici Reddit pokazala je kako iskusni inženjeri ponekad kreiraju preterano složena rešenja za jednostavne probleme.
Jedan tehnički direktor predstavio je komplikovanu arhitekturu za servis koji treba da obradi 100.000 zahteva za skraćivanje URL-ova u sekundi. Njihovo rešenje uključivalo je brojne redove za čekanje, radne instance i kompleksno upravljanje podacima. Međutim, mnogi komentatori su primetili da takva složenost nije neophodna.
Problem URL shortenera je zapravo prilično jednostavan: korisnik šalje dugačak URL, a sistem vraća kratku verziju. Eventualno, zahteva se i mogućnost da korisnik sam izabere kako će izgledati skraćeni link, ali to ne komplikuje osnovnu arhitekturu.
Jednostavna i efikasna arhitektura za URL shortener
Osnovna struktura efikasnog URL shortener sistema mogla bi da izgleda ovako:
- API serveri sa kešom u memoriji
- Baza podataka za trajno čuvanje podataka
- Jednostavan tok obrade zahteva
Kada korisnik pošalje POST zahtev za kreiranje novog kratkog URL-a, zahtev stiže do jednog od API servera, koji zatim zapisuje podatke u bazu. Za GET zahteve (kada neko poseti kratki URL), server prvo proverava keš u memoriji i samo ako ne pronađe podatke, obraća se bazi podataka.
Ključna prednost ovog pristupa je što većina zahteva za čitanje nikada ne dođe do baze podataka, već se opslužuje direktno iz keša u memoriji.
DynamoDB ili bilo koji drugi moderni key-value sistem skladištenja podataka može da izađe na kraj sa potrebnim obimom pisanja i čitanja. Grubo računajući, ako kratki i dugački URL zajedno zauzimaju oko 500 bajtova, pri 100.000 upisa u sekundi, sistem bi pisao oko 50 megabajta podataka u sekundi.
Jedan DynamoDB može da obradi oko 40.000 KB pisanja u sekundi, ili 80.000 KB kada je unapred provizioniran. Ako ti je potrebno više, možeš podeliti podatke na dve instance baze podataka prema heš vrednosti kratkog URL-a.
LRU keš ubrzava čitanje podataka
LRU keš (Least Recently Used) je struktura podataka koja čuva fiksni broj najčešće korišćenih stavki. Kada dođe do prekoračenja kapaciteta, izbacuju se stavke koje su najređe korišćene.
Ako bi svaki zapis u kešu zauzimao oko 1 KB memorije, čuvanje milion zapisa bi koštalo samo 1 GB RAM-a, što je sasvim prihvatljivo za moderne servere. Pošto su skraćeni URL-ovi nepromenljivi (jednom kreiran kratki URL uvek vodi na isti dugački URL), stopa pogodaka u kešu biće izuzetno visoka.
Za obradu milion zahteva u sekundi, gde se većina opslužuje direktno iz memorije, dovoljno je svega desetak API servera. Takva postavka omogućava i lako skaliranje broja servera prema potrebi, bez značajnog uticaja na ostatak arhitekture.
Zašto složenost nije uvek bolja
U originalnom članku, autor je naveo zahtev da svaki dugački URL može imati samo jedan odgovarajući kratki URL. Ovo je neobičan zahtev koji većina URL shortener servisa nema, a čak i ako bi bilo potrebno implementirati takvu funkcionalnost, ne bi bila potrebna komplikovana arhitektura.
Jednostavno rešenje bi bilo čuvanje obrnutog mapiranja (dugački URL → kratki URL) kao dodatni ključ-vrednost par. Ovo bi omogućilo:
- Proveru duplikata na određenom šardu baze podataka
- Izveštavanje o svim kratkim linkovima za dati domen
Internet inženjeri i programeri, posebno početnici, često na osnovu autoritativnih blog postova zaključuju da je preterano složena arhitektura "pravi način" za rešavanje tehničkih problema. Međutim, jednostavnija rešenja su često efikasnija, lakša za održavanje i jeftinija.