Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Andrey Salnikov-en 2016aren hasierako txostenaren transkripzioa irakurtzea gomendatzen dizut "Postgresql-en puztu egiten duten aplikazioetako akats tipikoak"

Txosten honetan, aplikazioen kodea diseinatzeko eta idazteko fasean sortzen diren aplikazioetan akats nagusiak aztertuko ditut. Eta Postgresql-en puztu egiten duten akatsak bakarrik hartuko ditut. Oro har, hau zure sistema osoaren errendimenduaren amaieraren hasiera da, nahiz eta hasieran horretarako baldintzarik ez zegoen ikusten.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Pozik ongi etorria emateaz! Txosten hau ez da nire lankidearen aurrekoa bezain teknikoa. Txosten hau backend sistemen garatzaileei zuzenduta dago, bezero kopuru nahiko handia dugulako. Eta guztiek akats berdinak egiten dituzte. Haien berri emango dizut. Akats horiek zein gauza larri eta txar eragiten dituzten azalduko dut.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zergatik egiten dira akatsak? Bi arrazoirengatik egiten dira: ausaz, agian funtzionatuko du eta datu-basearen eta aplikazioaren arteko mailan, baita datu-basean bertan ere, gertatzen diren mekanismo batzuen ezezagutzagatik.

Hiru adibide emango dizkizut, gauzak nola txartu ziren irudi ikaragarriekin. Bertan gertatzen den mekanismoaren berri labur-labur kontatuko dizuet. Eta nola aurre egin, noiz gertatu ziren eta zein prebentzio-metodo erabili akatsak saihesteko. Tresna osagarrien berri emango dizut eta esteka erabilgarriak emango dizkizut.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Proba datu-base bat erabili nuen non bi taula nituen. Plaka bat bezero kontuekin, bestea kontu hauetako transakzioekin. Eta nolabaiteko maiztasunarekin kontu hauen saldoak eguneratzen ditugu.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Plakaren hasierako datuak: nahiko txikia da, 2 MB. Datu-baserako eta zehazki zeinurako erantzuteko denbora ere oso ona da. Eta karga nahiko ona - 2 eragiketa segundoko plakaren arabera.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta txosten honen bitartez grafikoak erakutsiko dizkizuet, gertatzen ari dena argi uler dezazuen. Beti egongo dira 2 diapositiba grafikoekin. Lehen diapositiba zerbitzarian orokorrean gertatzen dena da.

Eta egoera honetan, benetan seinale txiki bat dugula ikusten dugu. Indizea txikia da 2 MBrekin. Hau da ezkerreko lehenengo grafikoa.

Zerbitzariaren batez besteko erantzun denbora ere egonkorra eta laburra da. Hau goiko eskuineko grafikoa da.

Beheko ezkerreko grafikoak transakzio luzeenak erakusten ditu. Transakzioak azkar egiten direla ikusten dugu. Eta autohutsak oraindik ez du funtzionatzen hemen, hasierako proba bat zelako. Lanean jarraituko du eta baliagarria izango zaigu.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Bigarren diapositiba beti probatzen ari den plakari eskainiko zaio. Egoera honetan, bezeroaren kontu-saldoak etengabe eguneratzen ditugu. Eta ikusten dugu eguneratze-eragiketa baten batez besteko erantzun-denbora nahiko ona dela, milisegundo bat baino gutxiago. Prozesadorearen baliabideak (goiko eskuineko grafikoa da) ere berdin eta nahiko txikiak kontsumitzen direla ikusten dugu.

Beheko eskuineko grafikoak erakusten du zenbat memoria operatibo eta diskotik igarotzen garen eguneratu aurretik nahi dugun lerroaren bila. Eta zeinuaren araberako operazio kopurua segundoko 2 da, hasieran esan bezala.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta orain tragedia bat dugu. Arrazoiren batengatik aspaldi ahaztutako transakzio bat dago. Arrazoiak normalean hutsalak dira:

  • Ohikoenetako bat da aplikazioaren kodean kanpoko zerbitzu batean sartzen hasi garela. Eta zerbitzu honek ez digu erantzuten. Hau da, transakzio bat ireki, datu-basean aldaketa bat egin eta aplikaziotik posta irakurtzera edo gure azpiegituraren barruko beste zerbitzu batera pasa ginen, eta arrazoiren batengatik ez digu erantzuten. Eta gure saioa noiz konponduko den ezezaguna den egoera batean trabatuta dago.
  • Bigarren egoera gure kodean arrazoiren batengatik salbuespen bat gertatu denean da. Eta salbuespenean ez dugu transakzioaren itxiera prozesatu. Eta zintzilik saio batekin amaitu genuen transakzio ireki batekin.
  • Eta azkena ere nahiko ohikoa den kasua da. Hau kalitate baxuko kodea da. Zenbait esparruk transakzio bat irekitzen dute. Zintzilikatzen da, eta baliteke aplikazioan ez jakitea zintzilik duzula.

Nora eramaten dute horrelako gauzak?

Gure taulak eta indizeak izugarri hazten hasten diren arte. Hau bloat efektu bera da. Datu-baseari dagokionez, horrek esan nahi du datu-basearen erantzun-denbora asko handituko dela eta datu-basearen zerbitzariaren karga handituko dela. Eta, ondorioz, gure aplikazioak sufrituko du. Zeren eta zure kodean 10 milisegundo eman badituzu datu-baseari egindako eskaeran, 10 milisegundo zure logikan, orduan zure funtzioak 20 milisegundo behar izan ditu osatzeko. Eta orain zure egoera guztiz tristea izango da.

