Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den

Kaixo, Habr! Artem Karamyshev naiz, sistemen administrazio taldeko burua. Mail.Ru Hodeiko Soluzioak (MCS)Azken urtean produktu berri asko merkaturatu ditugu. Gure API zerbitzuak erraz eskalagarriak, hutsegiteekiko toleranteak eta erabiltzaileen kargaren hazkunde azkarrarentzat prest egotea nahi genuen. Gure plataforma OpenStack-en oinarrituta dago, eta hutsegiteekiko tolerantzia-sistema bat lortzeko konpondu behar izan ditugun osagaien hutsegiteekiko tolerantzia-arazo batzuk partekatu nahi nituzke. Uste dut hau interesgarria izango dela OpenStack-en produktuak garatzen dituztenentzat ere.

Plataformaren erresilientzia orokorra bere osagaien erresilientziaren araberakoa da. Beraz, pixkanaka arriskuak identifikatu eta konpondu ditugun geruza guztietan lan egingo dugu.

Istorio honen bideo-bertsioa, jatorrizko iturria Uptime 4. eguneko konferentzian egindako aurkezpen bat izan zena, antolatuta ITsumma, begirada bat eman diezaiokezu Uptime Community YouTube kanalean.

Arkitektura fisikoaren akatsen tolerantzia

MCS hodeiaren zati publikoa bi Tier III datu-zentrotan dago gaur egun, zuntz ilun sare dedikatu baten bidez konektatuta, erredundantzia fisiko bereiziak eta 200 Gbps-ko abiadura dituena. Tier III-ak beharrezko tolerantzia maila eskaintzen dio azpiegitura fisikoari.

Zuntz iluna erredundantea da bai maila fisikoan bai logikoan. Kanalaren erredundantzia prozesua iteratiboa izan zen, eta arazoak sortu ziren arren, etengabe hobetzen ari gara datu-zentroen arteko konexioa.

Adibidez, duela gutxi, gure datu-zentroetako baten ondoan dagoen putzu batean lanean ari ginela, induskatzaile batek hodi bat zulatu zuen, eta bertan zuntz optikoko kable nagusia eta babeskopia zeuden. Datu-zentroarekin genuen komunikazio-kanal segurua ahula zen une batean, putzuan bertan. Ondorioz, gure azpiegituraren zati bat galdu genuen. Horretatik ikasi genuen eta hainbat neurri hartu genituen, besteak beste, ondoko putzu batean zuntz optikoko kable gehigarriak instalatzea.

Gure datu-zentroek telekomunikazio-hornitzaileen presentzia-puntuak dituzte, eta gure aurrizkiak BGP bidez igortzen dizkiegu. Sarearen norabide bakoitzerako metrika onena hautatzen da, bezero ezberdinei konexio-kalitate onena eskaintzeko aukera emanez. Hornitzaile baten bidezko konexioa eten egiten bada, gure bideratzea berkonfiguratzen dugu eskuragarri dauden hornitzaileen bidez.

Hornitzaile baten hutsegitea gertatuz gero, automatikoki hurrengo hornitzailera aldatzen gara. Datu-zentro bat huts egiten badu, gure zerbitzuen ispilu-kopia bat dugu bigarren datu-zentro batean, eta honek bere gain hartzen du karga osoa.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
Azpiegitura fisikoaren erresilientzia

Aplikazio mailako akatsen tolerantziarako zer erabiltzen dugun

Gure zerbitzua hainbat osagai irekitan oinarritzen da.

ExaBGP — BGP oinarritutako bideratze dinamikoaren protokoloa erabiliz hainbat funtzio ezartzen dituen zerbitzu bat. Aktiboki erabiltzen dugu gure zerrenda zuriko IP helbideak iragartzeko, eta horien bidez erabiltzaileek APIra sartzen dira.

HAProxy — OSI ereduaren geruza desberdinetan trafikoa orekatzeko arau oso malguak konfiguratzeko aukera ematen duen karga handiko karga-orekatzaile bat. Zerbitzu guztietan karga-orekatzeko erabiltzen dugu: datu-baseak, mezu-bitartekariak, API zerbitzuak, web zerbitzuak eta gure barne-proiektuak — denak HAProxy-k bultzatuta.

