{"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\/hr\/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 nedavnog vremena, u Odnoklassnicima se oko 50 TB podataka, obra\u0111enih u stvarnom vremenu, \u010duvalo u SQL Serveru. Za tako veliku koli\u010dinu osigurati brzi, pouzdani i otporni na gre\u0161ke DC pristup koriste\u0107i SQL DB, prakti\u010dki je nemogu\u0107e. Obi\u010dno se u takvim slu\u010dajevima koristi jedno od NoSQL skladi\u0161ta, ali nije sve mogu\u0107e prenijeti u NoSQL: neka entiteta zahtijevaju ACID transakcijske garancije. <\/p>\n<p>To nas je dovelo do kori\u0161tenja NewSQL skladi\u0161ta, tj. DB koja pru\u017ea otpornost na gre\u0161ke, skalabilnost i brzinu NoSQL sustava, dok istovremeno zadr\u017eava klasi\u010dne ACID garancije. Brojevi industrijskih sustava ovog novog tipa su mali, stoga smo takav sustav implementirali sami i pokrenuli ga u produkciju. <\/p>\n<p>Kako to funkcionira i \u0161to smo postigli \u2014 \u010ditaj dalje.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nDanas mjese\u010dna publika \u201eOdnoklassnika\u201d iznosi vi\u0161e od 70 milijuna jedinstvenih posjetitelja. Mi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.similarweb.com\/top-websites\/category\/internet-and-telecom\/social-network\">smo me\u0111u pet<\/a><\/noindex> najve\u0107ih dru\u0161tvenih mre\u017ea na svijetu, i me\u0111u dvadeset web stranica na kojima korisnici provode najvi\u0161e vremena. Infrastruktura \u201eOK\u201d obra\u0111uje vrlo visoke optere\u0107enja: vi\u0161e od milijun HTTP zahtjeva\/s na frontovima. Dijelovi server farmi u broju od preko 8000 su smje\u0161teni blizu jedni drugima - u \u010detiri moskovska data centra, \u0161to omogu\u0107ava mre\u017enu latenciju manju od 1 ms izme\u0111u njih.<\/p>\n<p>Koristimo Cassandru od 2010. godine, po\u010dev\u0161i od verzije 0.6. Danas u upotrebi imamo nekoliko desetina klastera. Najbr\u017ei klaster obra\u0111uje vi\u0161e od 4 milijuna operacija u sekundi, a najve\u0107i pohranjuje 260 TB. <\/p>\n<p>Me\u0111utim, sve to su obi\u010dni NoSQL klasteri, koji se koriste za pohranu <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 uskla\u0111enih<\/a><\/noindex> podataka. Mi smo \u017eeljeli zamijeniti glavnu konzistentnu pohranu, Microsoft SQL Server, koji se koristio od samog po\u010detka \u201eOdnoklassnika\u201d. Pohrana se sastojala od vi\u0161e od 300 SQL Server Standard Edition ma\u0161ina, na kojima je bilo 50 TB podataka \u2014 poslovnih entiteta. Ovi podaci se modificiraju u okviru ACID transakcija i zahtijevaju <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">visoku konzistentnost<\/a><\/noindex>.<\/p>\n<p>Za distribuciju podataka po nodama SQL Server koristili smo i vertikalno i horizontalno <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Partition_(database)\">particioniranje<\/a><\/noindex> (sharding). Povijesno smo koristili jednostavnu shemu sharding podataka: svakoj entitetu je dodijeljen token \u2014 funkcija od ID entiteta. Entiteti s istim tokenom su smje\u0161teni na jedan SQL poslu\u017eitelj. Odnos tipa master-detail je realiziran tako da tokeni glavnog i potomaka zapisa uvijek odgovaraju i nalaze se na jednom poslu\u017eitelju. U dru\u0161tvenoj mre\u017ei gotovo svi unosi se generiraju u ime korisnika \u2014 to zna\u010di da su svi podaci korisnika unutar jedne funkcionalne podsustave pohranjeni na jednom poslu\u017eitelju. Drugim rije\u010dima, u poslovnim transakcijama gotovo uvijek su sudjelovale tablice jednog SQL poslu\u017eitelja, \u0161to je omogu\u0107ilo osiguravanje dosljednosti podataka pomo\u0107u lokalnih ACID transakcija, bez potrebe za kori\u0161tenjem <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">sporih i nepouzdanih<\/a><\/noindex> distribuiranih ACID transakcija.<\/p>\n<p>Zahvaljuju\u0107i sharding-u i zbog ubrzanja rada SQL-a:<\/p>\n<ul>\n<li>Ne koristimo strane klju\u010dne uvjete, budu\u0107i da se pri sharding-u ID entiteta mo\u017ee nalaziti na drugom poslu\u017eitelju.<\/li>\n<li>Ne koristimo pohranjene procedure i okida\u010de zbog dodatnog optere\u0107enja na CPU-u DBMS-a.<\/li>\n<li>Ne koristimo JOIN-ove zbog svega navedenog i niza slu\u010dajnih \u010ditanja s diska.<\/li>\n<li>Izvan transakcije, kako bismo smanjili me\u0111usobna zaklju\u010davanja, koristimo razinu izolacije Read Uncommitted.<\/li>\n<li>Izvr\u0161avamo samo kratke transakcije (u prosjeku kra\u0107e od 100 ms).<\/li>\n<li>Ne koristimo vi\u0161eredne UPDATE i DELETE zbog velikog broja me\u0111usobnih zaklju\u010davanja \u2014 a\u017euriramo samo po jedan zapis.<\/li>\n<li>Upiti uvijek izvr\u0161avamo samo po indeksima \u2014 upit s planom potpunog pregleda tablice za nas zna\u010di preoptere\u0107enje baze podataka i njen kvar.<\/li>\n<\/ul>\n<p>\nOvi koraci su omogu\u0107ili da iz SQL poslu\u017eitelja izdvojimo gotovo maksimum performansi. Me\u0111utim, problemi su postajali sve ve\u0107i. Pogledajmo ih.<\/p>\n<h2>Problemi sa SQL-om<\/h2>\n<p><\/p>\n<ul>\n<li>Budu\u0107i da smo koristili vlastiti sharding, dodavanje novih shardova obavljali su administratori ru\u010dno. Sve to vrijeme, skalabilne replike podataka nisu obra\u0111ivale upite. <\/li>\n<li>Kako se broj zapisa u tablici pove\u0107ava, brzina umetanja i izmjene opada, a prilikom dodavanja indeksa postoje\u0107oj tablici brzina se drasti\u010dno smanjuje, stvaranje i ponovno stvaranje indeksa odvija se uz vrijeme nedostupnosti.<\/li>\n<li>Postojanje malog broja Windows poslu\u017eitelja za SQL Server u produkciji ote\u017eava upravljanje infrastrukturom.<\/li>\n<\/ul>\n<p>\nAli glavni problem \u2014 <\/p>\n<h2>Otpornost na gre\u0161ke<\/h2>\n<p>\nKlasi\u010dni SQL server ima lo\u0161u otpornost na kvarove. Pretpostavimo da imate samo jedan server baze podataka i on otkazuje svake tri godine. U to vreme sajt ne radi 20 minuta, \u0161to je prihvatljivo. Ako imate 64 servera, sajt ne radi jednom svake tri nedelje. A ako imate 200 servera, sajt ne radi svake nedelje. To je problem. <\/p>\n<p>\u0160ta se mo\u017ee u\u010diniti za pove\u0107anje otpornosti SQL servera? Wikipedia nam predla\u017ee da izgradimo <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/High-availability_cluster\">visoko dostupni klaster<\/a><\/noindex>: gde u slu\u010daju kvara bilo kog od komponenti postoji duplikat.<\/p>\n<p>To zahteva park skupog hardvera: brojna duplikacija, opti\u010dka vlakna, skladi\u0161ta zajedni\u010dkog pristupa, a uklju\u010divanje rezervi funkcioni\u0161e nepouzdano: oko 10% uklju\u010divanja zavr\u0161ava otkazom rezervne \u010dvora zajedno s osnovnim \u010dvorom. <\/p>\n<p>Ali glavni nedostatak takvog visoko dostupnog klastera je nulta dostupnost u slu\u010daju kvara data centra u kojem se nalazi. 'Odnoklassniki' ima \u010detiri data centra, i moramo obezbediti rad u slu\u010daju potpunog kvara jednog od njih.<\/p>\n<p>Za to bismo mogli primeniti <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 re\u0161enje je zna\u010dajno skuplje zbog tro\u0161kova softvera i pati od dobro poznatih problema sa replikacijom \u2014 nepredvidivih ka\u0161njenja transakcija pri sinhronoj replikaciji i ka\u0161njenja u primeni replikacija (i, kao posledica, izgubljenih modifikacija) pri asinkronoj. Pretpostavljeni <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 re\u0161avanje konflikata<\/a><\/noindex> \u010dinimo ovu opciju potpuno neprihvatljivom za nas.<\/p>\n<p>Svi ovi problemi zahtevali su radikalno re\u0161enje i zapo\u010deli smo detaljnu analizu. Ovde se moramo upoznati s onim \u0161to SQL Server uglavnom radi \u2014 transakcijama.<\/p>\n<h2>Jednostavna transakcija<\/h2>\n<p>\nRazmotrimo najjednostavniju, s gledi\u0161ta aplikativnog SQL programera, transakciju: dodavanje fotografije u album. Albumi i fotografije se \u010duvaju u razli\u010ditim tabelama. Album ima broja\u010d javnih fotografija. Tako se transakcija deli na slede\u0107e korake: <\/p>\n<ol>\n<li>Zaklju\u010davamo album prema klju\u010devi.<\/li>\n<li>Kreiramo zapis u tabeli fotografija. <\/li>\n<li>Ako fotografija ima javni status, pove\u0107avamo u albumu broja\u010d javnih fotografija, 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 naj\u010de\u0161\u0107i scenarij poslovne transakcije - \u010ditanje podataka iz baze podataka u memoriju aplikacijskog poslu\u017eitelja, izmjena ne\u010dega i spremanje novih vrijednosti nazad u bazu podataka. Obi\u010dno u takvoj transakciji a\u017euriramo nekoliko entiteta, nekoliko tablica. <\/p>\n<p>Pritom mo\u017ee do\u0107i do konkurentnog modificiranja istih podataka iz drugog sustava. Na primjer, Antispam mo\u017ee smatrati da je korisnik sumnjiv i stoga sve fotografije korisnika vi\u0161e ne bi trebale biti javne, trebaju se poslati na moderaciju, a to zna\u010di promjenu photo.status na neku drugu vrijednost i preokret odgovaraju\u0107ih broja\u010da. O\u010digledno je da ako se ova operacija odvija bez jamstva atomarne primjene i izolacije konkurentnih modifikacija, kao u <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>, rezultat ne\u0107e biti ono \u0161to je potrebno - ili \u0107e broj fotografija prikazivati neto\u010dnu vrijednost, ili ne\u0107e sve fotografije biti poslane na moderaciju. <\/p>\n<p>Sli\u010dnog koda, koji manipulira razli\u010ditim poslovnim entitetima unutar jedne transakcije, napisano je jako mnogo otkad postoje Odnoklassniki. Prema iskustvu migracija na NoSQL s <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">Postepenom dosljedno\u0161\u0107u<\/a><\/noindex> znamo da najve\u0107e pote\u0161ko\u0107e (i vremenski tro\u0161kovi) izaziva potreba za razvojem koda usmjerenog na odr\u017eavanje dosljednosti podataka. Stoga je glavni zahtjev za novo skladi\u0161te bio osiguranje pravi\u010dnih ACID transakcija za poslovnu logiku. <\/p>\n<p>Drugi, ne manje va\u017eni zahtjevi su bili:<\/p>\n<ul>\n<li>U slu\u010daju pada podatkovnog centra, trebali bi biti dostupni i \u010ditanje i zapis u novo skladi\u0161te.<\/li>\n<li>Odr\u017eavanje trenutne brzine razvoja. To jest, pri radu s novim skladi\u0161tem, koli\u010dina koda trebala bi biti pribli\u017eno ista, ne bi se trebale pojaviti potrebe za dodatnim pisanjem u skladi\u0161te, razvojem algoritama za rje\u0161avanje sukoba, odr\u017eavanje sekundarnih indeksa i sli\u010dno. <\/li>\n<li>Brzina rada novog skladi\u0161ta trebala bi biti dovoljno visoka, i pri \u010ditanju podataka i pri obradi transakcija, \u0161to u\u010dinkovito zna\u010di da akademski stroga, univerzalna, ali spora rje\u0161enja, poput <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">dvofaznog potvr\u0111ivanja ne\u0107e biti primjenjiva<\/a><\/noindex>.<\/li>\n<li>Automatsko skaliranje u stvarnom vremenu. <\/li>\n<li>Kori\u0161tenje obi\u010dnih jeftinih servera, bez potrebe za kupovinom egzoti\u010dnih komponenti. <\/li>\n<li>Mogu\u0107nost razvoja skladi\u0161ta od strane programerskog tima. Drugim rije\u010dima, prioritet su imali vlastiti ili rje\u0161enja zasnovana na otvorenom kodu, po\u017eeljno na Javi.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Rje\u0161enja, rje\u0161enja<\/h2>\n<p>\nAnaliziraju\u0107i mogu\u0107a rje\u0161enja, do\u0161li smo do dva mogu\u0107a izbora arhitekture:<\/p>\n<p>Prvi \u2014 uzeti bilo koji SQL server i implementirati potrebnu otpornost na gre\u0161ke, mehanizam skaliranja, klaster otpornosti na gre\u0161ke, rje\u0161avanje konflikata i distribuirane, pouzdane i brze ACID-transakcije. Ovu opciju smo ocijenili kao prili\u010dno slo\u017eenu i radno intenzivnu.<\/p>\n<p>Druga opcija \u2014 uzeti spremno NoSQL skladi\u0161te s implementiranim skaliranjem, klasterom otpornim na gre\u0161ke, rje\u0161avanjem konflikata i sami implementirati transakcije i SQL. Na prvi pogled, \u010dak i zadatak implementacije SQL-a, da ne govorimo o ACID transakcijama, izgleda kao problem za godine. No kasnije smo shvatili da skup mogu\u0107nosti SQL-a koji koristimo u praksi, daleko odstupa od ANSI SQL-a koliko i <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Apache_Cassandra#Cassandra_Query_Language\">Cassandra CQL<\/a><\/noindex> daleko od ANSI SQL-a. Kada smo se dodatno osvrnuli na CQL, shvatili smo da je dovoljno blizu onome \u0161to nam treba.<\/p>\n<h2>Cassandra i CQL<\/h2>\n<p>\nDakle, \u0161to je to Cassandra zanimljiva, koje mogu\u0107nosti ima?<\/p>\n<p>Prvo, ovdje mo\u017eete stvarati tablice s podr\u0161kom za razli\u010dite tipove podataka, mo\u017eete izvr\u0161avati SELECT ili UPDATE po primarnom klju\u010du.<\/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 osiguranje konzistentnosti podataka replikacija, Cassandra koristi <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Quorum_(distributed_computing)\">kvormni pristup<\/a><\/noindex>. U najjednostavnijem slu\u010daju, to zna\u010di da se prilikom postavljanja tri replike istog reda na razli\u010ditim \u010dvorovima klastera zapis smatra uspje\u0161nim ako ve\u0107ina \u010dvorova (tj. dva od tri) potvrdi uspje\u0161nost te operacije pisanja. Podaci reda smatraju se dosljednima ako su prilikom \u010ditanja ve\u0107ina \u010dvorova bila upitana i potvrdila ih. Tako se, u prisutnosti tri replike, jam\u010di puna i trenutna dosljednost podataka u slu\u010daju kvara jednog \u010dvora. Ovaj pristup omogu\u0107io nam je da implementiramo jo\u0161 pouzdaniju shemu: uvijek slati zahtjeve na sve tri replike, \u010dekaju\u0107i odgovor od dva najbr\u017ea. Odgovor tre\u0107e replike koja kasni u tom slu\u010daju se odbacuje. \u010cvor koji kasni s odgovorom mo\u017ee imati ozbiljnih problema \u2014 usporavanje, prikupljanje sme\u0107a u JVM-u, osloba\u0111anje direktne memorije u Linux kernelu, kvar hardvera, prekid veze. Me\u0111utim, ovo nikako ne utje\u010de na operacije klijenta i podatke.<\/p>\n<p>Pristup kada se obra\u0107amo trima \u010dvorovima, a dobivamo odgovor od dvaju, naziva se <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Speculative_execution\">spekulacijom<\/a><\/noindex>: zahtjev prema suvi\u0161nim replikama \u0161alje se jo\u0161 prije nego \u0161to 'otpadne'. <\/p>\n<p>Jo\u0161 jedna od prednosti Cassandre je Batchlog \u2014 mehanizam koji jam\u010di ili potpuno primjenjivanje ili potpuno neprimjenjivanje paketa promjena koje ste unijeli. To nam omogu\u0107uje da rje\u0161avamo A u ACID-u \u2014 atomarnost iz kutije.<\/p>\n<p>Najbli\u017ee transakcijama u Cassandri je takozvani &#171;<noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_using\/useInsertLWT.html\">lightweight transactions<\/a><\/noindex>&#171;. No, daleko su od \"pravih\" ACID transakcija: zapravo, to je mogu\u0107nost izvr\u0161avanja <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compare-and-swap\">CAS<\/a><\/noindex> na podacima samo jednog zapisa, koriste\u0107i konsenzus prema te\u0161kom protokolu Paxos. Stoga je brzina takvih transakcija niska. <\/p>\n<h2>\u0160to nam nedostaje u Cassandri<\/h2>\n<p>\nDakle, trebali smo implementirati prave ACID transakcije u Cassandri. Uz njihovu pomo\u0107 mogli bismo lako realizirati dvije druge korisne mogu\u0107nosti klasi\u010dnih DBMS-a: dosljedne brze indekse, \u0161to bi nam omogu\u0107ilo izvo\u0111enje upita podataka ne samo prema primarnom klju\u010du i obi\u010dni generator monotone autoinkrementalnih ID.<\/p>\n<h4>C*One<\/h4>\n<p>\nTako je nastala nova DBMS <b>C*One<\/b>, koja se sastoji od tri vrste poslu\u017eiteljskih \u010dvorova:<\/p>\n<ul>\n<li>Skladi\u0161ta \u2014 (gotovo) standardni poslu\u017eitelji Cassandre, odgovorni za pohranu podataka na lokalnim diskovima. Kako raste optere\u0107enje i volumen podataka, njihovu koli\u010dinu \u043c\u043e\u0436\u043d\u0430 lako pove\u0107ati na desetke i stotine.<\/li>\n<li>Koordinatori transakcija - osiguravaju izvr\u0161enje transakcija. <\/li>\n<li>Klijenti - serveri aplikacija koji provode poslovne operacije i pokre\u0107u 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 komunikaciju jedni s drugima i <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip<\/a><\/noindex> za razmenu klasterskih informacija. Pomo\u0107u Heartbeat serveri saznaju o me\u0111usobnim kvarovima, odr\u017eavaju jedinstvenu \u0161emu podataka - tabele, njihovu strukturu i replikaciju; \u0161emu particioniranja, 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 skladi\u0161ti podatke, ali mo\u017ee delovati kao koordinator izvr\u0161enja zahteva, tj. Klijent sam izvr\u0161ava funkciju koordinatora svojih zahteva: ispituje replike skladi\u0161ta i re\u0161ava konflikte. Ovo je ne samo pouzdanije i br\u017ee od standardnog drajvera, koji zahteva komunikaciju s udaljenim koordinatorom, ve\u0107 i omogu\u0107ava upravljanje prenosa zahteva. U okviru otvorene transakcije na klijentu, zahtevi se \u0161alju u skladi\u0161ta. Ako je klijent otvorio transakciju, tada se svi zahtevi u okviru transakcije usmeravaju ka 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 - ono \u0161to smo implementirali za C*One od nule. On je odgovoran za upravljanje transakcijama, zaklju\u010davanjima i redosledom primene transakcija.<\/p>\n<p>Za svaku obra\u0111ivanu transakciju koordinator generi\u0161e vremensku oznaku: svaka slede\u0107a je ve\u0107a od prethodne transakcije. Po\u0161to je u Cassandri sistem re\u0161avanja konflikata zasnovan na vremenskim oznakama (od dve konfliktne evidencije, aktuelna je ona sa kasnijom vremenskom oznakom), konflikt \u0107e biti uvek re\u0161en u korist slede\u0107e transakcije. Na taj na\u010din smo implementirali <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\">Lamportove satove<\/a><\/noindex> \u2014 jeftin na\u010din re\u0161avanja konflikata u distribuiranom sistemu.<\/p>\n<h2>Zaklju\u010davanja<\/h2>\n<p>\nDa bismo osigurali izolaciju, odlu\u010dili smo se koristiti najjednostavniji na\u010din - pesimisti\u010dka zaklju\u010davanja po primarnom klju\u010du evidencije. Drugim re\u010dima, u transakciji, evidencija mora prvo biti zaklju\u010dana, zatim pro\u010ditana, modifikovana i sa\u010duvana. Tek nakon uspe\u0161nog komitovanja, evidencija se mo\u017ee otklju\u010dati kako bi konkurentske transakcije mogle da je koriste.<\/p>\n<p>Implementacija takve blokade jednostavna je u nerazdijeljenoj sredini. U distribuiranom sustavu postoje dva glavna puta: ili implementirati distribuiranu blokadu na klasteru, ili raspodijeliti transakcije tako da transakcije koje uklju\u010duju jedan zapis uvijek obra\u0111uje isti koordinator.<\/p>\n<p>Budu\u0107i da su u na\u0161em slu\u010daju podaci ve\u0107 raspore\u0111eni po grupama lokalnih transakcija u SQL-u, odlu\u010deno je da se koordinatorima dodijele grupe lokalnih transakcija: jedan koordinator obra\u0111uje sve transakcije s tokenom od 0 do 9, drugi - s tokenom od 10 do 19, i tako dalje. Kao rezultat toga, svaka od instanci koordinatora postaje master grupe transakcija. <\/p>\n<p>Tada se blokade mogu implementirati kao obi\u010dni HashMap u memoriji koordinatora.<\/p>\n<h2>Kvarovi koordinatora<\/h2>\n<p>\nBudu\u0107i da jedan koordinator isklju\u010divo obra\u0111uje grupu transakcija, vrlo je va\u017eno brzo utvrditi njegov kvar kako bi ponovni poku\u0161aj izvr\u0161enja transakcije stao u vremensko ograni\u010denje. Kako bi to bilo brzo i pouzdano, primijenili smo protokol potpune povezane kvorumske heartbeat-a:<\/p>\n<p>U svakom data centru nalaze se najmanje dvije \u010dvora koordinatora. Povremeno svaki koordinator \u0161alje heartbeat poruku ostalim koordinatorima i obavje\u0161tava ih o svom radu, kao i o tome od kojih koordinatora u klasteru je posljednji put primio heartbeat poruke. <\/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 njihovim heartbeat porukama, svaki koordinator odlu\u010duje koji su \u010dvorovi klastera funkcionalni, a koji nisu, prema principu kvoruma: ako je \u010dvor X od ve\u0107ine \u010dvorova u klasteru primio informacije o normalnom primanju poruka s \u010dvora Y, to zna\u010di da Y radi. I obrnuto, \u010dim ve\u0107ina prijavi gubitak poruka s \u010dvora Y, to zna\u010di da je Y otkazao. Zanimljivo je da ako kvorum obavijesti \u010dvor X da vi\u0161e ne prima poruke s njega, onda \u0107e se sam \u010dvor X smatrati otkazanim.<\/p>\n<p>Heartbeat poruke se \u0161alju s velikom u\u010destalo\u0161\u0107u, oko 20 puta u sekundi, s periodom od 50 ms. U Javi je te\u0161ko jam\u010diti odgovor aplikacije unutar 50 ms zbog sli\u010dnih trajanja pauza uzrokovanih sakuplja\u010dem otpada. Uspjeli smo posti\u0107i takvo vrijeme odgovora koriste\u0107i sakuplja\u010d otpada G1, koji omogu\u0107ava definiranje cilja za trajanje GC pauza. Me\u0111utim, ponekad, vrlo rijetko, pauze sakuplja\u010da prema\u0161uju 50 ms, \u0161to mo\u017ee dovesti do la\u017enog otkrivanja kvara. Kako bismo to izbjegli, koordinator ne prijavljuje kvar udaljenog \u010dvora nakon gubitka prvog heartbeat poruka, ve\u0107 samo ako ih izgubi vi\u0161e zaredom. Tako smo uspjeli posti\u0107i otkrivanje kvara \u010dvora koordinatora za 200 ms. <\/p>\n<p>Ali nije dovoljno brzo shvatiti koji \u010dvor je prestao funkcionirati. Potrebno je ne\u0161to poduzeti. <\/p>\n<h2>Sigurnosna kopija<\/h2>\n<p>\nKlasi\u010dna shema pretpostavlja pokretanje izbora novog vo\u0111e u slu\u010daju kvara, preko jednog 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\"> popularnih<\/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> algoritama. Me\u0111utim, takvi algoritmi imaju dobro poznate probleme s konvergencijom u vremenu i trajanjem samog procesa izbora. Takve dodatne latencije uspjeli smo izbje\u0107i kroz shemu zamjene koordinatora u potpuno povezanoj 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 \/>\nPretpostavimo da \u017eelimo izvr\u0161iti transakciju u grupi 50. Unaprijed definiramo shemu zamjene, tj. koji \u0107e \u010dvorovi izvr\u0161avati transakcije grupe 50 u slu\u010daju kvara glavnog koordinatora. Na\u0161 cilj je zadr\u017eati operabilnost sustava u slu\u010daju kvara datacentra. Definiramo da \u0107e prvi rezervni \u010dvor biti iz drugog datacentra, a drugi rezervni iz tre\u0107eg. Ova shema se bira jednom i ne mijenja se sve dok se topologija klastera ne promijeni, tj. sve dok se ne pridru\u017ee novi \u010dvorovi (\u0161to se vrlo rijetko doga\u0111a). Redoslijed odabira novog aktivnog vo\u0111e u slu\u010daju kvara starog bit \u0107e uvijek takav: aktivni vo\u0111a postat \u0107e prvi rezervni \u010dvor, a ako je i on prestao funkcionirati \u2013 drugi rezervni. <\/p>\n<p>Ova shema je pouzdanija od univerzalnog algoritma, jer za aktivaciju novog vo\u0111e dovoljno je utvrditi \u010dinjenicu kvara starog.<\/p>\n<p>No kako klijenti mogu saznati koji od majstora trenutno radi? U 50 ms nije mogu\u0107e poslati informacije tisu\u0107ama klijenata. Mogu\u0107e je da klijent po\u0161alje zahtjev za otvaranje transakcije, jo\u0161 ne znaju\u0107i da taj majstor vi\u0161e ne funkcioni\u0161e, i da \u0107e zahtjev zablokirati na vremenskom isteku. Da bi se to izbjeglo, klijenti spekulativno \u0161alju zahtjev za otvaranje transakcije direktno majstoru grupe i oba njegova rezervna majstora, ali \u0107e odgovoriti samo onaj koji je aktivni majstor u tom trenutku. Svu daljnju komunikaciju u okviru transakcije klijent \u0107e izvoditi samo s aktivnim majstorom.<\/p>\n<p>Rezervni majstori zaprimljene zahtjeve za ne svoje transakcije stavljaju u rednerazorenih transakcija, gdje ostaju neko vrijeme. Ako aktivni majstor umre, novi majstor obra\u0111uje zahtjeve za otvaranje transakcija iz svog reda i odgovara klijentu. Ako je klijent ve\u0107 uspeo otvoriti transakciju sa starim majstorom, drugi odgovor se ignorira (i, o\u010digledno, takva transakcija se ne\u0107e zavr\u0161iti i klijent \u0107e je ponoviti).<\/p>\n<h2>Kako funkcioni\u0161e transakcija<\/h2>\n<p>\nPretpostavimo da je klijent poslao koordinatoru zahtjev za otvaranje transakcije za odre\u0111enu entitet s odre\u0111enim primarnim klju\u010dem. Koordinator blokira tu entitet i stavlja je u tabelu blokada u memoriji. Ako je potrebno, koordinator \u010dita tu entitet iz skladi\u0161ta i sprema dobivene 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 promijeniti podatke u transakciji, \u0161alje koordinatoru zahtjev za modifikaciju entiteta, a on stavlja nove podatke u tabelu stanja transakcija u memoriji. Na tome zapis zavr\u0161ava \u2014 zapis u skladi\u0161te 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 vlastite izmijenjene 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 u memoriji ne postoji, nedostaju\u0107i podaci se \u010ditaju iz nod-skladi\u0161ta, spajaju s ve\u0107 postoje\u0107ima u memoriji, i rezultat se vra\u0107a klijentu. <\/li>\n<\/ul>\n<p>\nTako klijent mo\u017ee pro\u010ditati vlastite promjene, dok drugi klijenti te promjene 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 \/>\nKada klijent po\u0161alje commit, stanje koje je bilo u memoriji usluge pohranjuje koordinator u logged batch, a ve\u0107 u obliku logged batch \u0161alje se u spremi\u0161ta Cassandra. Spremi\u0161ta \u010dine sve potrebno da bi se ovaj paket atomarno (potpuno) primijenio i vra\u0107aju odgovor koordinatoru, koji osloba\u0111a blokade i potvr\u0111uje uspje\u0161nost transakcije klijentu.<\/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 \/>\nA za povratak, koordinatoru je dovoljno samo osloboditi memoriju zauzetu stanjem transakcije.<\/p>\n<p>Kao rezultat goreopisane dorade, ostvarili smo principe ACID:<\/p>\n<ul>\n<li><b>Atomarnost<\/b>. To je jamstvo da nijedna transakcija ne\u0107e biti djelomi\u010dno zabilje\u017eena u sustavu, bit \u0107e ili izvr\u0161ene sve njezine podoperacije ili nijedna. Ovaj princip kod nas se po\u0161tuje zahvaljuju\u0107i logged batch-u u Cassandri.<\/li>\n<li><b>Konsistentnost<\/b>. Svaka uspje\u0161na transakcija po definiciji bilje\u017ei samo dopu\u0161tene rezultate. Ako nakon otvaranja transakcije i izvr\u0161avanja dijela operacija do\u0111e do otkri\u0107a da je rezultat nedopu\u0161ten, izvr\u0161it \u0107e se povratak.<\/li>\n<li><b>Izoliranost<\/b>. Tijekom izvr\u0161avanja transakcije, paralelne transakcije ne bi trebale utjecati na njezin rezultat. Konkurentske transakcije su izolirane pomo\u0107u pesimisti\u010dkih blokada na koordinatoru. Za \u010ditanja izvan transakcije po\u0161tuje se na\u010delo izoliranosti na razini Read Committed.<\/li>\n<li><b>Otpornost<\/b>. Bez obzira na probleme na donjim razinama \u2014 isklju\u010denje sustava, kvar opreme \u2014 promjene izvr\u0161ene uspje\u0161no zavr\u0161enom transakcijom moraju ostati pohranjene nakon obnavljanja rada. <\/li>\n<\/ul>\n<p><\/p>\n<h2>\u010citanje prema indeksima<\/h2>\n<p>\nUzmimo jednostavnu tablicu: <\/p>\n<pre><code>CREATE TABLE photos (\nid bigint primary key,\nowner bigint,\nmodified timestamp,\n\u2026)<\/code><\/pre>\n<p>\nOna ima ID (primarni klju\u010d), vlasnika i datum promjene. Potrebno je napraviti vrlo jednostavan upit \u2014 izabrati podatke prema vlasniku s datumom promjene \"u posljednja 24 sata\". <\/p>\n<pre><code>SELECT *\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nKako bi takav upit brzo djelovao, u klasi\u010dnom SQL DBMS-u potrebno je izgraditi indeks po kolonama (owner, modified). Takvo ne\u0161to mo\u017eemo napraviti dovoljno lako, jer sada imamo jamstva ACID!<\/p>\n<h2>Indeksi u C*One<\/h2>\n<p>\nPostoji izvorna tablica s fotografijama, u kojoj 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 s indeksnim izrazom, a 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 \"vlasniku u posljednjih 24 sata\" mo\u017ee prepisati kao select iz druge tabele:<\/p>\n<pre><code>SELECT * FROM i1_test\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nDosljednost podataka izvorne tabele photos i indeksne i1 automatski odr\u017eava koordinator. Na temelju same sheme podataka, pri prijemu promjene, koordinator generira i pamti promjenu ne samo glavne tabele, ve\u0107 i promjene kopija. Nema dodatnih radnji s tabelom indeksa, logovi se ne \u010ditaju, blokade se ne koriste. Drugim rije\u010dima, dodavanje indeksa gotovo da ne tro\u0161i resurse i prakti\u010dki ne utje\u010de na brzinu izvr\u0161enja modifikacija.<\/p>\n<p>Pomo\u0107u ACID-a uspjeli smo implementirati indekse \"kao u SQL-u\". Oni imaju dosljednost, mogu se skalirati, brzo rade, mogu biti slo\u017eeni i integrirani u jezik upita CQL. Za podr\u0161ku indeksima nije potrebno mijenjati aplikacijski kod. Sve je jednostavno, kao u SQL-u. I \u0161to je najva\u017enije, indeksi ne utje\u010du na brzinu izvr\u0161enja modifikacija izvorne tabele transakcija.<\/p>\n<h2>\u0160to smo postigli<\/h2>\n<p>\nRazvili smo C*One prije tri godine i lansirali u industrijsku primjenu. <\/p>\n<p>\u0160to smo na kraju dobili? Procijenimo to na primjeru podsustava obrade i pohrane fotografija, jednog od najva\u017enijih tipova podataka u dru\u0161tvenoj mre\u017ei. Rije\u010d je o svim vrstama metainformacija, a ne samo o samim fotografijama. Trenutno u \"Odnoklassnicima\" ima oko 20 milijardi takvih zapisa, sustav obra\u0111uje 80 tisu\u0107a upita za \u010ditanje u sekundi, do 8 tisu\u0107a ACID transakcija u sekundi, vezano uz modifikaciju podataka. <\/p>\n<p>Kada smo koristili SQL s replication factor = 1 (ali u RAID 10), metainformacija fotografija pohranjena je na visoko dostupnom klasteru od 32 ma\u0161ine s Microsoft SQL Serverom (plus 11 rezervnih). Tako\u0111er je bilo dodijeljeno 10 servera za pohranu rezervnih kopija. Ukupno 50 skupih ma\u0161ina. Istovremeno, sustav je radio pod nominalnim optere\u0107enjem, bez rezerve.<\/p>\n<p>Nakon migracije na novi sustav dobili smo faktor replikacije = 3 \u2014 po kopiji u svakom podatkovnom centru. Sustav se sastoji od 63 nodova Cassandra skladi\u0161ta i 6 koordinacijskih ma\u0161ina, ukupno 69 servera. Ove ma\u0161ine su me\u0111utim znatno jeftinije, njihova ukupna cijena iznosi oko 30 % cijene sustava na SQL-u. Pri tome je optere\u0107enje na razini od 30 %.<\/p>\n<p>S implementacijom C*One smanjene su i latencije: u SQL-u operacija pisanja trajala je oko 4,5 ms. U C*One \u2014 oko 1,6 ms. Trajanje transakcije u prosjeku je manje od 40 ms, commit se izvr\u0161ava za 2 ms, trajanje \u010ditanja i pisanja \u2014 u prosjeku 2 ms. 99. percentil iznosi samo 3-3,1 ms, broj timeouta smanjen je 100 puta \u2014 sve zahvaljuju\u0107i \u0161irokoj primjeni spekulacija. <\/p>\n<p>Do sada je iz uporabe izba\u010den ve\u0107i dio nodova SQL Servera, novi proizvodi se razvijaju samo kori\u0161tenjem 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 automatiziralo odr\u017eavanje. Bez izvorne koda, to bi bilo znatno slo\u017eenije i zahtjevnije. <\/p>\n<p>Trenutno radimo na prijelazu 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\/hr\/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=\"hr_HR\" \/>\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\/hr\/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 se obra\u0111uju.","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/newsql-nosql-acid","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/37956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=37956"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/37956\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media\/28484"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=37956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=37956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=37956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}