Eta ea zer gertatzen den. Beheko ezkerreko grafikoak transakzio luze luze bat dugula erakusten du. Eta goiko ezkerreko grafikoari erreparatzen badiogu, ikusiko dugu gure taularen tamaina bat-batean bi megabytetik 300 megabytera igaro dela. Aldi berean, taulako datu kopurua ez da aldatu, hau da, nahiko zabor kopuru handia dago bertan.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zerbitzariaren batez besteko erantzun-denborari buruzko egoera orokorra ere hainbat magnitude aldatu da. Hau da, zerbitzariko eskaera guztiak guztiz jaisten hasi ziren. Eta, aldi berean, barneko Postgres prozesuak abiarazi ziren auto-hutsean, zerbait egin nahian eta baliabideak kontsumitzen ari direnak.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zer gertatzen da gure seinalearekin? Berdina. Zeinuaren araberako gure batez besteko erantzun-denbora hainbat magnitude-ordena igo da. Zehazki kontsumitutako baliabideei dagokienez, prozesadorearen karga asko handitu dela ikusten dugu. Hau goiko eskuineko grafikoa da. Eta handitu egin da prozesadoreak behar denaren bila alferrikako lerro mordoa ordenatu behar duelako. Hau beheko eskuineko grafikoa da. Eta ondorioz, segundoko gure dei kopurua oso nabarmen jaisten hasi zen, datu-baseak ez baitzuen astirik izan eskaera kopuru bera prozesatzeko.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Bizitzara itzuli behar dugu. Sarean sartzen gara eta transakzio luzeek arazoak ekartzen dituztela jakiten dugu. Transakzio hau aurkitu eta hiltzen dugu. Eta dena normal bihurtzen ari zaigu. Dena behar bezala funtzionatzen du.

Lasaitu ginen, baina pixka bat igaro ondoren aplikazioak ez duela larrialdiaren aurretik funtzionatzen nabaritzen hasten gara. Oraindik motelago prozesatzen dira eskaerak, eta nabarmen motelago. Bat eta erdi edo bi aldiz motelagoa zehazki nire adibidean. Zerbitzariaren karga ere istripua gertatu aurretik zegoena baino handiagoa da.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta galdera: "Zer gertatzen ari da une honetan oinarriarekin?" Eta oinarriarekin honako egoera gertatzen da. Transakzio-taulan gelditu egin dela ikus dezakezu eta ez dagoela epe luzerako transakziorik. Baina seinalearen tamaina izugarri handitu zen istripuan zehar. Eta ordutik ez dira gutxitu. Oinarriaren batez besteko denbora egonkortu egin da. Eta badirudi erantzunak behar bezala datozela guretzat onargarria den abiaduran. Auto-hutsean aktiboago bihurtu zen eta seinalearekin zerbait egiten hasi zen, datu gehiago bahetu behar dituelako.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zehazki, kontuak dituen proba-plakaren arabera, non saldoak aldatzen ditugun: eskaera baten erantzun-denbora normaltasunera itzuli dela dirudi. Baina errealitatean aldiz bat eta erdi handiagoa da.

Eta prozesadorearen kargaren arabera, ikusten dugu prozesadorearen karga ez dela itzuli behar den baliora hutsegitearen aurretik. Eta arrazoiak beheko eskuineko grafikoan daude hain zuzen. Bertan memoria kopuru bat bilatzen ari dela ikus daiteke. Hau da, behar den lerroa aurkitzeko, datu-basearen zerbitzariaren baliabideak xahutzen ditugu alferrikako datuak sailkatu bitartean. Segundoko transakzio kopurua egonkortu egin da.

Orokorrean ona, baina egoera zena baino okerragoa da. Garbitu datu-basearen degradazioa datu-base honekin lan egiten duen gure aplikazioaren ondorioz.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta hor gertatzen ari dena ulertzeko, aurreko txostenean egon ez bazina, har dezagun orain teoria apur bat. Barne-prozesuari buruzko teoria. Zergatik autoen xurgagailua eta zer egiten du?

Literalki laburki ulertzeko. Uneren batean mahai bat daukagu. Taulan errenkadak ditugu. Lerro hauek aktiboak, biziak eta orain behar ditugunak izan daitezke. Irudian berdez markatuta daude. Eta badaude epe mugak dagoeneko landuak, eguneratuak eta horietan sarrera berriak agertu direnak. Eta datu-baserako jada ez direla interesgarriak markatuta daude. Baina taulan daude Postgres ezaugarri bat dela eta.

Zergatik behar duzu autoaren xurgagailua? Noizbait, auto-vacuum dator, datu-basera sartzen da eta galdetzen dio: "Mesedez, eman datu-basean irekita dagoen transakzio zaharrenaren id. Datu-baseak id hau itzultzen du. Eta auto-hutsean, horretan oinarrituz, taulako lerroak ordenatzen ditu. Eta ikusten badu lerro batzuk askoz transakzio zaharragoek aldatu zituztela, orduan bertan datu berriak idatziz etorkizunean berrerabili ahal izango ditugun lerro gisa markatzeko eskubidea du. Hau atzeko prozesu bat da.

Une honetan, datu-basearekin lanean jarraitzen dugu eta taulan aldaketa batzuk egiten jarraitzen dugu. Eta berrerabili ditzakegun lerro hauetan datu berriak idazten ditugu. Eta horrela ziklo bat lortzen dugu, hau da, lerro zahar hil batzuk agertzen diren denbora guztian bertan, horien ordez behar ditugun lerro berriak idazten ditugu. Eta hau PostgreSQL-k funtzionatzeko egoera normala da.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zer gertatu zen istripuan? Nola gertatu zen prozesu hau han?

Seinale bat genuen egoera batzuetan, batzuk biziak, beste batzuk hildako lerroak. Iritsi da autoen hutsa. Datu-baseari galdetu dio zein den gure transakzio zaharrena eta zein den bere id. Id hau jaso nuen, duela ordu asko izan zitekeena, duela hamar minutu agian. Zure datu-basean duzun kargaren araberakoa da. Eta berrerabilitzat markatu ahal zituen lerroen bila joan zen. Eta ez nuen halako lerrorik aurkitu gure taulan.