API aplikazioa — Python-en idatzitako web aplikazio bat, erabiltzaileak bere azpiegitura eta zerbitzua kudeatzen dituena.

Langileen eskaera (aurrerantzean langile gisa aipatuko dena) OpenStack zerbitzuetako azpiegitura-deabru bat da, API komandoak azpiegiturara transmititzea ahalbidetzen duena. Adibidez, diskoa sortzea langile batean gertatzen da, eta sorrera-eskaera API aplikazioari bidaltzen zaio.

OpenStack Aplikazioen Arkitektura Estandarra

OpenStack-erako garatutako zerbitzu gehienek paradigma bateratu bat jarraitzen saiatzen dira. Zerbitzu batek normalean bi zati ditu: API bat eta langileak (backend exekutatzaileak). Normalean, APIa Python-en idatzitako WSGI aplikazio bat da, prozesu independente (daemon) gisa edo Nginx edo Apache bezalako web zerbitzari bat erabiliz exekutatzen dena. APIak erabiltzailearen eskaera prozesatzen du eta argibide gehiago bidaltzen dizkio langile aplikazioari exekutatzeko. Transmisio hau mezu-bitartekari baten bidez gertatzen da, normalean RabbitMQ; beste motak ez dira ondo onartzen. Mezuak bitartekarira iristen direnean, langileek prozesatzen dituzte eta, beharrezkoa bada, erantzun bat itzultzen dute.

Paradigma honek hutsegite-puntu komun isolatuak inplikatzen ditu: RabbitMQ eta datu-basea. Hala ere, RabbitMQ zerbitzu bakarrean isolatuta dago eta, teorian, zerbitzu bakoitzerako espezifikoa izan liteke. Beraz, MCSn, zerbitzu hauek ahalik eta gehien bereizten ditugu, datu-base bereizi bat eta RabbitMQ bereizi bat sortuz proiektu bakoitzerako. Ikuspegi hau abantailagarria da, puntu ahul batean hutsegite bat gertatzen bada, zerbitzuaren zati bat bakarrik kaltetzen baita, ez zerbitzu osoa.

Ez dago langileen aplikazio kopuruari mugarik, beraz, APIa erraz eskala daiteke horizontalki orekatzaileen atzean errendimendua eta akatsen tolerantzia handitzeko.

Zerbitzu batzuek zerbitzu barruko koordinazioa behar dute, hau da, APIen eta langileen artean eragiketa sekuentzial konplexuak gertatzen direnean. Kasu honetan, koordinazio-zentro bakarra erabiltzen da, Redis, Memcache, etcd bezalako kluster-sistema bat, langile batek beste bati zeregin bat esleitu zaiola esateko aukera ematen diona ("mesedez, ez hartu"). Guk etcd erabiltzen dugu. Normalean, langileek datu-basearekin aktiboki komunikatzen dira, bertatik informazioa idatziz eta irakurriz. mariadb erabiltzen dugu gure datu-base gisa, gure master anitzeko klusterrean kokatuta dagoena.

Zerbitzu klasiko bakar hau OpenStack-entzat orokorrean onartutako moduan antolatuta dago. Sistema itxi gisa ikus daiteke, eskalatze eta hutsegite-tolerantzia aukerekin. Adibidez, API hutsegite-tolerantzia bermatzeko, jarri karga-banatzaile bat APIaren aurrean. Langileen eskalatzea haien kopurua handituz lortzen da.

Eskema osoko puntu ahulak RabbitMQ eta MariaDB dira. Haien arkitekturak artikulu bereizi bat merezi du. Artikulu honetan, API akatsen tolerantzian zentratu nahi nuke.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
OpenStack aplikazioen arkitektura: hodeiko plataforma baten oreka eta hutsegiteen tolerantzia

HAProxy karga-banatzailea ExaBGP-rekin akatsen aurkakoa bihurtzea

Gure APIak eskalagarriak, azkarrak eta akatsen aurkako tolerantzia dutela ziurtatzeko, karga-banatzaile bat instalatu genuen. HAProxy aukeratu genuen. Nire ustez, gure beharretarako beharrezko ezaugarri guztiak ditu: OSI geruza anitzetan karga-banatzea, kudeaketa-interfazea, malgutasuna eta eskalagarritasuna, karga-banatzeko metodo ugari eta saio-taulen euskarria.

