Blog

Upozorenja koja se šalju jednom, a ne jednom po serveru

Jedno od naših operativnih upozorenja, “niski krediti” za objavljenu aplikaciju graditelja, namijenjeno je da nam stigne najviše jednom dnevno. Jednog je popodneva stiglo pet puta. Uzrok: svaka kopija našeg API-ja pamtila je koja su upozorenja već poslala u vlastitoj memoriji, pa su dva servera slala isto dvaput, a svaki deploy briše tu memoriju i dopušta ponovno slanje. Isti obrazac uzrokovao je i da pozadinski posao radi svoj posao dvaput. Oboje se sada usklađuje kroz zajedničku pohranu, a oboje u slučaju nedostupnosti te pohrane griješe na sigurnoj strani.

Simptom

Mythex šalje timska upozorenja kad nešto treba pogledati: servis je pao, posao je zapeo, a stanje kredita graditelja je nisko dok je njegova aplikacija objavljena. Svako upozorenje ima prozor deduplikacije, razdoblje tijekom kojeg se isto upozorenje šalje samo jednom. Za upozorenje o niskim kreditima taj prozor traje 24 sata.

Pet istih upozorenja u jednom popodnevu značilo je da prozor ne drži. Gore od toga, dolazila su u parovima, otprilike 11 minuta jedno od drugoga.

Zašto se to dogodilo

Paket za upozorenja držao je deduplikaciju u memoriji: tablicu “ključ upozorenja → kada je zadnji put poslano”, unutar pokrenutog procesa. To radi kad postoji jedan proces koji se nikad ne pokreće ponovno. Produkcija nema ni jedno ni drugo:

  • Dvije API replike. Produkcija pokreće dvije kopije API-ja. Svaka je imala svoju tablicu, pa je svaka poslala upozorenje jednom. Eto parova.
  • Deployi. Svaki deploy zamjenjuje obje replike novim procesima s praznim tablicama. Nakon deploya upozorenje je ponovno izašlo, kao da nikad nije bilo poslano.

Razmak od oko 11 minuta između dva upozorenja u svakom paru dolazio je od posla koji podiže to upozorenje. Posao radi na obje replike i uzima zaključavanje, pa replike dobivaju red naizmjence, a svaka je podigla upozorenje kad je došao njen red.

U istom kodu krio se i drugi, tiši kvar. Da tablica ne bi zauvijek rasla, čistila se kad je dosegnula 500 ključeva: brisala je svaki unos stariji od 15 minuta, bez obzira na njegov prozor. Pod opterećenjem 24-satna deduplikacija mogla je trajati četvrt sata.

Ispravak

Jedan zajednički zapis po upozorenju

Prije nego API pošalje upozorenje, sada u Redisu, zajedničkoj memoriji kojoj obje replike pristupaju i koja se ne resetira kad se API ponovno pokrene, zauzme ključ deduplikacije za to upozorenje. Zauzimanje je jedna operacija: “postavi ovaj ključ samo ako ne postoji i istekni ga nakon prozora”. Replika koja prva zauzme ključ šalje upozorenje; druga nađe ključ zauzet i šuti. Novi proces nakon deploya nađe ključ i dalje tamo.

Ključ i prozor dolaze iz istog pravila koje sada dijele paket za upozorenja i ta dva sloja, pa se ne mogu razilaziti oko toga što je “isto upozorenje”.

Griješi na otvorenoj strani

Najvažnija odluka bila je što učiniti kad se Redisu ne može pristupiti. Odlučili smo poslati upozorenje ipak. Ako Redis ne radi ili ne odgovori u roku od 1,5 sekunde, upozorenje odlazi. Duplo upozorenje je šum. Izgubljeno upozorenje znači da netko nije obaviješten.

Najozbiljnija upozorenja, P0, deduplikacija uopće ne zadržava.

Svaki unos zadržava svoj prozor

U vlastitoj deduplikaciji paketa za upozorenja u memoriji svaki unos sada pamti kada mu prozor završava, a čišćenje uklanja samo unose čiji je prozor istekao. Ključ od 24 sata ostaje 24 sata, bez obzira na to koliko je drugih upozorenja stiglo.

Isti kvar, na drugom mjestu

Isti obrazac udvostručio je i dio pozadinskog posla: posao usklađivanja koji naš zapis statusa svakog radnog prostora drži u skladu s onim kod našeg pružatelja sandboxa. Svaki prolaz nabraja svaki sandbox na računu, tisuće u produkciji, otprilike pet sekundi, plus svaki projekt koji radi ili je pauziran. Obje replike pokretale su ga svake dvije minute.

Njegovi upisi su idempotentni, tj. pokretanje dvaput daje isti rezultat kao jednom, pa ništa nije puklo. Samo je bilo dvostruko više posla. Sada se svaki dvominutni prozor zauzima u Redisu na isti način kao što su naši mjerači potrošnje već zauzimali svoje, a prolaz pokreće samo ona replika koja ga zauzme. Ako se Redisu ne može pristupiti, prolaz se ipak izvrši: dvostruki rad je bezopasan, a izostavljen rad nije.

Kako smo testirali

Testovi modeliraju pravo okruženje. Učitavaju modul za upozorenja dvaput, kao dvije odvojene “replike”, usmjere obje na jednu zajedničku pohranu, podignu isto upozorenje iz svake, zatim učitaju treću svježu kopiju koja zamjenjuje “nakon deploya” i podignu ga opet. Šalje se točno jedno upozorenje. Drugi testovi provjeravaju da upozorenje drugog graditelja i dalje stiže, da P0 odlazi s obje replike te da se upozorenje šalje i kad je pohrana nedostupna ili prekorači vremenski limit. Popravak čišćenja ima vlastiti test: ključ od 24 sata preživi 600 drugih upozorenja koja stignu 20 minuta kasnije.

Za posao usklađivanja, dvije replike koje otkucavaju u isto vrijeme, plus treći otkucaj u istom prozoru, daju jedan popis.

Što smo iz ovoga naučili

  • Stanje u memoriji pripada procesu. Sve što mora biti istinito preko servera, “poslano jednom” ili “pokrenuto jednom”, mora živjeti na mjestu koje oni dijele.
  • Deployi su ponovna pokretanja. Stanje koje preživi samo do sljedećeg ponovnog pokretanja ne preživi običan radni dan.
  • Odluči u koju stranu ćeš griješiti. Za upozorenja, nedostupna zajednička pohrana treba značiti više upozorenja, a ne manje.
  • Traži obrazac, a ne samo primjer. Upozorenje je bio glasni slučaj; udvostručeni posao usklađivanja bio je isti kvar koji tiho troši rad.

Ništa od ovoga nije vidljivo iznutra Mythexa. Više o tome kako držimo platformu stabilnom pogledajte u kako smo spustili deploye na nula 502 grešaka i nedostajuća swap datoteka. Ako vam je ideja pokretanja više kopija servisa nova, naš vodič što je server pokriva osnove.

Mythex · Pricing · Izradite bilo što uz AI · Predlošci za web stranice i aplikacije · Mythex u usporedbi · Rječnik izrade aplikacija uz AI · Besplatni alati za izradu aplikacija uz AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو Tiếng Việt 简体中文 繁體中文(香港) 繁體中文(台灣)