Baina momentu honetan mahaiarekin lanean jarraitzen dugu. Zerbait egiten dugu bertan, eguneratzen dugu, datuak aldatzen ditugu. Zer egin behar du datu-baseak une honetan? Lehendik dagoen taularen amaieran lerro berriak gehitzea beste aukerarik ez du. Eta horrela gure mahaiaren tamaina hazten hasten da.

Egia esan, marra berdeak behar ditugu lan egiteko. Baina halako arazo batean, lerro berdeen ehunekoa oso baxua da mahai osoan zehar.

Eta kontsulta bat exekutatzen dugunean, datu-baseak lerro guztietatik pasatu behar du: bai gorria bai berdea, nahi den lerroa aurkitzeko. Eta alferrikako datuekin taula bat puztzearen efektuari "bloat" deitzen zaio, eta horrek ere gure diskoko espazioa jaten du. Gogoratu, 2 MB zela, 300 MB bihurtu zela? Orain aldatu megabyte gigabyte eta azkar galduko dituzu diskoko baliabide guztiak.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zein ondorio izan ditzakegu guretzat?

  • Nire adibidean, taula eta indizea 150 aldiz hazi dira. Gure bezero batzuek kasu larriagoak izan dituzte diskoko lekurik gabe geratzen hasi zirenean.
  • Taulen tamaina bera ez da inoiz murriztuko. Auto-hutsean, kasu batzuetan, mahaiaren buztana moztu dezake hildako lerroak bakarrik badaude. Baina etengabeko biraketa dagoenez, lerro berde bat amaieran izoztu daiteke eta ez eguneratu, beste guztiak plakaren hasieran nonbait idatziko dira. Baina gertaera hain zaila da zure mahaia bera tamainaz txikituko den, beraz, ez zenuke espero behar.
  • Datu-baseak alferrikako lerro sorta bat ordenatu behar du. Eta disko baliabideak xahutzen ditugu, prozesadorearen baliabideak eta elektrizitatea xahutzen ditugu.
  • Eta horrek zuzenean eragiten dio gure aplikazioari, zeren hasieran 10 milisegundo eskabidean, 10 milisegundo gure kodean pasatzen bagenuen, orduan kraskaduran segundu bat ematen hasi ginen eskaeran eta 10 milisegundo kodean, hau da, ordena bat. aplikazioaren errendimenduaren magnitudea murriztu da. Eta istripua konpondu zenean, 20 milisegundo pasatzen hasi ginen eskaera batean, 10 milisegundo kode batean. Horrek esan nahi du produktibitatea aldiz eta erdi jaitsi dugula oraindik. Eta hau guztia izoztu zen transakzio batengatik da, agian gure erruagatik.
  • Eta galdera: β€œNola berreskuratu dezakegu dena?”, horrela dena ondo joan dadin eta eskaerak istripua baino lehen bezain azkar etor daitezen.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Horretarako lan-ziklo jakin bat egiten da.

Lehenik eta behin puztuta dauden taula problematikoak aurkitu behar ditugu. Ulertzen dugu taula batzuetan grabazioa aktiboagoa dela, beste batzuetan ez hain aktiboa. Eta horretarako luzapena erabiltzen dugu pgstattuple. Luzapen hau instalatuta, nahiko puztuta dauden taulak aurkitzen lagunduko dizuten kontsultak idatzi ditzakezu.

Taula hauek aurkitu ondoren, konprimitu behar dituzu. Dagoeneko badaude horretarako tresnak. Gure enpresan hiru tresna erabiltzen ditugu. Lehenengoa VACUUM FULL integratua da. Ankerra, gogorra eta errukigabea da, baina batzuetan oso erabilgarria da. Pg_repack ΠΈ pgcompactable - Hirugarrenen utilitateak dira taulak konprimitzeko. Eta datu-basea arreta handiagoz tratatzen dute.

Zuretzako erosoago denaren arabera erabiltzen dira. Baina amaieran kontatuko dizut honi buruz. Gauza nagusia hiru tresna daudela da. Asko dago aukeran.

Dena zuzendu eta dena ondo dagoela ziurtatu ondoren, etorkizunean egoera hori nola prebenitzen jakin behar dugu:

  • Nahiko erraz ekidin daiteke. Master zerbitzarian saioen iraupena kontrolatu behar duzu. Batez ere saio arriskutsuak inaktibo dauden transakzio egoeran. Hauek dira transakzio bat ireki, zerbait egin eta utzi, edo besterik gabe zintzilikatu, kodean galdu zirenak.
  • Eta zuretzat, garatzaile gisa, garrantzitsua da zure kodea probatzea egoera hauek sortzen direnean. Ez da zaila egitea. Egiaztapen erabilgarria izango da. Transakzio luzeekin lotutako "haurren" arazo ugari saihestuko dituzu.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Grafiko hauetan, kasu honetan VACUUM FULL-ekin seinaletik pasa ondoren datu-basearen zeinua eta portaera nola aldatu diren erakutsi nahi dizut. Hau ez da produkzioa niretzat.

Taularen tamaina berehala itzuli zen bere funtzionamendu-egoera arruntera, megabyte pare batekoa. Horrek ez zuen asko eragin zerbitzariaren batez besteko erantzun denboran.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Baina bereziki gure proba-seinalerako, non kontu-saldoak eguneratu genituen, ikusten dugu seinaleko datuak eguneratzeko eskaeraren batez besteko erantzun-denbora larrialdi aurreko mailetara murriztu zela. Eskaera hau osatzeko prozesadoreak kontsumitutako baliabideak hutsegite aurreko mailetara ere jaitsi ziren. Eta beheko eskuineko grafikoak erakusten du orain behar dugun lerroa berehala aurkitzen dugula, mahaia konprimitu aurretik zeuden lerro hilen piloetatik pasatu gabe. Eta eskaeraren batez besteko denbora maila berean geratu zen gutxi gorabehera. Baina hemen dut, hobeto esanda, akats bat nire hardwarean.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Hor amaitzen da lehen istorioa. Ohikoena da. Eta denei gertatzen zaie, bezeroaren esperientzia eta programatzaileak zenbatekoak diren kontuan hartu gabe. Lehenago edo beranduago hau gertatzen da.

