{"id":37956,"date":"2019-10-31T22:20:47","date_gmt":"2019-10-31T19:20:47","guid":{"rendered":"https:\/\/prohoster.info\/blog\/newsql-nosql-acid\/"},"modified":"2019-10-31T22:20:47","modified_gmt":"2019-10-31T19:20:47","slug":"newsql-nosql-acid","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/newsql-nosql-acid","title":{"rendered":"NewSQL = NoSQL + ACID","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/973145efa566bca10ffe7ba95733a1d5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nDo nedavnega je bilo v Odnoklassnikah shranjenih pribli\u017eno 50 TB podatkov, ki so se obdelovali v realnem \u010dasu, v SQL Serverju. Za tako obse\u017eno koli\u010dino je skoraj nemogo\u010de zagotoviti hitro, zanesljivo in odpornosti na napake podatkovno sredi\u0161\u010de, ki uporablja SQL DBMS. Obi\u010dajno v takih primerih uporabijo eno od NoSQL shranjevanj, vendar vsega ni mogo\u010de prenesti v NoSQL: nekateri entiteti zahtevajo zagotovila ACID transakcij. <\/p>\n<p>To nas je pripeljalo do uporabe NewSQL shranjevanja, torej DBMS, ki zagotavlja odpornost na napake, skalabilnost in hitro delovanje NoSQL sistemov, hkrati pa ohranja obi\u010dajna ACID zagotovila klasi\u010dnih sistemov. Delujo\u010dih industrijskih sistemov tega novega razreda je malo, zato smo tak sistem razvili sami in ga uvedli v industrijsko uporabo. <\/p>\n<p>Kako to deluje in kaj smo dosegli \u2014 preberite spodaj.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nDanes mese\u010dna javnost Odnoklassnikov obsega ve\u010d kot 70 milijonov unikatnih obiskovalcev. Mi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.similarweb.com\/top-websites\/category\/internet-and-telecom\/social-network\">smo med petimi<\/a><\/noindex> najve\u010djimi dru\u017ebenimi omre\u017eji na svetu in v dvajseterici spletnih strani, na katerih uporabniki pre\u017eivijo najve\u010d \u010dasa. Infrastruktura 'OK' obdeluje zelo visoke obremenitve: ve\u010d kot milijon HTTP zahtevkov na sekundo na fronte. Deli stre\u017eni\u0161kega parka, ki \u0161teje ve\u010d kot 8000 enot, so name\u0161\u010deni blizu skupaj \u2014 v \u0161tirih moskovskih podatkovnih centrih, kar omogo\u010da zagotavljanje omre\u017ene zamude manj kot 1 ms med njimi.<\/p>\n<p>Uporabljamo Cassandro od leta 2010, od razli\u010dice 0.6. Danes deluje ve\u010d deset klasterjev. Najhitrej\u0161i klaster obdeluje ve\u010d kot 4 milijone operacij na sekundo, najve\u010dji pa shranjuje 260 TB. <\/p>\n<p>Vendar so to obi\u010dajni NoSQL klasterji, ki se uporabljajo za shranjevanje <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A1%D0%BE%D0%B3%D0%BB%D0%B0%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B2_%D0%BA%D0%BE%D0%BD%D0%B5%D1%87%D0%BD%D0%BE%D0%BC_%D1%81%D1%87%D1%91%D1%82%D0%B5\">slabo usklajenih<\/a><\/noindex> podatkov. \u017deleli smo zamenjati glavno usklajeno shranjevanje, Microsoft SQL Server, ki se je uporabljal od ustanovitve 'Odnoklassnikov'. Shranjevanje je bilo sestavljeno iz ve\u010d kot 300 sistemov SQL Server Standard Edition, ki so vsebovali 50 TB podatkov \u2014 poslovnih entitet. Ti podatki se spreminjajo v okviru ACID transakcij in zahtevajo <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">visoko usklajenost<\/a><\/noindex>.<\/p>\n<p>Za razdelitev podatkov po vozli\u0161\u010dih SQL Serverja smo uporabljali tako vertikalno kot horizontalno <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Partition_(database)\">particioniranje<\/a><\/noindex> (sharding). Zgodovina nas je nau\u010dila preproste sheme sharding podatkov: vsaki entiteti je bil dodeljen \u017eeton \u2014 funkcija ID entitete. Entitete z enakim \u017eetonom so bile name\u0161\u010dene na enem SQL stre\u017eniku. Razmerje tipa master-detail je bilo izvedeno tako, da sta bili \u017eetona glavne in podrejene zveze vedno enaki in se nahajali na istem stre\u017eniku. V dru\u017ebenih omre\u017ejih skoraj vse zapise ustvarja uporabnik \u2014 to pomeni, da so vsi podatki uporabnika v okviru enega funkcionalnega podsistema shranjeni na enem stre\u017eniku. V poslovni transakciji so skoraj vedno sodelovale tabele istega SQL stre\u017enika, kar je omogo\u010dalo zagotovitev usklajenosti podatkov s pomo\u010djo lokalnih ACID transakcij, brez potrebe po uporabi <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">po\u010dasi in nezanesljivo<\/a><\/noindex> porazdeljenih ACID transakcij.<\/p>\n<p>Zaradi sharding in za pospe\u0161itev delovanja SQL:<\/p>\n<ul>\n<li>Ne uporabljamo tujih klju\u010dnih omejitev, ker se ob sharding ID entitete lahko nahaja na drugem stre\u017eniku.<\/li>\n<li>Ne uporabljamo shranjenih postopkov in spro\u017eilcev zaradi dodatne obremenitve procesorja DBMS.<\/li>\n<li>Ne uporabljamo JOIN-ov zaradi vsega zgoraj navedenega in \u0161tevilnih naklju\u010dnih branj z diska.<\/li>\n<li>Izven transakcij za zmanj\u0161anje medsebojnega blokiranja uporabljamo raven izolacije Read Uncommitted.<\/li>\n<li>Izvajamo samo kratke transakcije (v povpre\u010dju kraj\u0161e od 100 ms).<\/li>\n<li>Ne uporabljamo ve\u010dvrstnih UPDATE in DELETE zaradi velikega \u0161tevila medsebojnih blokad - posodabljamo samo eno vrstico.<\/li>\n<li>Zahteve vedno izvajamo samo po indeksih - zahteva s platenjem za popolno pregledovanje tabele za nas pomeni preobremenitev baze podatkov in njen neuspeh.<\/li>\n<\/ul>\n<p>\nTi koraki so omogo\u010dili, da smo iz SQL stre\u017enikov iztisnili skoraj maksimum zmogljivosti. Vendar pa se je te\u017eav pojavljalo vse ve\u010d. Oglejmo si jih.<\/p>\n<h2>Te\u017eave s SQL<\/h2>\n<p><\/p>\n<ul>\n<li>Ker smo uporabljali lastni sharding, so novi shardi dodajali skrbniki ro\u010dno. Vso to \u010das so raz\u0161irljive replike podatkov obravnavale zahteve. <\/li>\n<li>Z rastjo \u0161tevila zapisov v tabeli se zmanj\u0161uje hitrost vstavljanja in modificiranja, pri dodajanju indeksov obstoje\u010di tabeli se hitrost ve\u010dkrat zmanj\u0161a, ustvarjanje in ponovno ustvarjanje indeksov pa poteka s \u010dasom izpada.<\/li>\n<li>Obstoj majhnega \u0161tevila Windows za SQL Server v produkciji ote\u017euje upravljanje infrastrukture<\/li>\n<\/ul>\n<p>\nToda najve\u010dja te\u017eava je \u2014 <\/p>\n<h2>Odporna zasnova<\/h2>\n<p>\nKlasi\u010dni SQL poslu\u017eitelj ima lo\u0161u otpornost na kvarove. Pretpostavimo da imate samo jedan server baze podataka, i on otka\u017ee svake tri godine. U tom periodu web stranica ne radi 20 minuta, \u0161to je prihvatljivo. Ako imate 64 servera, web stranica ne radi svake tri sedmice. A ako imate 200 servera, web stranica ne radi svake sedmice. To je problem. <\/p>\n<p>\u0160ta se mo\u017ee u\u010diniti za pobolj\u0161anje otpornosti na kvarove SQL poslu\u017eitelja? Wikipedia nam predla\u017ee da izgradimo <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/High-availability_cluster\">visoko dostupni klaster<\/a><\/noindex>: gdje u slu\u010daju otkaza bilo kojeg od komponenti postoji duplikat.<\/p>\n<p>To zahtijeva skup skupog hardvera: brojne duplikate, opti\u010dka vlakna, skladi\u0161ta koja se dijele, a i uklju\u010divanje rezervi radi nepouzdanosti: oko 10% uklju\u010divanja zavr\u0161ava otkazom rezervnog \u010dvora koji pra\u0107a glavni \u010dvor. <\/p>\n<p>No, glavni nedostatak takvog visoko dostupnog klastera je nulta dostupnost u slu\u010daju otkaza data centra u kojem se nalazi. 'Odnoklassniki' imaju \u010detiri data centa, i neophodno je osigurati rad u slu\u010daju potpunog kvara u jednom od njih.<\/p>\n<p>Za to bismo mogli primijeniti <noindex><a rel=\"nofollow\" href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms151196.aspx\">Multi-Master<\/a><\/noindex> replikaciju, ugra\u0111enu u SQL Server. Ovo rje\u0161enje je znatno skuplje zbog tro\u0161kova softvera i pati od dobro poznatih problema s replikacijom \u2014 nepredvidivih ka\u0161njenja transakcija pri sinkronoj replikaciji i ka\u0161njenja u primjeni replikacija (i, kao posljedica, izgubljenih modifikacija) pri asinkronoj. Pretpostavljaju\u0107i <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/replication\/transactional\/peer-to-peer-conflict-detection-in-peer-to-peer-replication\">ru\u010dno rje\u0161avanje sukoba<\/a><\/noindex> \u010dini ovu opciju potpuno neprihvatljivom za nas.<\/p>\n<p>Svi ovi problemi zahtijevali su radikalno rje\u0161enje i zapo\u010deli smo s detaljnom analizom. Ovdje se trebamo upoznati s onim \u0161to SQL Server u su\u0161tini radi \u2014 transakcijama.<\/p>\n<h2>Jednostavna transakcija<\/h2>\n<p>\nRazmotri\u0107emo najjednostavniju, s aspekta aplikacijskog SQL programera, transakciju: dodavanje fotografije u album. Albumi i fotografije se \u010duvaju u razli\u010ditim tabelama. Album ima broja\u010d javnih fotografija. Tada se ta transakcija razla\u017ee na sljede\u0107e korake: <\/p>\n<ol>\n<li>Zaklju\u010davamo album po klju\u010du.<\/li>\n<li>Kreiramo zapis u tabeli fotografija. <\/li>\n<li>Ako fotografija ima javni status, pove\u0107avamo broja\u010d javnih fotografija u albumu, a\u017euriramo zapis i potvr\u0111ujemo transakciju.<\/li>\n<\/ol>\n<p>\nIli u obliku pseudokoda:<\/p>\n<pre><code>TX.start(\"Albums\", id);\nAlbum album = albums.lock(id);\nPhoto photo = photos.create(\u2026);\n\nif (photo.status == PUBLIC) {\n    album.incPublicPhotosCount();\n}\nalbum.update();\n\nTX.commit();<\/code><\/pre>\n<p>\nVidimo, da je najpogostej\u0161i scenarij poslovne transakcije \u2014 branje podatkov iz baze podatkov v pomnilnik stre\u017enika aplikacij, nekaj spremeniti in shraniti nove vrednosti nazaj v bazo podatkov. Obi\u010dajno v taki transakciji posodobimo ve\u010d entitet, ve\u010d tabel. <\/p>\n<p>Med izvajanjem transakcije lahko pride do konkuren\u010dne modifikacije istih podatkov iz drugega sistema. Na primer, Antispam lahko ugotovi, da je uporabnik nekako sumljiv in zato vse fotografije uporabnika ne bi smele biti ve\u010d javne, treba bi jih bilo poslati na moderacijo, kar pomeni, da je treba spremeniti photo.status na nek drug vrednost in ustrezno posodobiti \u0161tevce. O\u010ditno je, da \u010de bo ta operacija potekala brez garancij atomarnosti in izolacije konkurirajo\u010dih modifikacij, kot v <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>, bo rezultat vsekakor neustrezal \u2014 ali bo \u0161tevec fotografij prikazoval napa\u010dno vrednost, ali pa ne bodo vse fotografije poslane na moderacijo. <\/p>\n<p>Tak\u0161nega kodeksa, ki manipulira z razli\u010dnimi poslovnimi entitetami v okviru ene transakcije, je bilo v vsem obdobju obstoja Odnoklassnikov napisanega zelo veliko. Po izku\u0161njah migracij na NoSQL z <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">Eventual Consistency<\/a><\/noindex> vemo, da najve\u010dje te\u017eave (in \u010dasovne obremenitve) povzro\u010da potreba po razvijanju kode, usmerjene v vzdr\u017eevanje skladnosti podatkov. Zato smo glavne zahteve za novo skladi\u0161\u010de \u0161teli za zagotavljanje pravih ACID transakcij za aplikacijsko logiko. <\/p>\n<p>Druge, prav tako pomembne, zahteve so bile:<\/p>\n<ul>\n<li>Ob odpovedi podatkovnega centra morata biti dostopna tako branje kot pisanje v novo skladi\u0161\u010de.<\/li>\n<li>Ohranitev trenutne hitrosti razvoja. To pomeni, da bi moralo biti pri delu z novim skladi\u0161\u010dem koli\u010dina kode pribli\u017eno enaka, ne bi smelo biti potrebe po dodajanju ne\u010desa v skladi\u0161\u010de, razvijanju algoritmov za re\u0161evanje konfliktov, vzdr\u017eevanju sekundarnih indeksov itd. <\/li>\n<li>Hitrost delovanja novega skladi\u0161\u010da mora biti dovolj visoka, tako pri branju podatkov kot pri obdelavi transakcij, kar u\u010dinkovito pomeni neprimernost akademsko strogih, univerzalnih, a po\u010dasnih re\u0161itev, kot so na primer <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">dvofazni commit<\/a><\/noindex>.<\/li>\n<li>Samodejno prilagajanje v realnem \u010dasu. <\/li>\n<li>Uporaba obi\u010dajnih poceni stre\u017enikov, brez potrebe po nakupu eksoti\u010dne opreme. <\/li>\n<li>Mo\u017enost razvoja shrambe z viri podjetja. Z drugimi besedami, prednostso se lahko dajo lastnim ali odprtokodnim re\u0161itvam, najbolje na Java.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Re\u0161itve, re\u0161itve<\/h2>\n<p>\nAnalizirajo\u010d mo\u017ene re\u0161itve, smo pri\u0161li do dveh mo\u017enih arhitektur:<\/p>\n<p>Prva je, da vzamemo katerikoli SQL stre\u017enik in realiziramo potrebno odpornost na napake, mehanizem prilagajanja, odpornost na napake grozd, re\u0161evanje konfliktov in distribuirane, zanesljive in hitre ACID transakcije. To mo\u017enost smo ocenili kot precej nenavadno in delovno zahtevno.<\/p>\n<p>Druga mo\u017enost je, da vzamemo pripravljeno NoSQL shrambo z realiziranim prilagajanjem, odpornim grozdom na napake, re\u0161evanjem konfliktov in sami realiziramo transakcije in SQL. Na prvi pogled se zdi naloga realizacije SQL, \u010deprav ne omenjamo ACID transakcij, naloga, ki traja leta. A nato smo spoznali, da je skupek mo\u017enosti SQL, ki jih dejansko uporabljamo, dale\u010d od ANSI SQL, prav tako dale\u010d kot <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Apache_Cassandra#Cassandra_Query_Language\">Cassandra CQL<\/a><\/noindex> dale\u010d od ANSI SQL. Ko smo se \u0161e bolj pozorno ozrli na CQL, smo spoznali, da je dovolj blizu temu, kar potrebujemo.<\/p>\n<h2>Cassandra in CQL<\/h2>\n<p>\nTorej, kaj je zanimivega pri Cassandri, kak\u0161ne mo\u017enosti ponuja?<\/p>\n<p>Prvi\u010d, tukaj lahko ustvarjate tabele s podporo za razli\u010dne tipe podatkov, lahko izvajate SELECT ali UPDATE po primarnem klju\u010di.<\/p>\n<pre><code>CREATE TABLE photos (id bigint KEY, owner bigint,\u2026);\nSELECT * FROM photos WHERE id=?;\nUPDATE photos SET \u2026 WHERE id=?;<\/code><\/pre>\n<p>\nZa zagotavljanje skladnosti podatkov replik, Cassandra uporablja <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Quorum_(distributed_computing)\">kvorumni pristop<\/a><\/noindex>V najpreprostej\u0161em primeru to pomeni, da se pri postavitvi treh replik iste vrstice na razli\u010dnih vozlih grozda, zapis \u0161teje za uspe\u0161en, \u010de ve\u010dina vozlov (t.j. dva od treh) potrdi uspe\u0161nost te operacije zapisa. Podatki vrstice se \u0161tejejo za usklajene, \u010de so ob branju ve\u010dina vozlov bila anketirana in so potrdila. Tako se pri treh replikah zagotavlja popolna in takoj\u0161nja usklajenost podatkov v primeru odpovedi enega vozla. Ta pristop nam je omogo\u010dil, da smo implementirali \u0161e bolj zanesljivo shemo: vedno po\u0161iljamo zahteve na vse tri replike, pri \u010demer \u010dakamo na odgovor dveh najhitrej\u0161ih. Pozno odgovorjena tretja replika se v tem primeru zavr\u017ee. Vozlo, ki je pozno odgovorilo, lahko ima resne te\u017eave \u2014 zastoji, zbiranje smeti v JVM, zajemanje neposredne pomnilni\u0161ke enote v jedru linuxa, okvara strojne opreme, odklop od omre\u017eja. Vendar na operacijo stranke in na podatke to ne vpliva na noben na\u010din.<\/p>\n<p>Pristop, ko se obra\u010damo na tri vozle, a prejmemo odgovor od dveh, se imenuje <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Speculative_execution\">spekulacija<\/a><\/noindex>: zahteva za odve\u010dne replike se po\u0161lje preden \u2018odstopi\u2019. <\/p>\n<p>\u0160e ena od prednosti Cassandre je Batchlog \u2014 mehanizem, ki jam\u010di bodisi popolno izvajanje bodisi popolno neizvajanje paketa va\u0161ih sprememb. To nam omogo\u010da re\u0161evanje A v ACID \u2014 atomarnost iz \u0161katle.<\/p>\n<p>Najbli\u017eje transakcijam v Cassandri so tako imenovani &#171;<noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_using\/useInsertLWT.html\">lahke transakcije<\/a><\/noindex>&#171;. Vendar so od \"pravi\" ACID-transakcij precej oddaljene: v resnici omogo\u010dajo <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compare-and-swap\">CAS<\/a><\/noindex> na podatkih samo enega zapisa, s soglasjem po te\u017ekem protokolu Paxos. Zaradi tega je hitrost takih transakcij majhna. <\/p>\n<h2>\u010cesar nam je primanjkovalo v Cassandri<\/h2>\n<p>\nTorej, morali smo v Cassandri implementirati prave ACID-transakcije. S katerimi bi zlahka uresni\u010dili dve drugi uporabni funkciji klasi\u010dnih DBMS: dosledne hitre indekse, kar bi nam omogo\u010dilo iskanje podatkov ne le po primarnem klju\u010du in obi\u010dajni generator monotone samodejno pove\u010danih ID-jev.<\/p>\n<h4>C*One<\/h4>\n<p>\nTako je nastala nova SODB <b>C*One<\/b>, ki je sestavljena iz treh tipov stre\u017eni\u0161kih vozlov:<\/p>\n<ul>\n<li>Shranjevanja \u2014 (skoraj) standardni stre\u017eniki Cassandre, odgovorni za shranjevanje podatkov na lokalnih diskih. Z nara\u0161\u010danjem obremenitve in obsega podatkov je njihovo \u0161tevilo mogo\u010de enostavno raz\u0161iriti na desettiso\u010de in stotine.<\/li>\n<li>Koordinatori transakcija - osiguravaju izvr\u0161enje transakcija. <\/li>\n<li>Klijenti - serveri aplikacija koji realizuju poslovne operacije i iniciraju transakcije. Takvih klijenata mo\u017ee biti na hiljade.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/f3809d89404ae596c62b642dbdb9e431.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nServeri svih tipova su deo zajedni\u010dkog klastera, koriste unutra\u0161nji protokol poruka Cassandra za me\u0111usobnu komunikaciju i <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip<\/a><\/noindex> za razmenu klasterskih informacija. Pomo\u0107u Heartbeat-a serveri saznaju o me\u0111usobnim kvarovima, odr\u017eavaju jedinstvenu \u0161emu podataka - tabele, njihovu strukturu i replikaciju; \u0161emu particionisanja, topologiju klastera itd.<\/p>\n<h4>Klijenti<\/h4>\n<p>\n<img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/80f83358f215cf59db3b657ba1083420.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUmesto standardnih drajvera koristi se re\u017eim Fat Client. Ova nod ne \u010duva podatke, ali mo\u017ee da deluje kao koordinator izvr\u0161enja zahteva, \u0161to zna\u010di da klijent sam obavlja funkciju koordinatora svojih zahteva: ispituje replikate skladi\u0161ta i re\u0161ava sukobe. Ovo je ne samo pouzdanije i br\u017ee od standardnog drajvera, koji zahteva komunikaciju sa udaljenim koordinatorom, ve\u0107 i omogu\u0107ava upravljanje prenosom zahteva. Van otvorene transakcije na klijentu, zahtevi se \u0161alju u skladi\u0161ta. Ukoliko klijent otvori transakciju, svi zahtevi u okviru transakcije se \u0161alju koordinatoru transakcija.<br \/>\n<img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/709bf227eeb8f71abeff703a72780efd.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Koordinator transakcija C*One<\/h2>\n<p>\nKoordinator je ono \u0161to smo realizovali za C*One od nule. On je odgovoran za upravljanje transakcijama, zaklju\u010davanjima i redosledom primene transakcija.<\/p>\n<p>Za svaku obra\u0111enu transakciju koordinator generi\u0161e vremensku oznaku: svaka naredna je ve\u0107a od prethodne transakcije. Po\u0161to je u Cassandri sistem re\u0161avanja sukoba zasnovan na vremenskim oznakama (od dve sukobljene evidencije, aktuelna se smatra onom sa kasnijom vremenskom oznakom), sukob \u0107e uvek biti re\u0161en u korist naredne transakcije. Tako smo realizovali <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A7%D0%B0%D1%81%D1%8B_%D0%9B%D1%8D%D0%BC%D0%BF%D0%BE%D1%80%D1%82%D0%B0\">Lamporov sat<\/a><\/noindex> \u2014 jeftin na\u010din re\u0161avanja sukoba u distribuiranom sistemu.<\/p>\n<h2>Zaklju\u010davanja<\/h2>\n<p>\nZa obezbe\u0111ivanje izolacije odlu\u010dili smo se za najjednostavniji pristup - pesimisti\u010dka zaklju\u010davanja po primarnom klju\u010du evidencije. Drugim re\u010dima, u transakciji, evidenciju je potrebno prvo zaklju\u010dati, pa tek onda pro\u010ditati, modifikovati i sa\u010duvati. Samo nakon uspe\u0161nog komita evidencija mo\u017ee biti otklju\u010dana, kako bi konkurentske transakcije mogle da je koriste.<\/p>\n<p>Implementacija takve blokade je jednostavna u nerazdeljenom okru\u017eenju. U distribuiranom sistemu postoje dva glavna pristupa: ili realizovati distribuiranu blokadu u klasteru, ili raspodeliti transakcije tako da se transakcije koje uklju\u010duju jedan zapis uvek obra\u0111uju od istog koordinatora.<\/p>\n<p>Po\u0161to su u na\u0161em slu\u010daju podaci ve\u0107 raspodeljeni po grupama lokalnih transakcija u SQL-u, odlu\u010deno je da se koordinatorima dodele grupe lokalnih transakcija: jedan koordinator izvr\u0161ava sve transakcije sa tokenom od 0 do 9, drugi - sa tokenom od 10 do 19, i tako dalje. Kao rezultat, svaki od instanci koordinatora postaje glavni za grupu transakcija. <\/p>\n<p>Tada se blokade mogu realizovati u obliku obi\u010dnog HashMap-a u memoriji koordinatora.<\/p>\n<h2>Gre\u0161ke koordinatora<\/h2>\n<p>\nPo\u0161to jedan koordinator isklju\u010divo obra\u0111uje grupu transakcija, veoma je va\u017eno brzo utvrditi njegovu gre\u0161ku kako bi ponovno poku\u0161avanje izvr\u0161enja transakcije stalo u vremenski okvir. Da bi to bilo brzo i pouzdano, primenili smo protokol potpunog povezanog kvorumskog heartbeat-a:<\/p>\n<p>U svakom data centru se nalazi najmanje dve \u010dvora koordinatora. Periodi\u010dno, svaki koordinator \u0161alje heartbeat poruku ostalim koordinatorima i izve\u0161tava ih o svom funkcionisanju, kao i o tome koje heartbeat poruke od kojih koordinatora u klasteru je primio poslednji put. <\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/5c337e53815cad0a2071b160d98d42fa.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPrimaju\u0107i sli\u010dne informacije od ostalih u sastavu svojih heartbeat poruka, svaki koordinator odlu\u010duje za sebe koje \u010dvorove klastera funkcioni\u0161u, a koje ne, oslanjaju\u0107i se na princip kvoruma: ako je \u010dvor X primio od ve\u0107ine \u010dvorova u klasteru informaciju o normalnom prijemu poruka sa \u010dvora Y, to zna\u010di da Y radi. I obrnuto, \u010dim ve\u0107ina izvesti o gubitku poruka sa \u010dvora Y, to zna\u010di da je Y otkazao. Zanimljivo je da ako kvorum obavesti \u010dvor X da ne prima vi\u0161e poruka od njega, sam \u010dvor X \u0107e smatrati da je otkazao.<\/p>\n<p>Heartbeat sporo\u010dila se po\u0161iljajo z veliko frekvenco, pribli\u017eno 20-krat na sekundo, s \u010dasovnim intervalom 50 ms. V Javi je te\u017eko zagotoviti odzivnost aplikacije v 50 ms zaradi primerljive dol\u017eine zamud, ki jih povzro\u010da zbiralnik odpadkov. Uspe\u0161no smo dosegli to odpoved z uporabo zbiralnika odpadkov G1, ki omogo\u010da dolo\u010ditev cilja glede dol\u017eine zamud GC. Vendar pa v\u010dasih, zelo redko, zamude zbiralnika presegajo 50 ms, kar lahko privede do napa\u010dne zaznave okvare. Da bi to prepre\u010dili, koordinator ne poro\u010da o okvari oddaljene vozli\u0161\u010da po izgubi prvega heartbeat sporo\u010dila od njega, temve\u010d le, \u010de jih je ve\u010d zaporednih. Tako smo uspeli dose\u010di zaznavanje okvare vozli\u0161\u010da koordinatorja v 200 ms. <\/p>\n<p>Toda hitro razumeti, katero vozli\u0161\u010de je prenehalo delovati, ni dovolj. Potrebno je nekaj storiti glede tega. <\/p>\n<h2>Rezervacija<\/h2>\n<p>\nKlasi\u010dna shema predvideva, da se v primeru okvare vodje izvedejo volitve novega z enim od<noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_Raft\"> modnih<\/a><\/noindex> <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9F%D0%B0%D0%BA%D1%81%D0%BE%D1%81\">univerzalnih<\/a><\/noindex> algoritmov. Vendar pa imajo podobni algoritmi dobro znane te\u017eave s konvergenco v \u010dasu in dol\u017eino samega procesa volitev. Dodatnih zamud smo se uspeli izogniti s shemo zamenjave koordinatorjev v popolnoma povezani mre\u017ei:<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/5e2db258fa2200026390a73a414dfe81.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nRecimo, da \u017eelimo izvesti transakcijo v skupini 50. Vnaprej dolo\u010dimo shemo zamenjave, tj. katera vozli\u0161\u010da bodo izvajala transakcije skupine 50 v primeru okvare glavnega koordinatorja. Na\u0161 cilj je ohraniti delovanje sistema v primeru okvare podatkovnega centra. Dolo\u010dimo, da bo prva rezerva vozli\u0161\u010de iz drugega podatkovnega centra, druga rezerva pa vozli\u0161\u010de iz tretjega. Ta shema se dolo\u010di enkrat in ne spremeni, dokler se topologija klasterja ne spremeni, t.j. dokler v njem ne pridejo nova vozli\u0161\u010da (kar se zgodi zelo redko). Postopek izbire novega aktivnega vodje ob okvari starega bo vedno tak: aktivni vodja postane prva rezerva, \u010de pa ta preneha delovati, postane druga rezerva. <\/p>\n<p>Tak\u0161na shema je zanesljivej\u0161a od univerzalnega algoritma, saj je za aktivacijo novega vodje dovolj ugotoviti dejstvo okvare starega.<\/p>\n<p>Kako \u0107e klijenti znati koji majstor trenutno radi? U 50 ms nije mogu\u0107e poslati informacije hiljadama klijenata. Mogu\u0107e je da klijent po\u0161alje zahtev za otvaranje transakcije, a da ne zna da taj majstor ve\u0107 ne funkcioni\u0161e, i zahtev \u0107e se zadr\u017eati na vremenskom isteku. Da se to ne bi desilo, klijenti spekulativno \u0161alju zahtev za otvaranje transakcije direktno majstoru grupe i oba njegova rezervna majstora, ali na taj zahtev \u0107e odgovoriti samo onaj koji je trenutno aktivan. Svaku dalju komunikaciju u okviru transakcije klijent \u0107e voditi samo sa aktivnim majstorom.<\/p>\n<p>Rezervni majstori primljene zahteve za ne svoje transakcije sme\u0161taju u red nerotnih transakcija, gde se \u010duvaju neko vreme. Ako aktivni majstor umre, novi majstor obra\u0111uje zahteve za otvaranje transakcija iz svog reda i odgovara klijentu. Ako je klijent ve\u0107 uspeo da otvori transakciju sa starim majstorom, tada se drugi odgovor ignori\u0161e (i, o\u010digledno, takva transakcija se ne\u0107e zavr\u0161iti i bi\u0107e ponovljena od strane klijenta).<\/p>\n<h2>Kako funkcioni\u0161e transakcija<\/h2>\n<p>\nPretpostavimo da je klijent poslao koordinatoru zahtev za otvaranje transakcije za odre\u0111eni entitet sa odre\u0111enim primarnih klju\u010dem. Koordinator blokira tu entitet i sme\u0161ta je u tabelu blokada u memoriji. Ako je potrebno, koordinator \u010dita tu entitet iz skladi\u0161ta i \u010duva dobijene podatke u stanje transakcije u memoriji koordinatora.<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/246b4a5c68a4cc886b87af784c16b9dc.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKada klijent \u017eeli da izmeni podatke u transakciji, \u0161alje koordinatoru zahtev za modifikaciju entiteta, a on sme\u0161ta nove podatke u tabelu stanja transakcija u memoriji. Na tome je zapis zavr\u0161en \u2014 zapis u skladi\u0161tu se ne vr\u0161i.<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/4400a91af30eb71134978ff27474f745.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKada klijent tra\u017ei u okviru aktivne transakcije svoje izmenjene podatke, koordinator postupa ovako: <\/p>\n<ul>\n<li>ako ID ve\u0107 postoji u transakciji, podaci se uzimaju iz memorije; <\/li>\n<li>ako ID nije u memoriji, nedostaju\u0107i podaci se \u010ditaju iz nodova skladi\u0161ta, kombinuju sa onima koji su ve\u0107 u memoriji, i rezultat se vra\u0107a klijentu. <\/li>\n<\/ul>\n<p>\nTako klijent mo\u017ee pro\u010ditati svoje promene, a drugi klijenti te promene ne vide, jer se \u010duvaju samo u memoriji koordinatora, a u nodovima Cassandre ih jo\u0161 nema.<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/c93fd7e8393f431a976f1f56b95e227c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKo klient po\u0161lje commit, stanje, ki je bilo v pomnilniku storitve, shrani koordinator v logged batch, ki se nato po\u0161lje v skladi\u0161\u010da Cassandra. Skladi\u0161\u010da opravijo vse potrebno, da se ta paket atomarno (popolno) uporabi in vrnejo odgovor koordinatorju, ki nato sprosti zaklepe in potrdi uspe\u0161nost transakcije klientu.<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/ab20487ba53ed88e2f560a2249b5d6f9.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa povrat je koordinatorju dovolj, da sprosti pomnilnik, zaseden s stanjem transakcije.<\/p>\n<p>Kot rezultat zgoraj opisanih izbolj\u0161av smo implementirali na\u010dela ACID:<\/p>\n<ul>\n<li><b>Atomarnost<\/b>. To je zagotovilo, da nobena transakcija ne bo delno zabele\u017eena v sistemu; izvedene bodo bodisi vse njene podoperacije bodisi nobena. Ta princip pri nas upo\u0161tevamo z logged batch v Cassandri.<\/li>\n<li><b>Konsistenca<\/b>. Vsaka uspe\u0161na transakcija po definiciji zabele\u017ei le dovoljene rezultate. \u010ce po odprtju transakcije in izvedbi dela operacij ugotovimo, da je rezultat nedovoljen, se izvede povrat.<\/li>\n<li><b>Izolacija<\/b>. Pri izvajanju transakcije paralelne transakcije ne smejo vplivati na njen rezultat. Konkuren\u010dne transakcije so izolirane z uporabo pesimisti\u010dnih zaklepov na koordinatorju. Za branja zunaj transakcije se upo\u0161teva na\u010delo izolacije na ravni Read Committed.<\/li>\n<li><b>Trdnost<\/b>. Ne glede na te\u017eave na spodnjih ravneh \u2014 izpad napajanja, okvara opreme \u2014 spremembe, ki jih je uspe\u0161no zaklju\u010dila transakcija, morajo ostati shranjene po ponovnem zagonu delovanja. <\/li>\n<\/ul>\n<p><\/p>\n<h2>Branje po indeksih<\/h2>\n<p>\nVzemimo preprosto tabelo: <\/p>\n<pre><code>CREATE TABLE photos (\nid bigint primary key,\nowner bigint,\nmodified timestamp,\n\u2026)<\/code><\/pre>\n<p>\nIma ID (prvi klju\u010d), lastnika in datum spremembe. Treba je izvesti zelo preprost poizvedbo \u2014 izbrati podatke po lastniku s datumom spremembe \"v zadnjih 24 urah\". <\/p>\n<pre><code>SELECT *\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nDa se tako poizvedba hitro izvede, je v klasi\u010dnem SQL DBMS potrebno zgraditi indeks po stolpcih (owner, modified). To lahko storimo dovolj enostavno, saj imamo zdaj jamstva ACID!<\/p>\n<h2>Indeksi v C*One<\/h2>\n<p>\nImamo izvirno tabelo s fotografijami, kjer je ID zapisa primarni klju\u010d. <\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/9f5d7c5f66882666a7ae8219f710beeb.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZa indeks C*One se stvara nova tabela koja je kopija izvorne. Klju\u010d se poklapa sa indeksnim izrazom, pri \u010demu uklju\u010duje i primarni klju\u010d zapisa iz izvorne tabele:<\/p>\n<p><img decoding=\"async\" alt=\"NewSQL = NoSQL + ACID\" src=\"\/wp-content\/uploads\/2019\/09\/ce6df1c8407bca7ddc61fd88141455e6.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSada se upit po 'vlasniku za poslednjih 24 sata' mo\u017ee prepraviti kao select iz druge tabele:<\/p>\n<pre><code>SELECT * FROM i1_test\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nKonzistentnost podataka izvorne tabele photos i indeksne i1 automatski odr\u017eava koordinator. Na osnovu samo \u0161eme podataka prilikom primanja promene, koordinator generi\u0161e i pamti promenu ne samo glavne tabele, ve\u0107 i promene kopija. Nema dodatnih radnji sa tabelom indeksa, logovi se ne \u010ditaju, zaklju\u010davanja se ne koriste. To zna\u010di da dodavanje indeksa gotovo ne tro\u0161i resurse i prakti\u010dno ne uti\u010de na brzinu primene modifikacija.<\/p>\n<p>Pomo\u0107u ACID-a uspeli smo da implementiramo indekse 'kao u SQL-u'. Oni imaju konzistenciju, mogu se skalirati, brzo rade, mogu biti slo\u017eeni i ugra\u0111eni su u CQL jezik upita. Za podr\u0161ku indeksima nije potrebno menjati aplikativni kod. Sve je jednostavno, kao u SQL-u. I \u0161to je najva\u017enije, indeksi ne uti\u010du na brzinu izvr\u0161avanja modifikacija izvorne tabele transakcija.<\/p>\n<h2>\u0160ta je postignuto<\/h2>\n<p>\nRazvili smo C*One pre tri godine i pokrenuli ga u proizvodnoj upotrebi. <\/p>\n<p>\u0160ta smo dobili na kraju? Procijenimo to na primeru podsistema za obradu i skladi\u0161tenje fotografija, jednog od najva\u017enijih tipova podataka u dru\u0161tvenoj mre\u017ei. Radi se ne o samim telima fotografija, ve\u0107 o raznim metainformacijama. Trenutno u 'Odnoklassnikima' ima oko 20 milijardi takvih zapisa, sistem obra\u0111uje 80 hiljada upita za \u010ditanje u sekundi, do 8 hiljada ACID transakcija u sekundi, povezanih sa modifikacijom podataka. <\/p>\n<p>Kada smo koristili SQL sa replication factor = 1 (ali u RAID 10), metainformacije o fotografijama su se \u010duvale na visoko dostupnom klasteru od 32 ma\u0161ine sa Microsoft SQL Server (plus 11 rezervnih). Tako\u0111e je bilo dodeljeno 10 servera za \u010duvanje rezervnih kopija. Ukupno 50 skupih ma\u0161ina. Pri tome je sistem radio pod nominalnim optere\u0107enjem, bez rezerve.<\/p>\n<p>Po migraciji na novi sistem dobili smo faktor replikacije = 3 \u2014 po jedna kopija u svakom data centru. Sistem se sastoji od 63 nodova za skladi\u0161tenje Cassandre i 6 ma\u0161ina koordinatora, ukupno 69 servera. Me\u0111utim, ove ma\u0161ine su znatno jeftinije, a ukupni tro\u0161ak iznosi oko 30 % tro\u0161ka SQL sistema. U me\u0111uvremenu, optere\u0107enje se odr\u017eava na nivou od 30 %.<\/p>\n<p>Uvo\u0111enjem C*One smanjene su i latencije: u SQL-u operacija upisa je trajala oko 4,5 ms. U C*One \u2014 oko 1,6 ms. Trajanje transakcije u proseku je manje od 40 ms, komit se izvr\u0161ava za 2 ms, a trajanje \u010ditanja i upisa \u2014 u proseku 2 ms. 99. percentile su svega 3-3,1 ms, a broj vremenskih prekida smanjen je 100 puta \u2014 sve zahvaljuju\u0107i \u0161irokoj primeni spekulacija. <\/p>\n<p>Trenutno je ve\u0107a partija nodova SQL Servera izba\u010dena iz eksploatacije, nove proizvode razvijamo samo uz kori\u0161\u0107enje C*One. Prilagodili smo C*One za rad u na\u0161em oblaku. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/odnoklassniki\/blog\/346868\/\">one-cloud<\/a><\/noindex>, \u0161to je omogu\u0107ilo br\u017ee postavljanje novih klastera, pojednostavilo konfiguraciju i automatizovalo eksploataciju. Bez izvorne \u0161ifre, to bi bilo znatno slo\u017eenije i klimavije. <\/p>\n<p>Trenutno radimo na prebacivanju drugih na\u0161ih skladi\u0161ta u oblak \u2014 ali to je ve\u0107 sasvim druga pri\u010da.<br \/>\n<br \/>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/odnoklassniki\/blog\/417593\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u0432 SQL Server. \u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439, \u0434\u0430 \u0435\u0449\u0435 \u0438 \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a \u043e\u0442\u043a\u0430\u0437\u0443 \u0426\u041e\u0414 \u0434\u043e\u0441\u0442\u0443\u043f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f SQL \u0421\u0423\u0411\u0414, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u041e\u0431\u044b\u0447\u043d\u043e \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0434\u043d\u043e \u0438\u0437 NoSQL-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449, \u043d\u043e \u043d\u0435 \u0432\u0441\u0451 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 NoSQL: \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28484,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-37956","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/newsql-nosql-acid\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47NewSQL = NoSQL+ACID | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/newsql-nosql-acid\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:20:47+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:20:47+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47NewSQL = NoSQL+ACID | ProHoster","description":"Do nedavnog vremena u Odnoklassnicima je bilo oko 50 TB podataka, koji su se obra\u0111ivali.","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/newsql-nosql-acid","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47NewSQL = NoSQL+ACID | ProHoster","og:description":"\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445.","og:url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/newsql-nosql-acid","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:20:47+00:00","article:modified_time":"2019-10-31T19:20:47+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"37956","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 19:55:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:17:23","updated":"2026-01-23 19:55:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/37956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=37956"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/37956\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/28484"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=37956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=37956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=37956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}