Kako steći iskustvo u visokoj konkurentnosti?
Prvo zaključak.
Prvo na svom računaru moraš da namestiš okruženje za komponente visoke konkurentnosti i distribuirane arhitekture — Redis, kafka, dubbo, mycat i sl. — i preko tih okruženja da upoznaš osnovne API-je distribuiranih komponenti.
Za te distribuirane komponente pronađi scenarije iz prakse koji dokazuju da si ih koristio i rešavao stvarne probleme. Ovde treba naglasiti da napamet učenje odgovora na pitanja sa razgovora o visokoj konkurentnosti ne pomaže.
Izmeni CV kako bi dobio priliku za razgovore o visokoj konkurentnosti, a zatim kroz više razgovora neprestano doteruj način na koji pričaš o svom iskustvu sa visoko konkurentnim projektima. Ako u tom trenutku možeš da u veliku kompaniju uđeš pričom o visokoj konkurentnosti — to je najbolje; ako ne, nađi prelaznu poziciju koja pruža praksu u toj oblasti.
Ako imaš praktično iskustvo sa projektima visoke konkurentnosti, onda dalje nema šta da se priča — samo rešavaj više stvarnih problema, i veštinu visoke konkurentnosti ćeš brzo savladati. Tada stečena veština visoke konkurentnosti više nije samo teorija i poznavanje osnovnih API-ja, već prava projektna praksa.
Može se reći da pronalaženje praktičnog iskustva u projektima visoke konkurentnosti odlučuje o tome da li će programer napredovati do arhitekte, a to nije lako. U nastavku ću ispričati iskustvo jednog mog prijatelja; Erge se često čuje sa njim i oni međusobno lajkuju na Zhihu-u, haha.