Bigarren istorioa, karga banatu eta zerbitzariaren baliabideak optimizatzen ditugu

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

  • Dagoeneko hazi gara eta mutil serio bihurtu gara. Eta ulertzen dugu erreplika bat daukagula eta karga orekatzea ondo legokeela: Maisuari idatzi, eta erreplikatik irakurri. Eta normalean egoera hori txosten edo ETL batzuk prestatu nahi ditugunean sortzen da. Eta negozioak oso pozik daude honekin. Benetan hainbat txosten nahi ditu analitika konplexu askorekin.
  • Txostenek ordu asko behar dituzte, analitika konplexuak ezin direlako milisegundotan kalkulatu. Guk, ausartak bezala, kodea idazten dugu. Txertatzeko aplikazioan Masterrean grabazioa egiten dugu, eta erreplikaren gaineko txostenak exekutatzen ditugu.
  • Karga banatzea.
  • Dena primeran funtzionatzen du. Handiak gara.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta nolakoa da egoera hau? Zehazki, grafiko hauetan, transakzioen iraupenaren erreplikaren transakzioen iraupena ere gehitu dut. Gainerako grafiko guztiek zerbitzari maisuari soilik egiten diote erreferentzia.

Ordurako, nire txosten-taula hazi egin zen. Gehiago daude. Zerbitzariaren batez besteko erantzun denbora egonkorra dela ikusten dugu. Ikusten dugu erreplikan iraupen luzeko transakzio bat dugula 2 orduz. Hildako lerroak prozesatzen dituen autohutsean funtzionamendu lasaia ikusten dugu. Eta dena ondo dago gurekin.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zehazki, probatutako plakaren arabera, kontuen saldoak eguneratzen jarraitzen dugu bertan. Eta eskaerei erantzuteko denbora egonkorra ere badugu, baliabideen kontsumo egonkorra. Dena ondo dago gurekin.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Dena ondo dago txosten hauek erreplikaren gatazka baten ondorioz erreproduzitzen hasten diren unera arte. Eta tiro egiten dute aldizka.

Sarean sartzen gara eta hau zergatik gertatzen den irakurtzen hasten gara. Eta irtenbide bat aurkitzen dugu.

Lehenengo irtenbidea erreplikazioaren latentzia handitzea da. Badakigu gure txostenak 3 orduko iraupena duela. Erreplikazioaren atzerapena 3 ordutan ezarri dugu. Dena abiarazten ari gara, baina oraindik ere arazoak izaten jarraitzen dugu batzuetan bertan behera uzten diren txostenekin.

Dena perfektua izatea nahi dugu. Gehiago igotzen gara. Eta Interneten ezarpen polita aurkitu dugu - hot_standby_feedback. Piztu dezagun. Hot_standby_feedback-ek Masterreko hutsune automatikoari eusteko aukera ematen digu. Horrela, erreplikazio-gatazkak erabat kentzen ditugu. Eta dena ondo funtzionatzen digu txostenekin.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta zer gertatzen ari da une honetan Master zerbitzariarekin? Eta arazo osoa dugu Master zerbitzariarekin. Orain grafikoak ikusten ari gara bi ezarpen hauek gaituta ditudanean. Eta ikusten dugu gure erreplikaren saioa nolabait Master zerbitzariaren egoeran eragiten hasi zela. Efektua du autohutsean pausatu zuelako, eta horrek lerro hilak garbitzen ditu. Gure mahaiaren tamainak gora egin du berriro. Datu-base osoan kontsultak egiteko batez besteko denborak ere gora egin zuen. Auto-husgailuak apur bat estutu ziren.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Zehazki, gure plakatik, horren gaineko datuen eguneraketak ere zerura salto egin zuela ikusten dugu. PUZaren kontsumoa ere asko handitu da. Hildako eta alferrikako lerro ugari bizitzen ari gara berriro. Eta zeinu honen erantzun-denbora eta transakzio kopurua jaitsi egin dira.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Nolakoa izango da lehen zertaz ari nintzen ez badakigu?

  • Arazoen bila hasten gara. Lehenengo zatian arazoak topatu baditugu, badakigu transakzio luze baten ondorioz izan daitekeela eta Masterrera joan. Arazo bat dugu Masterrean. Saltxitxak hura. Berotzen da, bere Load Average ehun bat ingurukoa da.
  • Bertan eskaerak motelak dira, baina ez dugu ikusten denbora luzeko transakziorik. Eta ez dugu ulertzen zer den kontua. Ez dugu ulertzen nora begiratu.
  • Zerbitzariaren ekipoak egiaztatzen ditugu. Agian gure erasoa erori egin zen. Agian gure memoria makila erreta dago. Bai, edozer gerta daiteke. Baina ez, zerbitzariak berriak dira, dena ondo dabil.
  • Denak exekutatzen ari dira: administratzaileak, garatzaileak eta zuzendaria. Ezerk ez du laguntzen.
  • Eta momentu batean dena bat-batean hasten da zuzentzen.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Une honetan, gure erreplikaren eskaera prozesatu eta utzi egin zen. Txostena jaso dugu. Negozioak pozik daude oraindik. Ikus dezakezunez, gure seinalea berriro hazi da eta ez da txikituko. Saioen grafikoan, transakzio luze honen zati bat utzi dut erreplika batetik, egoera egonkortu arte zenbat denbora behar den kalkula dezazun.