Konpondu beharreko lehenengo arazoa karga-banatzailearen beraren akatsen tolerantzia zen. Karga-banatzailea instalatzeak hutsegite-puntu bakarra sortzen du: karga-banatzaileak huts egiten badu, zerbitzua erori egiten da. Hori ekiditeko, HAProxy erabili genuen ExaBGP-rekin batera.

ExaBGP-k zerbitzuaren osasun-egiaztapen mekanismo bat gaitzen du. Mekanismo hau erabili genuen HAProxy-ren osasuna egiaztatzeko eta, arazoak sortuz gero, BGP-tik HAProxy zerbitzua desgaitzeko.

ExaBGP+HAProxy Eskema

  1. Beharrezko softwarea, ExaBGP eta HAProxy, hiru zerbitzaritan instalatzen dugu.
  2. Zerbitzari bakoitzean loopback interfazea sortzen dugu.
  3. Hiru zerbitzarietan, IP helbide zuri bera erregistratzen dugu interfaze honetan.
  4. IP helbide zuria ExaBGP bidez iragartzen zaio Interneti.

Huts-tolerantzia hiru zerbitzarietatik IP helbide bera iragarriz lortzen da. Sarearen ikuspuntutik, helbide bera hiru hurrengo jauzi ezberdinetatik eskura daiteke. Bideratzaileak hiru ibilbide berdin ikusten ditu, lehentasun handiena duen ibilbidea hautatzen du bere metrikan oinarrituta (normalean ibilbide bera), eta trafikoa zerbitzarietako bakarrera bideratzen da.

HAProxy-rekin arazoak izanez gero edo zerbitzariaren akats bat izanez gero, ExaBGP-k ibilbidea iragartzeari uzten dio, eta trafikoa leunki aldatzen da beste zerbitzari batera.

Horrela, orekatzailearen akatsen tolerantzia lortu genuen.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
HAProxy karga-banatzailearen akatsen tolerantzia

Konfigurazioa ez zen perfektua: HAProxy-ren babeskopia nola egin ikasi genuen, baina ez genuen ikasi karga zerbitzuen artean nola banatu. Beraz, konfigurazioa apur bat zabaldu genuen, IP helbide publiko anitzetan karga orekatzea aldatuz.

DNS oinarritutako karga-orekatzea gehi BGP

Gure HAProxy-aren aurreko karga-banaketaren arazoa konpondu gabe dago oraindik. Hala ere, nahiko erraz konpondu daiteke, gurearekin egin genuen bezala.

Hiru zerbitzari orekatzeko, hiru IP helbide publiko eta DNS zahar ona beharko dituzu. Helbide horietako bakoitza HAProxy bakoitzaren loopback interfazeari esleitzen zaio eta internetera iragartzen da.

OpenStack-ek zerbitzu-katalogo bat erabiltzen du baliabideak kudeatzeko, eta honek zerbitzu bakoitzerako API amaiera-puntua definitzen du. Katalogo honetan, domeinu-izen bat zehazten dugu —public.infra.mail.ru—, DNS bidez hiru IP helbide ezberdinetara ebazten dena. Horrek hiru helbideen arteko karga-orekatzea dakar DNS erabiliz.

Hala ere, IP helbide zuriak iragartzerakoan zerbitzarien hautaketa lehentasunak kontrolatzen ez ditugunez, hau ez da oraindik orekatzen. Normalean, zerbitzari bakarra hautatuko da IP helbide altuenean oinarrituta, eta beste biak inaktibo egongo dira, BGP-n metrikarik zehaztu gabe dagoelako.

ExaBGP bidez ibilbideak banatzen hasi gara metrika desberdinekin. Karga-orekatzaile bakoitzak hiru IP helbide zuriak iragartzen ditu, baina horietako bat, karga-orekatzaile horren IP helbide nagusia, gutxieneko metrikarekin iragartzen da. Beraz, hiru karga-orekatzaileak martxan dauden bitartean, lehenengo IP helbiderako eskaerak lehenengo karga-orekatzailera joaten dira, bigarrenerako eskaerak bigarrenera, eta hirugarrenerako eskaerak hirugarrenera.