- Početkom 2017. godine prijatelj je u timu radio samo jednostavne projekte sa Spring + JDBC/ORM, razvoj je bio na Windowsu, a od komponenti visoke konkurentnosti dodirivao je samo nginx i mysql klastere, uz nešto iskustva sa deploy-om i debagovanjem na Linuxu; nije imao iskustvo u korišćenju komponenti visoke konkurentnosti.
Sigurno je da danas mnogi čitaoci liče na mog prijatelja — znaju samo da rade CRUD (dodavanje, čitanje, izmena, brisanje) na Windowsu, bez ikakvog iskustva sa distribuiranim komponentama i visokom konkurentnošću.
Ako tako nastavi, sa samo osnovnim CRUD-om, za još koju godinu, kada dođu godine, verovatno neće imati ni priliku za promenu posla.
Kasnije je ovaj prijatelj krenuo da uči odgovore napamet — strukture podataka u redis-u, dubbo protokol, tok u kafka-i, sprečavanje ne-idempotentnosti pri visokom opterećenju, ključne tačke korišćenja netty memorije van heap-a, optimizacija JVM-a i sl. Šta god je vezano za visoku konkurentnost, uglavnom je naučio napamet. Zatim je počeo da menja CV: „U projektu XX opterećenje je iznosilo XX zahteva u sekundi, korišćeni su Redis, kafka, dubbo (i ostale distribuirane komponente)…" — i prijavljivao se.
Pošto je prijateljeva tadašnja kompanija bila dobra, CV je brzo dobijao odgovore i on je dobio prilično prilika za razgovore u velikim kompanijama. U početku, kada su pitali o Javi i bazama podataka, prijatelj je prolazio u trenu. Ali na pitanja o distribuiranim komponentama uglavnom nije imao šta da kaže.
Pošto je prijatelj učio teoriju odvojenu od projekta — npr. kako se postavlja mysql klaster, koje su strukture podataka u redis-u — a intervjueri su pitali u kontekstu projekta, npr. „Kako u tvom projektu Redis osigurava visoku dostupnost?" ili „Kada se nginx-om deploy-uje Spring Boot projekat, na šta treba obratiti pažnju u konfiguracionom fajlu?". Pošto je prijatelj naučio samo teoriju napamet, nije mogao da odgovori.
- Posle nekoliko pokušaja, prijatelj je shvatio da učenje napamet ne može da prođe, pa je na svom računaru podigao razvojna okruženja za brojne komponente visoke konkurentnosti. Iako se komponente u projektu inače izvršavaju na Linuxu, većina ih ima i Windows verzije.
Tada je podigao razvojna okruženja za mysql master-slave klaster, redis master-slave klaster, rabbitmq, dubbo+zookeeper, nginx, mycat i druge, upoznao se sa osnovnom upotrebom svake komponente i za svaku pronašao scenarios iz prakse. Za redis je, na primer, rekao: „U projektu nam je trebao keš za podatke o zaposlenima, pa smo koristili xxx API iz Redis-a, a odgovarajući Java kod izgleda ovako…"; i slično, za svaku komponentu je našao pozadinu za primenu.
Tada je prijatelj ponovo išao na razgovore; u oblasti distribuiranih komponenti već je mogao da održi pristojan razgovor sa intervjuerom, čak je uspeo i na nekoliko razgovora u malim kompanijama. Ali kada bi intervjuer postavio pitanja o praktičnim detaljima — npr. kako redis sprečava „proboj keša" (cache penetration), kako radi failover u redis cluster-u — prijatelj nije znao odgovor. Zato je tada ostavljao utisak na intervjuera: ima iskustva sa distribuiranim komponentama, ume da razvija osnovne veštine visoke konkurentnosti pomoću njih, ali mu nedostaje sistematska sposobnost da dizajnira visoko konkurentna rešenja pomoću distribuiranih komponenti.
U tom trenutku prijatelj se setio onoga što je na početku učio napamet — kako netty sprečava curenje memorije van heap-a, kako netty rešava problem „polutačkih" i „lepivih" paketa (half-packet/sticky-packet), kako redis sprečava proboj keša, kako mycat implementira razdvajanje čitanja i pisanja, kao i mehanizme za ograničavanje protoka (rate limiting) i prekidanje kola (circuit breaking). Tada je shvatio: ta pitanja dolaze tek nakon što savladaš osnovne priče o visokoj konkurentnosti — ne na samom početku.
Kada je to shvatio, postalo je mnogo lakše: te veštine nisu vezane za razvoj, dovoljno je da u kontekstu projekta objasniš ključne tačke implementacije.
Na primer, za ograničavanje protoka prvo pripremi scenario — npr. sistem za upite u kompaniji propušta najviše 1000 zahteva u sekundi — a zatim objasni ključne tačke u praksi: to je u suštini redis+lua; potom objasni šta se radi u izuzetnim situacijama — u suštini, izbacivanje izuzetka kada se prekorači limit. Slično se pripremaju i teme o prekidu kola i sprečavanju proboja keša.
- Obratite pažnju: u ovom trenutku prijateljevo iskustvo sa distribuiranim visoko konkurentnim sistemima i dalje je bilo samo na teorijskom nivou; ali tada je na razgovoru pričom o „upotrebi + ključnim tačkama prakse" uspeo da se predstavi kao osoba sa iskustvom u projektima visoke konkurentnosti, pa je stopa uspeha na kasnijim razgovorima bila znatno veća.
Međutim, u toj fazi, kako bi napao pozicije u velikim kompanijama, prijatelj je još pripremio i „stvarne probleme rešene u projektu".
Šablon priče je u suštini uvek isti: prvo, koji se problem javio — npr. proboj keša u redis-u, OOM izuzetak, ili prevelika akumulacija mrtvih poruka (dead-letter) u kafka-i; zatim, koji je bio ishod — sistem pao, zamrznuo se, ili funkcija nije radila; zatim, kako je dijagnostikovan — uglavnom čitanjem logova, koji izuzetak se pojavio, šta se otkrilo; i najzad, kako je rešeno.
Takvih primera na internetu ima na pretek, ali su objašnjenja uglavnom čisto teorijska — moraš im pronaći projektnu pozadinu. Na primer: „Sistem za plaćanje XX naišao je na OOM izuzetak", „Sistem za distribuciju kupona XX imao je previše mrtvih poruka", „Sistem za plaćanje XX suočio se sa probojem keša u redis-u" i sl.
Drugim rečima, kroz neprestane razgovore prijatelj je sredio priče iz oblasti visoke konkurentnosti: osnovna upotreba + ključne tačke prakse + rešeni problemi. Tako, iako i dalje nije imao iskustvo sa projektima visoke konkurentnosti, već je mogao da obezbedi ulazak u veliku kompaniju. U stvari, tako je prijatelj i ušao u veliku kompaniju.
Nakon ulaska u veliku kompaniju, prijatelju je zapravo bilo veoma teško: s jedne strane, tim je kroz razgovor doneo ocenu da on ima projektno iskustvo visoke konkurentnosti, a zapravo nije imao — ali da se nije tako predstavio, ostao bi u staroj firmi da radi osnovni CRUD.
Tada je prijatelj, pored toga što je sam svuda tražio informacije, mogao samo da s jedne strane smelo pita ljude unaokolo, a s druge — mnogo radi prekovremeno. Pošto je njegov projekat koristio visoku konkurentnost, u svakodnevnom radu imao je obimne prilike za razvoj, deploy i debagovanje, i često je rešavao probleme visoke konkurentnosti.
Tako je prijatelj težak period provukao za oko tri meseca; kasnije nije samo rešavao probleme visoke konkurentnosti, već je učestvovao i u testovima pod opterećenjem, i putem njih poboljšavao performanse u uslovima visoke konkurentnosti — tek tada je prijatelj zaista stekao projektno iskustvo u visokoj konkurentnosti.
- Dividenda od savladavanja iskustva visoke konkurentnosti prilično je velika. Kada je prijatelj savladao to iskustvo, na kasnijim traženjima posla prolazio je na većini tehničkih razgovora.
Erge poznaje jednog majstora, zove se Li Zhihui; zahvaljujući sposobnostima u arhitekturi visoke konkurentnosti, on trenutno na jednom obrazovnom sajtu za tehničke ljude ima kurs o arhitekturi visoke konkurentnosti — ne znam da li je neko od vas čuo za njega.