Saioa amaitu da. Eta denbora pixka bat igaro ondoren zerbitzaria ordena gehiago edo gutxiago dator. Eta zerbitzari Nagusiko eskaeren batez besteko erantzun-denbora normaltasunera itzultzen da. Izan ere, azkenik, auto-husgailuak aukera duelako hildako lerro hauek garbitu eta markatzeko. Eta bere lana egiten hasi zen. Eta zein azkar egiten duen, hain azkar jarriko gara ordena.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Probatutako tabletaren arabera, non kontuen saldoak eguneratzen ditugun, irudi bera ikusten dugu. Kontua eguneratzeko batez besteko denbora ere pixkanaka normalizatzen ari da. Prozesadoreak kontsumitzen dituen baliabideak ere murrizten dira. Eta segundoko transakzio kopurua normaltasunera itzultzen da. Baina berriro normaltasunera itzuli gara, ez istripua gertatu aurretik ginen berdina.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Edonola ere, errendimenduaren beherapena lortzen dugu, lehen kasuan bezala, aldiz eta erdi edo bi aldiz, eta batzuetan gehiago.

Badirudi dena ondo egin dugula. Zama banatu. Ekipamendua ez dago inaktibo. Eskaerak gure gogoaren arabera banatu genituen, baina hala ere dena gaizki atera zen.

  • Ez al duzu gaitu hot_standby_feedback? Bai, ez da gomendagarria arrazoi bereziki sendorik gabe piztea. Bihurketa honek zerbitzari Nagusiari zuzenean eragiten diolako eta bertan auto-hutsean funtzionamendua eten egiten duelako. Erreplika batzuetan gaituta eta hura ahaztuta, Maisua hil dezakezu eta aplikazioarekin arazo handiak izan ditzakezu.
  • Max_standby_streaming_delay handitu nahi duzu? Bai, txostenetarako hori egia da. Hiru orduko txostena baduzu eta ez baduzu huts egin nahi errepikapen-gatazkak direla eta, handitu atzerapena. Epe luzeko txosten batek ez du inoiz behar oraintxe bertan datu-basera iritsi diren datuak. Hiru orduz badaukazu, datu zahar batzuetarako exekutatzen ari zara. Eta zuretzat, hiru orduko atzerapena edo sei ordukoa izateak ez du inolako alderik izango, baina txostenak koherentziaz jasoko dituzu eta ez duzu erortzeko arazorik izango.
  • Jakina, errepliketan saio luzeak kontrolatu behar dituzu, batez ere erreplika batean hot_standby_feedback gaitzea erabakitzen baduzu. Edozer gerta daitekeelako. Erreplika hau garatzaileari eman genion eskaerak proba ditzan. Eskaera zoro bat idatzi zuen. Abian jarri zuen eta tea edatera joan zen, eta maisu finkatua lortu genuen. Edo agian aplikazio okerra jarri dugu bertan. Egoerak askotarikoak dira. Erreplikei buruzko saioak Masterrean bezain arretaz kontrolatu behar dira.
  • Eta errepliketan kontsulta azkarrak eta luzeak badituzu, kasu honetan hobe da zatitzea karga banatzeko. Hau streaming_delay-rako esteka da. Azkarren kasuan, izan erreplika bat atzerapen txiki batekin. Iraupen luzeko txosten-eskaeretarako, izan 6 orduz edo egunean atzeratu daitekeen erreplika bat. Egoera guztiz normala da.

Ondorioak modu berean ezabatzen ditugu:

  • Mahai puztuak aurkitzen ditugu.
  • Eta konprimitzen dugu komeni zaigun tresnarik erosoenarekin.

Bigarren istorioa hemen amaitzen da. Goazen hirugarren istoriora.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Guretzat ere nahiko ohikoa migrazioa egiten dugun.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

  • Edozein software produktu hazten ari da. Horretarako baldintzak aldatzen ari dira. Nolanahi ere, garatu nahi dugu. Eta gertatzen da taulako datuak eguneratu behar ditugula, hots, gure garapenaren barruan sartzen ari garen funtzionalitate berriaren migrazioari dagokionez eguneraketa bat exekutatzeko.
  • Datu-formatu zaharra ez da asegarria. Demagun orain bigarren taulara jotzen dugula, non kontu hauetan transakzioak ditudan. Eta demagun errublotan zeudela, eta zehaztasuna handitzea eta kopeketan egitea erabaki genuen. Eta horretarako eguneraketa bat egin behar dugu: transakzioaren zenbatekoa duen eremua ehunez biderkatu.
  • Gaur egungo munduan, datu-baseen bertsioak kontrolatzeko tresna automatizatuak erabiltzen ditugu. Demagun Liquibase. Gure migrazioa bertan erregistratzen dugu. Gure proba oinarrian probatzen dugu. Dena ondo dago. Eguneraketa egiten ari da. Lana blokeatzen du denbora batez, baina datu eguneratuak jasotzen ditugu. Eta funtzionalitate berriak abiarazi ditzakegu honetan. Dena probatu eta egiaztatu zen. Dena baieztatu zen.
  • Planifikatutako lana egin genuen eta migrazioa egin genuen.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Hona hemen zure aurrean aurkeztutako eguneraketa duen migrazioa. Hauek nire kontuko transakzioak direnez, plaka 15 GB zen. Eta lerro guztiak eguneratzen ditugunez, taularen tamaina bikoiztu egin dugu eguneraketarekin, lerro guztiak berridatzi ditugulako.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Migrazioan, ezin izan dugu ezer egin plaka honekin, hari egindako eskaera guztiak ilaran jarri zirelako eta eguneratze hau amaitu arte itxaron zutelako. Baina hemen zure arreta erakarri nahi dizut ardatz bertikalean dauden zenbakiez. Hau da, 5 milisegundo inguruko eta prozesadorearen karga baino lehen eskaera-denbora bat dugu, diskoaren memoria irakurtzeko bloke-eragiketa kopurua 7,5 baino txikiagoa da.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Migrazioa egin genuen eta berriro arazoak izan genituen.

Migrazioa arrakastatsua izan zen, baina:

  • Funtzio zaharrak denbora gehiago behar du osatzeko.
  • Mahaia tamainaz hazi zen berriro.
  • Zerbitzariaren karga lehen baino handiagoa izan zen berriro.
  • Eta, noski, oraindik ondo funtzionatzen zuen funtzionalitatearekin moldatzen ari gara, pixka bat hobetu dugu.