Zer gertatzen da karga-banatzaileetako batek huts egiten duenean? Karga-banatzaileren batek huts egiten badu ere, beste biek bere helbide nagusia iragartzen jarraitzen dute, eta trafikoa haien artean birbanatzen da. Horrela, erabiltzaileari IP helbide ugari ematen dizkiogu DNS bidez. DNS eta metrika desberdinen bidez orekatuz, karga-banaketa uniformea ​​lortzen dugu hiru karga-banatzaileen artean, akatsen tolerantzia mantenduz.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
HAProxy karga-orekatzea DNS eta BGPrekin

ExaBGP eta HAProxy arteko elkarrekintza

Beraz, zerbitzariaren geldialdiaren aurkako failover babesa ezarri dugu ibilbideen iragarpenak etenez. Baina HAProxy zerbitzariaren hutsegiteaz gain beste arrazoi batzuengatik ere gera daiteke: administrazio-erroreak, barne-zerbitzuen hutsegiteak. Kasu hauetan ere karga-banatzaile eroria karga-banaketatik kendu nahi dugu, beraz, mekanismo desberdin bat behar dugu.

Beraz, aurreko eskema zabalduz, ExaBGP eta HAProxy arteko bihotz-taupada bat inplementatu dugu. Hau ExaBGP eta HAProxy arteko interakzioaren software inplementazio bat da, non ExaBGP-k script pertsonalizatuak erabiltzen dituen aplikazioen egoera egiaztatzeko.

Horretarako, ExaBGP konfigurazioan HAProxy-ren egoera egiaztatu dezakeen osasun-egiaztatzaile bat konfiguratu behar duzu. Gure kasuan, osasun-backend bat konfiguratu dugu HAProxy-n, eta ExaBGP aldean, GET eskaera soil batekin egiaztatzen dugu. Iragarpena gelditzen bada, HAProxy erorita dagoela dirudi eta ez da beharrezkoa iragartzea.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
HAProxy Osasun-egiaztapena

HAProxy parekideak: saioaren sinkronizazioa

Hurrengo egin beharreko gauza saioak sinkronizatzea izan zen. Banatutako karga-orekatzaileekin lan egitean, bezeroen saioaren informazioa gordetzea zaila da. Baina HAProxy hori egin dezakeen karga-orekatzaile gutxietako bat da, bere Peers funtzioari esker, zeinak saio-taula HAProxy prozesu desberdinen artean partekatzea ahalbidetzen baitu.

Orekatzeko metodo desberdinak daude: sinpleak, adibidez joan-robin, eta hedatuak, non bezeroaren saioa gogoratzen den eta zerbitzari berera bideratzen diren aldi bakoitzean. Bigarren aukera inplementatu nahi genuen.

HAProxy-k stick taulak erabiltzen ditu bezeroen saioak gordetzeko. Bezeroaren iturburu IP helbidea, hautatutako helburu helbidea (backend) eta zerbitzuaren informazio batzuk gordetzen dituzte. Stick taulak normalean iturburu-IP eta helmuga-IP bikoteak gordetzeko erabiltzen dira, eta hori bereziki erabilgarria da karga-orekatzaile desberdin batera aldatzean erabiltzaile-saioaren testuingurua transferitu ezin duten aplikazioetarako, hala nola RoundRobin karga-orekatze moduan.

HAProxy prozesu ezberdinen artean mugitzen irakatsiz stick taulari (karga-orekatzea horien artean gertatzen dena), gure karga-orekatzaileek stick taula multzo bakar batekin lan egin ahal izango dute. Horri esker, bezeroen sarearen failover ezin hobea izango da karga-orekatzaile batek huts egiten badu, eta bezeroen saioak aurretik hautatutako backend berdinetan zerbitzatzen jarraituko dute.

Behar bezala funtzionatzeko, saioa ezartzen den karga-banatzailearen iturburu-IP helbidearekin duen arazoa konpondu behar da. Gure kasuan, loopback interfazeko helbide dinamikoa da hau.