Ako i ti imaš iskustvo sa visokom konkurentnošću, možeš ući u stranu kompaniju radi mirnijeg života, ili u maloj firmi postati tehnički direktor — tako bar nećeš biti izbačen sa 35 godina.
Zapravo, otkrio sam da iskustvo mnogih ljudi u savladavanju veština visoke konkurentnosti veoma liči na iskustvo Ergeovog prijatelja.
U uslovima kada projekat u firmi ne pruža prilike za praksu visoke konkurentnosti, učenjem napamet — pa makar i po nekim takozvanim mapama uma (mind maps) — prođeš kroz sve vezano za tu oblast.
Zatim uđeš u projekat koji pruža praktične prilike za visoku konkurentnost i stekneš odgovarajuće iskustvo.
Dobiješ priliku za praksu i kroz projekat zaista savladaš veštine visoke konkurentnosti.
Na kraju, jedan sažetak: šta obuhvaćaju sposobnosti visoke konkurentnosti i kako ih savladati? To se ne može objasniti u kratkom članku.
Ali, ako pratiš korake koje sam gore dao — prvo podigneš okruženje, zatim savladaš osnovnu upotrebu distribuiranih komponenti, pa upoznaš ključne tačke prakse i priče o rešavanju problema u visokoj konkurentnosti — barem možeš kroz razgovor dobiti priliku za praksu na projektu visoke konkurentnosti.
Težina savladavanja iskustva visoke konkurentnosti leži u dobijanju praktične prilike; kada uđeš u tim i dobiješ priliku, tehnike visoke konkurentnosti ne moram ni da ti pričam — sam ćeš znati kako da ih savladaš.
Već je rečeno: da bi se steklo iskustvo u visokoj konkurentnosti, obično treba proći dva koraka — prvo, kroz razgovor dobiti priliku za praksu; drugo, unaprediti se kroz projekat. Prava težina je u prvom koraku: pripremiti razgovor iz oblasti visoke konkurentnosti bez ikakvih prethodnih osnova zaista je teško. A nakon što kroz razgovor dobiješ praksu, mogu te prezreti, i rukovodioci mogu misliti da si „vodeni", ali bar si dobio priliku za dalji napredak.
Ovde posebno naglašavam: tehnički intervjueri u velikim kompanijama obično imaju oštro oko — sa svega nekoliko pitanja mogu da razlikuju kandidata sa stvarnim iskustvom u projektima visoke konkurentnosti od onog koji ima samo teorijsko znanje. Nemojte se ovde nadati slučaju.
Gde je, dakle, težina pripreme razgovora iz oblasti visoke konkurentnosti bez prethodnih osnova?
Komponente visoke konkurentnosti uglavnom rade na Linuxu; na Windowsu je teško podići okruženje, a bez okruženja o drugom ne vredi ni pričati.
Čitaoci bez osnova ne znaju kako se distribuirane komponente koriste u uslovima visoke konkurentnosti, ili znaju samo kako da pozovu neki jednostavan API. Zbog nedostatka projektnog iskustva ne znaju ni kako se te komponente koriste u okviru projekta.
Pri učenju kako distribuirane komponente rešavaju probleme visoke konkurentnosti, često se koristi samo jedna komponenta izolovano — npr. samo redis za keš, ili samo rabbitmq kao posrednik za poruke — ali u stvarnim scenarijima se obično kombinuje više distribuiranih komponenti koje zajedno rešavaju problem visoke konkurentnosti.
Pošto znaju samo teoriju i u projektu nisu dodirivali razvoj visoke konkurentnosti, opšte je odsustvo iskustva u analizi, dijagnostici i rešavanju problema iz te oblasti.
U uslovima visoke konkurentnosti često se koriste klastere, prekidanje kola, ograničavanje protoka i sl. Pri radu sa komponentama visoke konkurentnosti često se nagazi na brojne zamke — npr. pogrešan dijalekat u mycat-u, polupaketi u netty-ju, ponovno slanje poruka u posredniku za poruke i sl.
Intervjueri u velikim kompanijama baš preko tih učestalih problema proveravaju kandidatovo iskustvo u visokoj konkurentnosti, a kandidati bez tog iskustva na tom delu obično brzo podlegnu.
U nastavku ću, na osnovu načina na koji ja ocenjujem veštine visoke konkurentnosti, dočarati teškoću sa kojom se suočava kandidat bez projektnog iskustva.
Ne pitam pojmove — npr. strukture podataka u redis-u, ključne komponente u netty-ju — jer ih je kandidat bez iskustva sigurno naučio napamet.
Prvi nivo težine: tu nema fiksnih pitanja; prvo pitam koje distribuirane komponente koristiš u projektu, a zatim, za komponente koje si koristio, pitam o osnovnom API-ju i konfiguraciji u Java okruženju. Na primer, ako si koristio Redis, pitam o sintaksi Jedis-a; ako si koristio Netty, pitam kako se na nivou Jave pravi komunikacioni protokol; ako si koristio RabbitMQ, pitam koje konfiguracije Spring Boot zahteva.
Pitam te kako si komponentu koju si koristio koristio u Javi. Otkrio sam da mnogi kandidati koji znaju samo teoriju, o samoj komponenti (npr. Redis ili netty) pričaju sasvim tečno, ali ne znaju kako da je integrišu sa Java-om — a to je neopravdano.
- Drugi nivo težine: neki kandidati su sami podizali okruženje i znaju API distribuiranih komponenti. Njima postavljam sledeće pitanje — objasni mi projektni scenario u kom si koristio distribuirane komponente (Redis, Kafka, Netty, nginx i sl.). Kažeš da si koristio Redis — kolika je količina podataka u tvom projektu? Da li vaš projekat koristi samostalni Redis ili Redis klaster? Ako je samostalni, kako osiguravate visoku dostupnost?
Kada tako pitam u kontekstu projekta, otkrivam da mnogi kandidati za visoku konkurentnost „popucaju". Njihovim rečima: nginx im je deploy-ovan na Windowsu, redis koriste samo u samostalnoj verziji, a opterećenje im nije ni veliko. To takođe pokazuje da nemaju iskustvo sa distribuiranim komponentama visoke konkurentnosti.
- Ustvari, ako kandidat može, u kontekstu projekta, da objasni upotrebu distribuiranih komponenti, to barem pokazuje da ima izvesnog iskustva; na pozicijama sa nižim zahtevima za visokom konkurentnošću takav nastup, barem u delu distribuiranih komponenti, može proći. Ali za poziciju senior developera ili arhitekte potrebno je pitati i treći nivo težine — koje si probleme rešio u oblasti distribuiranih komponenti visoke konkurentnosti? Time se dokazuje izvesno praktično iskustvo u toj oblasti.
Na internetu za to postoje gotova pitanja — npr. Dubbo problem sa prekoračenjem vremena, problem više centara za registraciju, Redis problem curenja memorije i sl.
No, da se vratimo: i kandidat bez projektnog iskustva u visokoj konkurentnosti, uz pravilnu pripremu, može putem projektnog okvira i rešenih problema da pokaže da ima takvo iskustvo.
Drugim rečima, čak i ako ti u oblasti visoke konkurentnosti nedostaje projektno iskustvo, uz dobru pripremu možeš kroz razgovor dobiti priliku za praksu — treba imati poverenja.
U člancima često koristim lik Xiao Er-a, pa ću i u nastavku uzeti njega za primer.
Xiao Er ima iskustvo u razvoju sa Spring Boot + JPA, što je zapravo i osnova za iskustvo u visokoj konkurentnosti.
Xiao Er je savladao postupak podizanja okruženja za Redis, MyCAT, RabbitMQ, nginx, dubbo+zookeeper, MongoDB i druge komponente na Windowsu — napomenimo: na Windowsu, a ne na Linuxu. Iako su u produkcionom okruženju te komponente na Linuxu, s obzirom na to da svi inače koriste Windows, a razlika u razvoju između Windows i Linux okruženja za te komponente nije velika.
Kada Xiao Er podigne okruženje, prvo pokrene skup projekata u kojima Spring Boot integriše brojne distribuirane komponente, tako da zna kako se koriste, a ne samo kako se priča o njima. Zatim ga nateram da za svaku komponentu pronađe poslovnu pozadinu.
Nakon što nauči da koristi komponente i da ih primenjuje uz poslovnu pozadinu, zatim od Xiao Er-a tražim da nauči napamet najčešće zamke pri radu sa distribuiranim komponentama, kao i uobičajena praktična iskustva — to su u suštini Dubbo prekoračenje vremena poziva, Redis prekoračenje vremena, Redis curenje memorije, ključne tačke integracije Dubbo sa zookeeper-om i sl. Ovaj deo ne treba preduboko zabadati — ne mora da ulazi u algoritme, ni u veštine na najnižem nivou. Inače, većina toga se pominje i u mojoj knjizi. Konačno, preko primera flash-prodaje (seckill) teram Xiao Er-a da na jednom primeru objedini ključne tačke korišćenja više distribuiranih komponenti.
5. Ovo je ključno: naterao sam Xiao Er-a da pripremi mnogo priča o rešavanju problema visoke konkurentnosti. Ti su problemi zapravo veoma uobičajeni — Redis prekoračenje vremena, ne-idempotentnost kod kafka-e zbog ponovnog slanja, otkazivanje centra za registraciju u Dubbo-u i sl. Za te teme, šta sam tražio od svog štićenika da pripremi? Kako se problem otkriva (najčešće preko alarma u logovima ili usporenog sistema), kako se dijagnostikuje (na Linuxu se gledaju logovi, u kojima se vide konkretni ključni pojmovi), kako se rešava (izmene fajlova ili konfiguracije).
Referentni link: https://www.zhihu.com/question/40609661/answer/2245612049
Visoka konkurentnost zapravo nije tako mistična — u suštini se svodi na rešavanje protivrečnosti između „ograničenih resursa" i „neograničenih korisnika". Primetićeš da današnja glavna rešenja stalno kruže oko istih nekoliko pristupa; ako si voljan, čak i bez stvarnog iskustva, nakon vežbanja u četiri oka, na razgovoru to možeš sasvim lepo izneti.