Eta hau berriro puztuta dago, gure bizitzak berriro hondatzen dituena.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Hemen erakusten dut taula, aurreko bi kasuetan bezala, ez dela bere aurreko tamainara itzuliko. Zerbitzariaren batez besteko karga egokia dela dirudi.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta kontuen mahaira jotzen badugu, ikusiko dugu batez besteko eskaera-denbora bikoiztu egin dela mahai honetarako. Prozesadorearen karga eta memorian ordenatutako lerro kopurua 7,5etik gora egin zuten, baina txikiagoa izan zen. Eta 2 aldiz egin zuen salto prozesadoreen kasuan, 1,5 aldiz bloke-eragiketen kasuan, hau da, zerbitzariaren errendimenduan degradazioa lortu genuen. Eta, ondorioz, gure aplikazioaren errendimenduaren degradazioa. Aldi berean, dei kopurua gutxi gorabehera maila berean mantendu zen.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Eta hemen gauza nagusia migrazio horiek nola egin behar diren ulertzea da. Eta egin behar dira. Migrazio hauek nahiko koherente egiten ditugu.

  • Horrelako migrazio handiak ez dira automatikoki gertatzen. Beti kontrolpean egon behar dute.
  • Pertsona aditu baten gainbegiratzea beharrezkoa da. Zure taldean DBA bat baduzu, utzi DBAk egiten. Bere lana da. Hala ez bada, utz dezala esperientziarik handiena duen pertsonari, datu-baseekin lan egiten dakienak.
  • Datu-basearen eskema berri bat, zutabe bat eguneratzen badugu ere, etapaka prestatzen dugu beti, hau da, aldez aurretik aplikazioaren bertsio berria zabaldu aurretik:
  • Eremu berriak gehitzen dira eta horietan datu eguneratuak erregistratuko ditugu.
  • Datuak eremu zaharretik eremu berrira transferitzen ditugu zati txikitan. Zergatik ari gara hau? Lehenik eta behin, prozesu honen prozesua kontrolatzen dugu beti. Badakigu dagoeneko hainbeste lote transferitu ditugula eta asko geratzen zaizkigula.
  • Eta bigarren efektu positiboa da lote bakoitzaren artean transakzioa ixten dugula, berri bat irekitzen dugula, eta horri esker, automatikoki hutsuneak plakaren arabera funtzionatzen du, berrerabiltzeko epeak markatzen ditugu.
  • Aplikazioa exekutatzen ari den bitartean agertuko diren lerroetarako (aplikazio zaharra martxan dugu oraindik), eremu berrietan balio berriak idazten dituen trigger bat gehitzen dugu. Gure kasuan, balio zaharraren ehun batez biderkatzea da.
  • Guztiz burugogorra bagara eta eremu bera nahi badugu, migrazio guztiak amaitutakoan eta aplikazioaren bertsio berri bat zabaldu aurretik, eremuak izena aldatuko dugu. Zaharrei asmatutako izen bat ematen zaie, eta eremu berriei zaharrei izena ematen diete.
  • Eta horren ondoren soilik aplikazioaren bertsio berri bat abiarazten dugu.

Eta, aldi berean, ez dugu puzketarik lortuko eta ez dugu errendimendu aldetik sufrituko.

Hemen amaitzen da hirugarren istorioa.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

https://github.com/dataegret/pg-utils/blob/master/sql/table_bloat.sql

https://github.com/dataegret/pg-utils/blob/master/sql/table_bloat_approx.sql

Eta orain lehen istorioan aipatu ditudan tresnei buruzko xehetasun apur bat gehiago.

Bloat bilatu aurretik, luzapena instalatu behar duzu pgstattuple.

Kontsultarik egin beharrik izan ez dezazun, dagoeneko idatzi ditugu kontsulta hauek gure lanean. Erabili ditzakezu. Hemen bi eskaera daude.

  • Lehenengoak denbora asko behar du lan egiteko, baina taulako bloat balio zehatzak erakutsiko dizkizu.
  • Bigarrenak azkarrago funtzionatzen du eta oso eraginkorra da taularen arabera puztuta dagoen edo ez azkar ebaluatu behar duzunean. Eta ulertu behar duzu bloat beti dagoela Postgres taula batean. Hau MVCC ereduaren ezaugarri bat da.
  • Eta %20ko puzketa normala da mahaietan kasu gehienetan. Hau da, ez zenuke kezkatu eta taula hau konprimitu behar.

Alferrikako datuekin puztuta dauden taulak nola identifikatzen asmatu genuen.

Orain puztuta nola konpondu:

  • Tableta txikia eta disko onak baditugu, hau da, gigabyte arteko tablet batean, nahiko posible da VACUUM FULL erabiltzea. Mahai gainean blokeo esklusibo bat hartuko du segundo batzuetan eta ados, baina dena azkar eta gogor egingo du. Zer egiten du VACUUM FULL-ek? Mahaiaren blokeo esklusibo bat hartzen du eta taula zaharretako zuzeneko errenkadak berridazten ditu taula berrira. Eta amaieran ordezkatzen ditu. Fitxategi zaharrak ezabatzen ditu eta zaharrak berriekin ordezkatzen ditu. Baina bere lanak irauten duen bitartean, blokeo esklusibo bat hartzen du mahai gainean. Horrek esan nahi du ezin duzula ezer egin taula honekin: ez idatzi, ez irakurri, ez aldatu. Eta VACUUM FULL-ek diskoko espazio gehigarria behar du datuak idazteko.
  • Hurrengo tresna pg_repack. Bere printzipioan, VACUUM FULL-en oso antzekoa da, fitxategi zaharretako datuak berridazten dituelako eta taulan ordezkatzen dituelako. Baina, aldi berean, ez du blokeo esklusiborik hartzen mahai gainean bere lanaren hasieran, baizik eta fitxategiak ordezkatzeko datuak prest dituen unean bakarrik hartzen du. Bere disko-baliabideen eskakizunak VACUUM FULL-en antzekoak dira. Disko espazio gehigarria behar duzu, eta hori batzuetan kritikoa da terabyte-taulak badituzu. Eta nahiko prozesadore gosea da I/O-rekin aktiboki lan egiten duelako.
  • Hirugarren erabilgarritasuna da pgcompactable. Kontu handiagoa du baliabideekin, printzipio apur bat ezberdinen arabera funtzionatzen duelako. pgcompacttable-ren ideia nagusia zuzeneko errenkada guztiak taularen hasierara eramaten dituela da, taulako eguneraketak erabiliz. Eta gero hutsean ibiltzen da mahai honetan, badakigulako hasieran errenkadak biziak ditugula eta amaieran hildakoak. Eta hutsak berak mozten du isats hori, hau da, ez du diskoko leku gehigarri handirik behar. Eta, aldi berean, oraindik estutu daiteke baliabideen aldetik.