Parekideek baldintza jakin batzuetan bakarrik funtzionatzen dute behar bezala. Zehazki, TCP denbora-mugak nahikoa luzeak izan behar dira, edo aldaketa nahikoa azkarra izan behar da TCP saioa amaitu ez dadin. Hala ere, horrek aldaketa ezin hobea ahalbidetzen du.

Teknologia bera erabiliz eraikitako IaaS zerbitzu bat dugu. OpenStack-erako karga-banatzailea zerbitzu gisa, Octavia izenekoa. Bi HAProxy prozesutan oinarritzen da eta parekideentzako euskarri natiboa du. Zerbitzu honetarako bikainak direla frogatu dute.

Irudiak eskematikoki erakusten du pareko taulen mugimendua hiru HAProxy instantzien artean, eta konfigurazio bat ematen da nola konfigura daitekeen ilustratzeko:

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
HAProxy parekideak (saioen sinkronizazioa)

Antzeko eskema bat ezartzen baduzu, arretaz probatu beharko zenuke. Ez dago bermatuta %100ean funtzionatuko duenik. Baina gutxienez ez dituzu zure taula itsaskorrak galduko bezeroaren iturburu IP helbidea gogoratu behar duzunean.

Bezero beraren aldibereko eskaeren kopurua mugatzea

Edozein zerbitzu publikok, gure APIak barne, eskaera uholde baten menpe egon daiteke. Arrazoiak asko alda daitezke, erabiltzaileen erroreetatik hasi eta eraso zuzenduetaraino. Aldian-aldian IP DDoS erasoak jasaten ditugu. Bezeroek askotan akatsak egiten dituzte beren scriptetan, mini-DDoS erasoak eraginez.

Nolanahi ere, segurtasun neurri gehigarriak beharrezkoak dira. Irtenbide ageriko bat API eskaeren kopurua mugatzea eta eskaera gaiztoak prozesatzen CPU denbora alferrik galtzea saihestea da.

Murrizketa hauek ezartzeko, HAProxy-n eraikitako abiadura-mugak erabiltzen ditugu, stick taula berdinak erabiliz. Mugak nahiko erraz konfiguratzen dira eta erabiltzaile batek egin ditzakeen API eskaera kopurua mugatzeko aukera ematen dute. Algoritmoak eskaerak egiten diren iturburu IP helbidea gogoratzen du eta erabiltzaile bakoitzeko aldibereko eskaera kopurua mugatzen du. Jakina, zerbitzu bakoitzerako batez besteko API karga-profila kalkulatu dugu eta balio hori baino 10 aldiz handiagoa den muga bat ezarri dugu. Egoera gertutik kontrolatzen jarraitzen dugu, pultsuari eutsi diezaiogun.

Nola funtzionatzen du honek praktikan? Bezeroak ditugu etengabe gure APIak autoeskalatzeko erabiltzen dituztenak. Goizean berrehun edo hirurehun makina birtual sortzen dituzte eta arratsaldean ezabatzen dituzte. OpenStack-entzat, makina birtual bat sortzeak, batez ere PaaS zerbitzuekin, gutxienez 1000 API eskaera behar ditu, zerbitzuen arteko elkarrekintzak APIen bidez ere gertatzen baitira.

Zeregin-transferentzia hauek karga nahiko handia sortzen dute. Karga hori ebaluatu genuen, eguneroko gailurrak bildu genituen, hamar aldiz handitu genituen, eta hori bihurtu zen gure abiadura-muga. Erlazionatuta gaude. Askotan ikusten ditugu bot-ak eta eskanerrak exekutatu daitezkeen CGA script-ik dugun ikusteko, eta aktiboki kentzen ditugu.

Nola eguneratu zure kode-basea erabiltzaileentzat modu errazean

Akatsen tolerantzia ere ezartzen dugu kodearen hedapen prozesu mailan. Akatsak gertatzen dira hedapenetan zehar, baina zerbitzuaren erabilgarritasunean duten eragina minimizatu daiteke.

Gure zerbitzuak etengabe eguneratzen ditugu eta ziurtatu behar dugu kode-basearen eguneraketak erabiltzaileei eragin gabe egiten direla. Hori lortu dugu HAProxy-ren kudeaketa-gaitasunak aprobetxatuz eta Graceful Shutdown gure zerbitzuetan ezarriz.

Arazo hau konpontzeko, orekatzailearen kudeaketa eta zerbitzua "zuzen" itzaltzea bermatu behar zen:

  • HAProxy-rekin, kudeaketa estatistika fitxategi baten bidez egiten da, funtsean HAProxy konfigurazio fitxategian definitutako socket bat dena. Komandoak stdio bidez pasa dakizkioke. Hala ere, gure konfigurazio kudeaketa tresna nagusia Ansible da, beraz, HAProxy kudeatzeko modulua dauka barnean, eta aktiboki erabiltzen dugu.
  • Gure API eta Motor zerbitzu gehienek itzaltze egokia onartzen dute: itzaltzean, uneko zeregina, HTTP eskaera bat edo beste zerbitzu-zeregin bat izan, amaitu arte itxaroten dute. Gauza bera gertatzen da langile batekin. Badaki egiten ari den zeregin guztiak eta guztiak behar bezala amaitu direnean amaitzen da.

Bi puntu hauei esker, gure hedapen seguruko algoritmoak honelako itxura du.

  1. Garatzaileak kode pakete berri bat sortzen du (gure kasuan, RPM da), garapen ingurunean probatzen du, stage ingurunean probatzen du eta stage biltegian uzten du.
  2. Garatzaileak "artefaktuen" deskribapen oso zehatza duen hedapen-zeregin bat ezartzen du: pakete berriaren bertsioa, funtzionalitate berriaren deskribapena eta hedapenaren beste xehetasun batzuk, beharrezkoak badira.
  3. Sistemaren administratzaileak abiarazten du eguneratzea. Ansible-ren eskuliburua exekutatzen du, eta honek, aldi berean, honako hau egiten du:
    • Pakete bat hartzen du etapa biltegitik eta paketearen bertsioa eguneratzen du ekoizpen biltegian, horren arabera.
    • Eguneratzen ari den zerbitzurako backend-en zerrenda bat sortzen du.
    • HAProxy-n eguneratzen ari den lehen zerbitzua itzaltzen du eta bere prozesuak amaitu arte itxaroten du. Itxiera egokiari esker, uneko bezero eskaera guztiak behar bezala burutzen direla ziurtatzen dugu.
    • APIa eta langileak guztiz gelditu eta HAProxy desaktibatu ondoren, kodea eguneratzen da.
    • Ansible-k zerbitzuak abiarazten ditu.
    • Zerbitzu bakoitzerako, "helduleku" espezifikoak erabiltzen dira, unitate-probak egiteko aurrez definitutako gako-proba sorta baten aurka. Kode berriaren oinarrizko egiaztapena gertatzen da.
    • Aurreko urratsean akatsik aurkitu ez bada, backenda aktibatzen da.
    • Hurrengo atzeko planora pasa gaitezen.
  4. Atzeko plano guztiak eguneratu ondoren, proba funtzionalak egiten dira. Falta badira, garatzaileak inplementatu dituen funtzionalitate berriak berrikusten ditu.

Honek inplementazioa osatzen du.

Mail.ru Cloud Solutions plataforman akatsekiko tolerantzia duen web arkitektura nola ezartzen den
Zerbitzuaren eguneratze zikloa

Sistema honek ez luke funtzionatuko arau bakarra ez bagenu. Bertsio zaharra eta berria aldi berean mantentzen ditugu. Hasieratik bertatik ziurtatzen dugu, softwarearen garapenean zehar, zerbitzuaren datu-basean aldaketak egin arren, aurreko kodea ez dela hautsiko. Ondorioz, kode-basea pixkanaka eguneratzen da.

Ondorioa

Akatsen aurkako web arkitekturari buruzko nire gogoetak partekatuz, bere puntu nagusiak errepikatu nahi nituzke:

  • akats fisikoen tolerantzia;
  • sareko akatsen tolerantzia (orekatzaileak, BGP);
  • erabilitako eta garatutako softwarearen akatsen tolerantzia.

Funtzionamendu egonkorra izan dezazuela guztiok!

Iturria: www.habr.com

Gehitu iruzkin berria