Dena tresnekin.

Postgresql-en puzketak eragiten dituzten aplikazioetako errore tipikoak. Andrei Salnikov

Barruan sakontzeari dagokionez bloat gaia interesgarria iruditzen bazaizu, hona hemen esteka erabilgarriak:

Gehiago saiatu nintzen garatzaileei beldurrezko istorio bat erakusten, haiek baitira datu-baseen bezero zuzenak eta ekintzek zer eta zertara eramaten duten ulertu behar dutelako. Espero dut lortu izana. Eskerrik asko zure arretagatik!

Zure galderak

Eskerrik asko erreportajeagatik! Arazoak nola identifikatu ditzakezun hitz egin duzu. Nola abisatu daitezke? Hau da, egoera bat izan nuen non eskaerak zintzilikatzen ziren ez bakarrik kanpoko zerbitzu batzuetara sartzen zirelako. Hauek uztartze basati batzuk besterik ez ziren. Eskaera txiki eta kaltegabe batzuk zeuden egun batez zintzilik, eta gero txorakeria batzuk egiten hasi ziren. Hau da, zuk deskribatzen duzunaren oso antzekoa. Nola egin horren jarraipena? Eseri eta etengabe ikusi zein eskaera trabatuta dagoen? Nola ekidin daiteke hori?

Kasu honetan, zure enpresaren administratzaileen zeregina da, ez zertan DBArena.

Administratzailea naiz.

PostgreSQL-k pg_stat_activity izeneko ikuspegia du, eta zintzilik dauden kontsultak erakusten ditu. Eta zenbat denboran zintzilikatzen den ikus dezakezu.

Sartu eta begiratu behar al dut 5 minuturo?

Konfiguratu cron eta egiaztatu. Epe luzerako eskaera baduzu, idatzi gutun bat eta kitto. Hau da, ez duzu begiekin begiratu behar, automatizatu egin daiteke. Gutun bat jasoko duzu, erreakzionatzen duzu. Edo automatikoki tiro egin dezakezu.

Ba al dago hori gertatzeko arrazoi agerikorik?

batzuk zerrendatu ditut. Beste adibide konplexuago batzuk. Eta elkarrizketa bat egon daiteke denbora luzez.

Eskerrik asko erreportajeagatik! pg_repack utilitateari buruz argitu nahi nuen. Ez badu blokeo esklusiborik egiten, orduan...

Blokeo esklusibo bat egiten du.

... orduan datuak gal ditzaket. Nire aplikazioak ez al du ezer grabatu behar denbora horretan?

Ez, ondo funtzionatzen du taularekin, hau da, pg_repack-ek lehenik dauden zuzeneko lerro guztiak transferitzen ditu. Berez, taulan nolabaiteko sarrera bat gertatzen da bertan. Zaldi-buztan hau botatzen ari da.

Hau da, benetan egiten du azkenean?

Azkenean, blokeo esklusibo bat hartzen du fitxategi hauek trukatzeko.

VACUUM FULL baino azkarragoa izango da?

VACUUM FULL, hasi bezain pronto, berehala blokeo esklusibo bat hartu zuen. Eta dena egin arte, ez dio joaten utziko. Eta pg_repack-ek blokeo esklusibo bat hartzen du fitxategia ordezkatzeko unean soilik. Momentu honetan ez duzu bertan idatziko, baina datuak ez dira galduko, dena ondo egongo da.

Kaixo! Autoen hutsunearen funtzionamenduaz hitz egin duzu. Grafiko bat zegoen gelaxka gorri, hori eta berdeekin. Hau da, horiak - ezabatu gisa markatu zituen. Eta, ondorioz, zerbait berria idatz daiteke horietan?

Bai. Postgres-ek ez ditu lerroak ezabatzen. Badauka halako berezitasun bat. Lerro bat eguneratzen badugu, zaharra ezabatuta bezala markatu dugu. Lerro hau aldatu duen transakzioaren id-a agertzen da hor, eta lerro berri bat idazten dugu. Eta irakur daitezkeen saioak ditugu. Noizbait nahiko zahartu egiten dira. Eta auto-hutsean funtzionatzen duenaren funtsa lerro hauetatik igarotzen dela eta beharrezkoak ez direla markatzen ditu. Eta datuak gainidatzi ditzakezu bertan.

Ulertzen dut. Baina ez da horri buruzko galdera. Ez nuen bukatu. Demagun mahai bat dugula. Tamaina aldakorreko eremuak ditu. Eta zerbait berria sartzen saiatzen banaiz, baliteke gelaxka zaharrean sartzea.

Ez, edonola ere lerro osoa hor eguneratzen da. Postgres-ek bi datuak biltegiratzeko eredu ditu. Datu motaren artean hautatzen du. Taulan zuzenean gordetzen diren datuak daude, eta tos datuak ere badaude. Hauek datu kopuru handiak dira: testua, json. Plater bereizietan gordetzen dira. Eta tablet hauen arabera, istorio bera gertatzen da puzketekin, hau da, dena berdina da. Bereiz zerrendatzen dira.

Eskerrik asko erreportajeagatik! Onargarria al da adierazpenen denbora-muga-kontsultak erabiltzea iraupena mugatzeko?

Oso onargarria. Hau nonahi erabiltzen dugu. Eta gure zerbitzurik ez dugunez, urruneko laguntza eskaintzen dugu, bezero asko ditugu. Eta denak guztiz pozik daude honekin. Hau da, egiaztatzen duten cron lanak ditugu. Saioen iraupena bezeroarekin adosten da, eta horren aurretik ez gara ados jartzen. Minutu bat izan daiteke, 10 minutu izan daitezke. Oinarriaren kargaren eta bere helburuaren araberakoa da. Baina denok erabiltzen dugu pg_stat_activity.

Eskerrik asko erreportajeagatik! Zure txostena nire aplikazioetan aplikatzen saiatzen ari naiz. Eta badirudi transakzio bat nonahi hasten dugula, eta argi eta garbi nonahi osatzen dugula. Salbuespenen bat baldin badago, atzerapena gertatzen da oraindik. Eta orduan hasi nintzen pentsatzen. Azken finean, baliteke transakzioa ez hastea esplizituki. Hau seguruenik neskari iradokizun bat da. Erregistro bat eguneratzen badut, transakzioa PostgreSQL-n hasiko da eta konexioa deskonektatzen denean bakarrik amaituko da?

Orain aplikazio mailari buruz ari bazara, erabiltzen ari zaren kontrolatzailearen araberakoa da, erabiltzen ari den ORMaren arabera. Ezarpen asko daude bertan. Konpromiso automatikoa gaituta baduzu, transakzio bat bertan hasiko da eta berehala ixten da.

Hau da, eguneratu ondoren berehala ixten da?

Ezarpenen araberakoa da. Ezarpen bat izendatu nuen. Konpromiso automatikoa da. Nahiko arrunta da. Gaituta badago, transakzioa ireki eta itxi egin da. "Hasi transakzioa" eta "amaitu transakzioa" esplizituki esan ez baduzu, baina eskaera bat abiarazi besterik ez duzu saioan.

Kaixo! Eskerrik asko erreportajeagatik! Imajina dezagun hazten eta hanpatzen ari den datu-base bat dugula eta gero zerbitzariko lekua agortzen dela. Egoera hau konpontzeko tresnarik ba al dago?

Zerbitzariko espazioa behar bezala kontrolatu behar da.

Adibidez, DBA tea hartzera joan zen, estazio batean zegoen, etab.

Fitxategi-sistema bat sortzen denean, gutxienez segurtasun-kopia-espazio bat sortzen da, non datuak idazten ez diren.

Zer gertatzen da guztiz zero azpian badago?

Bertan espazio erreserbatua deitzen da, hau da, askatu daiteke eta sortu den tamainaren arabera, espazio librea lortzen duzu. Berez ez dakit zenbat dauden. Eta beste kasu batean, entregatu diskoak, eragiketa berreraikitzaile bat egiteko tokia izan dezazun. Behar ez duzula ziurtatzen duzun taula ezabatu dezakezu.

Ba al dago beste tresnarik?

Beti eskuz egindakoa da. Eta lokalean argi geratzen da zer den onena bertan egitea, datu batzuk kritikoak direlako eta beste batzuk ez-kritikoak. Eta datu-base bakoitzerako eta horrekin lan egiten duen aplikaziorako, negozioaren araberakoa da. Beti lokalean erabakitzen da.

Eskerrik asko erreportajeagatik! Bi galdera ditut. Lehenik eta behin, transakzioak itsatsita daudenean, bai tablespace tamaina eta indizearen tamaina hazten direla erakusten duten diapositibak erakutsi dituzu. Eta txostenean aurrerago tableta paketatzen duten utilitate mordoa zegoen. Zer gertatzen da indizearekin?

Horiek ere ontziratzen dituzte.

Baina hutsak ez dio indizeari eragiten?

Batzuk indize batekin lan egiten dute. Adibidez, pg_rapack, pgcompacttable. Hutsak indizeak birsortzen ditu eta haiei eragiten die. VACUUM FULL-ekin dena gainidaztea da, hau da, denekin funtzionatzen du.

Eta bigarren galdera. Ez dut ulertzen zergatik erreplikei buruzko txostenak erreplikaren beraren hainbeste mende dauden. Iruditu zitzaidan txostenak irakurtzen direla, eta erreplikatzea idazten dela.

Zerk eragiten du errepikapen-gatazka bat? Master bat dugu zein prozesu egiten diren. Autoen hutsunea dugu martxan. Zer egiten du benetan hutsune automatiko batek? Lerro zahar batzuk mozten ari da. Une honetan lerro zahar hauek irakurtzen dituen erreplikan eskaera bat badugu, eta Masterrean autohutsak lerro hauek gainidazteko posible gisa markatu dituen egoera gertatu bada, gainidatzi ditugu. Eta datu-pakete bat jaso dugu, eskaerak erreplikan behar dituen lerro horiek berridatzi behar ditugunean, erreplikazio-prozesuak konfiguratu duzun denbora-mugarako itxarongo du. Eta gero PostgreSQL-k erabakiko du zer den garrantzitsuagoa. Eta erreplikazioa garrantzitsuagoa da berarentzat eskaera baino, eta eskaera filmatuko du erreplikan aldaketa horiek egiteko.

Andrey, galdera bat daukat. Aurkezpenean erakutsi dituzun grafiko zoragarri hauek, zure erabilgarritasun moduko baten lanaren emaitza al dira hauek? Nola egin ziren grafikoak?

Hau zerbitzu bat da Okmetroa.

Hau produktu komertziala al da?

Bai. Hau produktu komertziala da.

Iturria: www.habr.com

Gehitu iruzkin berria