{"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\/nl\/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 \/>\nTot voor kort werden er ongeveer 50 TB aan gegevens in real-time verwerkt in SQL Server bij Odnoklassniki. Voor zo'n volume is het praktisch onmogelijk om een snelle, betrouwbare en ook fouttolerante datacenter-toegang te bieden met een SQL-database. Gewoonlijk worden in dergelijke gevallen een van de NoSQL-opslagplaatsen gebruikt, maar niet alles kan naar NoSQL worden overgezet: bepaalde entiteiten vereisen ACID-transactiegaranties. <\/p>\n<p>Dit bracht ons ertoe om een NewSQL-opslagplaats te gebruiken, dat wil zeggen een DBMS dat fouttolerantie, schaalbaarheid en snelheid biedt van NoSQL-systemen, maar tegelijkertijd de bekende ACID-garanties van klassieke systemen behoudt. Er zijn niet veel werkende industri\u00eble systemen van deze nieuwe klasse, daarom hebben we zo'n systeem zelf ge\u00efmplementeerd en in commerci\u00eble exploitatie gebracht. <\/p>\n<p>Hoe dit werkt en wat we hebben bereikt \u2014 lees verder.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nVandaag de dag bedraagt het maandelijkse publiek van 'Odnoklassniki' meer dan 70 miljoen unieke bezoekers. Wij <noindex><a rel=\"nofollow\" href=\"https:\/\/www.similarweb.com\/top-websites\/category\/internet-and-telecom\/social-network\">vallen binnen de top vijf<\/a><\/noindex> grootste sociale netwerken ter wereld, en behoren tot de twintig websites waar gebruikers de meeste tijd doorbrengen. De infrastructuur van 'OK' verwerkt zeer hoge belasting: meer dan een miljoen HTTP-verzoeken per seconde aan de fronten. Delen van het serverpark, bestaande uit meer dan 8000 stuks, zijn dicht bij elkaar gelegen \u2014 in vier datacentra in Moskou, wat zorgt voor een netwerklatentie van minder dan 1 ms tussen hen.<\/p>\n<p>We gebruiken Cassandra sinds 2010, te beginnen met versie 0.6. Vandaag de dag zijn er tientallen clusters in gebruik. Het snelste cluster verwerkt meer dan 4 miljoen operaties per seconde, en het grootste slaat 260 TB op. <\/p>\n<p>Echter, al deze zijn gewone NoSQL-clusters, die worden gebruikt voor het opslaan van <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\">zwak gematchte<\/a><\/noindex> gegevens. Wij wilden echter de belangrijkste consistente opslag vervangen, Microsoft SQL Server, dat sinds de oprichting van 'Odnoklassniki' werd gebruikt. De opslag bestond uit meer dan 300 SQL Server Standard Edition machines, waarop 50 TB aan gegevens \u2014 zakelijke entiteiten \u2014 waren opgeslagen. Deze gegevens worden gemodificeerd in het kader van ACID-transacties en vereisen <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">hoge consistentie<\/a><\/noindex>.<\/p>\n<p>Voor de verdeling van gegevens over de knooppunten van SQL Server hebben we zowel verticale als horizontale <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Partition_(database)\">partitionering gebruikt.<\/a><\/noindex> (sharding). Historisch gezien hebben we een eenvoudige datascharnier schema gebruikt: elke entiteit werd gekoppeld aan een token \u2013 een functie van de entiteit ID. Entiteiten met dezelfde token werden op dezelfde SQL-server geplaatst. De master-detail relatie werd zo gerealiseerd dat de tokens van het hoofd- en afgeleide record altijd overeenkwamen en zich op dezelfde server bevonden. In het sociale netwerk worden bijna alle records gegenereerd namens de gebruiker \u2013 dat betekent dat alle gebruikersgegevens binnen een functioneel subsysteem op \u00e9\u00e9n server worden opgeslagen. Dit betekent dat bijna altijd tabellen van dezelfde SQL-server betrokken waren bij zakelijke transacties, wat het mogelijk maakte om gegevensconsistentie te waarborgen met lokale ACID-transacties, zonder de noodzaak voor gebruik <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">trage en onbetrouwbare<\/a><\/noindex> gedistribueerde ACID-transacties.<\/p>\n<p>Dankzij sharding en om de werking van SQL te versnellen:<\/p>\n<ul>\n<li>We gebruiken geen Foreign key constraints, aangezien bij sharding de entiteit ID zich op een andere server kan bevinden.<\/li>\n<li>We gebruiken geen opgeslagen procedures en triggers vanwege de extra belasting op de CPU van de DBMS.<\/li>\n<li>We gebruiken geen JOINs vanwege al het bovenstaande en talloze willekeurige leesacties vanaf de schijf.<\/li>\n<li>Buiten transacties gebruiken we het isolatieniveau Read Uncommitted om deadlocks te minimaliseren.<\/li>\n<li>We voeren alleen korte transacties uit (gemiddeld korter dan 100 ms).<\/li>\n<li>We gebruiken geen multi-row UPDATE en DELETE vanwege het grote aantal deadlocks \u2013 we werken alleen \u00e9\u00e9n record bij.<\/li>\n<li>De queries worden altijd uitsluitend via de indexen uitgevoerd \u2013 een query met een plan voor een volledige tabelscan betekent voor ons een overbelasting van de database en een storing.<\/li>\n<\/ul>\n<p>\nDeze stappen hebben ons geholpen bijna het maximale uit SQL-servers te halen. Echter, de problemen werden steeds talrijker. Laten we ze bekijken.<\/p>\n<h2>Problemen met SQL<\/h2>\n<p><\/p>\n<ul>\n<li>Omdat we onze eigen sharding hebben gebruikt, werd het toevoegen van nieuwe shards handmatig door beheerders uitgevoerd. Gedurende deze tijd behandelden schaalbare gegevensreplica's geen aanvragen. <\/li>\n<li>Naarmate het aantal records in de tabel groeide, nam de snelheid van invoegen en modificeren af; het toevoegen van indexen aan een bestaande tabel leidde tot een significante snelheidsdaling, en het maken en opnieuw maken van indexen ging gepaard met downtime.<\/li>\n<li>Het hebben van een beperkt aantal Windows voor SQL Server in productie bemoeilijkt het beheer van de infrastructuur.<\/li>\n<\/ul>\n<p>\nMaar het grootste probleem is \u2014 <\/p>\n<h2>Resilience<\/h2>\n<p>\nEen traditionele SQL-server heeft een slechte fouttolerantie. Stel dat u maar \u00e9\u00e9n database-server heeft en deze om de drie jaar uitvalt. Tijdens deze tijd is de website 20 minuten niet bereikbaar, wat acceptabel is. Maar als u 64 servers heeft, dan is de website om de drie weken niet bereikbaar. En als u 200 servers heeft, dan is de website elke week niet bereikbaar. Dat is een probleem. <\/p>\n<p>Wat kan er gedaan worden om de fouttolerantie van de SQL-server te verbeteren? Wikipedia stelt voor om een <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/High-availability_cluster\">high-availability cluster<\/a><\/noindex>: te bouwen waar, in geval van uitval van een van de componenten, er een duplicaat is.<\/p>\n<p>Dit vereist een park dure apparatuur: talrijke duplicaten, glasvezel, gedeelde opslag, en het inschakelen van reserve werkt onbetrouwbaar; ongeveer 10% van de inschakelingen eindigt in een storing van de reserveknoop die de hoofdknop volgt. <\/p>\n<p>Maar het grootste nadeel van zo'n high-availability cluster is de nulbeschikbaarheid bij uitval van het datacenter waar het zich bevindt. 'Odnoklassniki' heeft vier datacenters, en we moeten ervoor zorgen dat we blijven functioneren bij een totale storing in een van hen.<\/p>\n<p>Hiervoor zouden we <noindex><a rel=\"nofollow\" href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms151196.aspx\">Multi-Master<\/a><\/noindex> replicatie kunnen toepassen, ingebouwd in SQL Server. Deze oplossing is veel duurder door de softwarekosten en lijdt aan de bekende problemen met replicatie \u2014 onvoorspelbare transactievertragingen bij synchrone replicatie en vertragingen bij het toepassen van replicaties (en als gevolg daarvan verloren aanpassingen) bij asynchrone replicatie. Tevens impliceert het <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\">handmatige conflictresolutie<\/a><\/noindex> dit alternatief volledig ongeschikt voor ons.<\/p>\n<p>Al deze problemen vereisten een radicale oplossing en we begonnen met een gedetailleerde analyse. Hier moeten we kennismaken met wat SQL Server voornamelijk doet \u2014 transacties.<\/p>\n<h2>Een eenvoudige transactie<\/h2>\n<p>\nLaten we de eenvoudigste transactie beschouwen, vanuit het perspectief van een SQL-programmeur: het toevoegen van een foto aan een album. Albums en foto's worden in verschillende tabellen opgeslagen. Een album heeft een teller voor openbare foto's. Dan wordt zo'n transactie opgedeeld in de volgende stappen: <\/p>\n<ol>\n<li>We vergrendelen het album op sleutel.<\/li>\n<li>We cre\u00ebren een record in de fototabel. <\/li>\n<li>Als de foto een openbaar statuut heeft, verhogen we de teller voor openbare foto's in het album, werken we het record bij en committeren we de transactie.<\/li>\n<\/ol>\n<p>\nOf in de vorm van pseudocode:<\/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>\nWe zien dat het meest voorkomende scenario voor zakelijke transacties is om gegevens uit de database naar het geheugen van de applicatieserver te lezen, iets te wijzigen en de nieuwe waarden opnieuw in de database op te slaan. Gewoonlijk werken we in zo'n transactie meerdere entiteiten en tabellen bij. <\/p>\n<p>Tijdens de uitvoering van een transactie kan er concurrerende wijziging van dezelfde gegevens uit een ander systeem plaatsvinden. Bijvoorbeeld, Antispam kan besluiten dat een gebruiker verdacht is, waardoor alle foto's van die gebruiker niet langer openbaar moeten zijn, ze moeten naar moderatie worden gestuurd, wat betekent dat photo.status op een andere waarde moet worden gezet en de bijbehorende tellers moeten worden aangepast. Het is duidelijk dat als deze operatie plaatsvindt zonder garanties voor de atomariteit van de toepassing en isolatie van concurrerende wijzigingen, zoals in <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>, het resultaat niet zal zijn wat nodig is \u2014 of de fotocounter een onjuiste waarde zal tonen, of niet alle foto's zullen naar moderatie worden verzonden. <\/p>\n<p>Er is in de geschiedenis van Odnoklassniki veel code geschreven die met verschillende zakelijke entiteiten binnen \u00e9\u00e9n transactie manipuleert. Uit ervaring met migraties naar NoSQL met <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">Eventual Consistency<\/a><\/noindex> weten we dat de grootste moeilijkheden (en de meeste tijdsinvesteringen) voortkomen uit de noodzaak om code te ontwikkelen die gericht is op het handhaven van de consistentie van gegevens. Daarom beschouwden we als belangrijkste vereiste voor de nieuwe opslag de garantie voor de applicatielogica van echte ACID-transacties. <\/p>\n<p>Andere niet minder belangrijke vereisten waren:<\/p>\n<ul>\n<li>Bij een storing van het datacenter moeten zowel lezen als schrijven naar de nieuwe opslag beschikbaar zijn.<\/li>\n<li>Behoud van de huidige snelheid van ontwikkeling. Dat betekent dat bij het werken met de nieuwe opslag de hoeveelheid code ongeveer hetzelfde moet blijven, zonder dat er de noodzaak ontstaat om iets aan de opslag toe te voegen, conflictoplossingsalgoritmen te ontwikkelen, secundaire indexen, enz. te onderhouden. <\/li>\n<li>De snelheid van de nieuwe opslag moet hoog genoeg zijn, zowel bij het lezen van gegevens als bij het verwerken van transacties, wat effectief het gebruik van academisch strikte, universele, maar langzame oplossingen, zoals <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">twee-fasen commits<\/a><\/noindex>.<\/li>\n<li>Automatische schaling in real-time. <\/li>\n<li>Gebruik van gewone goedkope servers, zonder dat er exotische hardware aangeschaft hoeft te worden. <\/li>\n<li>De mogelijkheid om de opslag te ontwikkelen met hulp van de ontwikkelaars van het bedrijf. Met andere woorden, de voorkeur ging uit naar eigen of op open-source gebaseerde oplossingen, bij voorkeur in Java.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Oplossingen, oplossingen<\/h2>\n<p>\nBij het analyseren van mogelijke oplossingen zijn we aangekomen bij twee mogelijke architectuurkeuzes:<\/p>\n<p>De eerste is om een SQL-server te nemen en de nodige fouttolerantie, schaalmechanisme, fouttolerante cluster, conflictresolutie en gedistribueerde, betrouwbare en snelle ACID-transacties te implementeren. We hebben deze optie als vrij complex en tijdrovend beoordeeld.<\/p>\n<p>De tweede optie is om een kant-en-klaar NoSQL-opslag te nemen met ge\u00efmplementeerde schaling, een fouttolerant cluster, conflictresolutie en zelf transacties en SQL te implementeren. Op het eerste gezicht lijkt zelfs de taak om SQL te implementeren, om nog maar te zwijgen van ACID-transacties, een klus voor jaren. Maar toen realiseerden we ons dat de set mogelijkheden van SQL die we in de praktijk gebruiken, zo ver van ANSI SQL verwijderd is als <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Apache_Cassandra#Cassandra_Query_Language\">Cassandra CQL<\/a><\/noindex> ver weg van ANSI SQL. Toen we nog eens goed naar CQL keken, realiseerden we ons dat het vrij dicht bij was wat we nodig hadden.<\/p>\n<h2>Cassandra en CQL<\/h2>\n<p>\nDus, wat maakt Cassandra interessant, welke mogelijkheden heeft het?<\/p>\n<p>Ten eerste, hier kunnen tabellen worden aangemaakt die verschillende datatypes ondersteunen, en je kunt SELECT of UPDATE uitvoeren op de primaire sleutel.<\/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>\nOm de consistentie van de gegevensreplica's te waarborgen, gebruikt Cassandra <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Quorum_(distributed_computing)\">een quorumbenadering<\/a><\/noindex>. In de eenvoudigste zin betekent dit dat wanneer drie replicaten van dezelfde rij op verschillende knooppunten van het cluster worden geplaatst, de registratie als succesvol wordt beschouwd als de meerderheid van de knooppunten (d.w.z. twee van de drie) het succes van deze registratieoperatie bevestigt. De gegevens van de rij worden als consistent beschouwd als de meerderheid van de knooppunten is ondervraagd en deze heeft bevestigd. Hierdoor garandeert de aanwezigheid van drie replicaten volledige en onmiddellijke gegevensconsistentie bij uitval van \u00e9\u00e9n knooppunt. Deze aanpak stelde ons in staat om een nog betrouwbaardere regeling te implementeren: altijd verzoeken naar alle drie replicaten te sturen, wachtend op een reactie van de twee snelste. De vertraagde reactie van de derde replica wordt in dit geval afgewezen. Het vertraagde knooppunt kan ernstige problemen ondervinden \u2014 vertraging, garbage collection in de JVM, direct memory reclaim in de Linux-kernel, hardwarestoringen, loskoppeling van het netwerk. Echter, dit heeft geen invloed op de operaties van de klant en op de gegevens.<\/p>\n<p>De aanpak waarbij we drie knooppunten aanspreken en een antwoord van twee ontvangen, wordt <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Speculative_execution\">speculatie<\/a><\/noindex>: een verzoek naar overtollige replicaten wordt al verzonden voordat het 'uiteindelijk uitvalt'. <\/p>\n<p>Een ander voordeel van Cassandra is Batchlog \u2014 een mechanisme dat garandeert dat een pakket met wijzigingen volledig wordt toegepast of volledig niet wordt toegepast. Dit stelt ons in staat om de A in ACID \u2014 atomiciteit uit de doos \u2014 op te lossen.<\/p>\n<p>Het dichtstbijzijnde bij transacties in Cassandra is de zogenaamde &#171;<noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_using\/useInsertLWT.html\">lightweight transactions<\/a><\/noindex>&#171;. Maar ze zijn ver verwijderd van \"echte\" ACID-transacties: in werkelijkheid is het de mogelijkheid om te doen <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compare-and-swap\">CAS<\/a><\/noindex> op gegevens van slechts \u00e9\u00e9n record uit te voeren, gebruikmakend van consensus via het zware Paxos-protocol. Daarom is de snelheid van dergelijke transacties laag. <\/p>\n<h2>Wat ons ontbrak in Cassandra<\/h2>\n<p>\nDus, we moesten echte ACID-transacties in Cassandra implementeren. Met behulp waarvan we gemakkelijk twee andere handige mogelijkheden van traditionele DBMS konden realiseren: consistente snelle indexen, wat ons zou in staat stellen om niet alleen op de primaire sleutel te selecteren, en een gewone generator van monotone auto-increment ID's.<\/p>\n<h4>C*One<\/h4>\n<p>\nHieruit ontstond een nieuwe database <b>C*One<\/b>, bestaande uit drie typen serverknopen:<\/p>\n<ul>\n<li>Opslag \u2014 (bijna) standaard Cassandra-servers die verantwoordelijk zijn voor het opslaan van gegevens op lokale schijven. Naarmate de belasting en de hoeveelheid gegevens toenemen, kan hun aantal eenvoudig worden opgeschaald tot tientallen en honderden.<\/li>\n<li>Transactionco\u00f6rdinatoren zorgen voor de uitvoering van transacties. <\/li>\n<li>Klanten zijn de applicatieservers die bedrijfsoperaties uitvoeren en transacties initi\u00ebren. Er kunnen duizenden van deze klanten zijn.<\/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 \/>\nServers van alle typen maken deel uit van een algemeen cluster, gebruiken het interne berichtenprotocol Cassandra voor communicatie met elkaar en <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip<\/a><\/noindex> voor uitwisseling van clusterinformatie. Met behulp van Heartbeat leren servers van elkaars falen, onderhouden ze een uniforme datamodel \u2013 tabellen, hun structuur en replicatie; de partitionering schema, topologie van het cluster, enz.<\/p>\n<h4>Klanten<\/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 \/>\nIn plaats van standaarddrivers wordt de modus van Fat Client gebruikt. Zo'n node slaat geen gegevens op, maar kan fungeren als co\u00f6rdinator voor de uitvoering van verzoeken, dat wil zeggen dat de klant zelf de functie van co\u00f6rdinator van zijn verzoeken uitvoert: het vraagt \u200b\u200bde replicaten van de opslag en lost conflicten op. Dit is niet alleen betrouwbaarder en sneller dan de standaarddriver die communicatie met een externe co\u00f6rdinator vereist, maar stelt ook in staat de overdracht van verzoeken te beheren. Buiten een open transactie op de client worden verzoeken naar de opslag verzonden. Als de klant echter een transactie heeft geopend, worden alle verzoeken binnen de transactie naar de transactieco\u00f6rdinator gestuurd.<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>Transactieco\u00f6rdinator C*One<\/h2>\n<p>\nDe co\u00f6rdinator is wat we vanaf nul hebben ge\u00efmplementeerd voor C*One. Hij is verantwoordelijk voor het beheer van transacties, vergrendelingen en de volgorde van de toepassing van transacties.<\/p>\n<p>Voor elke bediende transactie genereert de co\u00f6rdinator een tijdstempel: elke volgende is groter dan de vorige transactie. Aangezien in Cassandra het systeem voor conflictoplossing is gebaseerd op tijdstempels (van twee conflicterende records wordt de meest actuele beschouwd met de laatste tijdstempel), zal een conflict altijd in het voordeel van de volgende transactie worden opgelost. Op deze manier hebben we <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\">Lamportklokken<\/a><\/noindex> \u2014 een goedkope manier om conflicten in een gedistribueerd systeem op te lossen.<\/p>\n<h2>Vergrendelingen<\/h2>\n<p>\nOm isolatie te waarborgen, hebben we besloten de eenvoudigste manier te gebruiken \u2014 pessimistische vergrendelingen op de primaire sleutel van het record. Met andere woorden, in de transactie moet het record eerst worden vergrendeld, daarna gelezen, gemodificeerd en opgeslagen. Pas na een succesvolle commit kan het record worden ontgrendeld, zodat concurrerende transacties het kunnen gebruiken.<\/p>\n<p>De implementatie van een dergelijke blokkering is eenvoudig in een niet-gedistribueerde omgeving. In een gedistribueerd systeem zijn er twee hoofdwegen: ofwel een gedistribueerde blokkering implementeren binnen het cluster, ofwel de transacties verdelen zodat de transacties met betrekking tot een bepaalde registratie altijd door dezelfde co\u00f6rdinator worden afgehandeld.<\/p>\n<p>Aangezien de gegevens in ons geval al zijn verdeeld over groepen van lokale transacties in SQL, is besloten om co\u00f6rdinatoren te koppelen aan groepen lokale transacties: \u00e9\u00e9n co\u00f6rdinator voert alle transacties uit met tokens van 0 tot 9, de tweede co\u00f6rdinator met tokens van 10 tot 19, enzovoort. Dit resulteert erin dat elk van de co\u00f6rdinatoren de master van de transactiegroep wordt. <\/p>\n<p>Blokkeringen kunnen dan worden ge\u00efmplementeerd als een eenvoudige HashMap in het geheugen van de co\u00f6rdinator.<\/p>\n<h2>Falen van co\u00f6rdinatoren<\/h2>\n<p>\nAangezien \u00e9\u00e9n co\u00f6rdinator uitsluitend een groep transacties bedient, is het van groot belang om snel het falen van deze co\u00f6rdinator vast te stellen, zodat de herhaling van de uitvoering van de transactie binnen de timeout past. Om dit snel en betrouwbaar te doen, hebben we een volledig verbonden quorum-heartbeatprotocol toegepast:<\/p>\n<p>In elk datacenter zijn er minimaal twee co\u00f6rdinatornodes aanwezig. Periodiek verzendt elke co\u00f6rdinator heartbeat-berichten naar de andere co\u00f6rdinatoren en informeert hen over zijn werking, evenals over welke heartbeat-berichten van welke co\u00f6rdinatoren in het cluster hij voor het laatst heeft ontvangen. <\/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 \/>\nDoor vergelijkbare informatie van de anderen te ontvangen in hun heartbeat-berichten, beslist elke co\u00f6rdinator voor zichzelf welke nodes in het cluster operationeel zijn en welke niet, volgens het quorumprincipe: als node X informatie heeft ontvangen over normale ontvangst van berichten van node Y van de meerderheid van de nodes in het cluster, betekent dit dat Y werkt. Omgekeerd, zodra de meerderheid meldt geen berichten meer van node Y te ontvangen, betekent dit dat Y heeft gefaald. Het is interessant dat als het quorum node X meldt dat het geen berichten meer ontvangt, node X zichzelf zal beschouwen als zijnde in storing.<\/p>\n<p>Heartbeat-berichten worden met een hoge frequentie verzonden, ongeveer 20 keer per seconde, met een interval van 50 ms. In Java is het moeilijk om de respons van de applicatie binnen 50 ms te garanderen vanwege de vergelijkbare duur van pauzes die worden veroorzaakt door de garbage collector. We hebben in staat kunnen stellen om deze responstijd te bereiken door de G1 garbage collector te gebruiken, die het mogelijk maakt om een doel te stellen voor de duur van GC-pauzes. Echter, soms, en dat is zeldzaam, overschrijden de pauzes van de garbage collector de 50 ms, wat kan leiden tot een valse detectie van uitval. Om dit te voorkomen, rapporteert de co\u00f6rdinator de uitval van een externe node niet bij het missen van de eerste heartbeat-bericht van die node, alleen als er meerdere op rij zijn verdwenen. Op deze manier konden we de uitval van de co\u00f6rdinator node binnen 200 ms detecteren. <\/p>\n<p>Maar het is niet genoeg om snel te begrijpen welke node gestopt is met functioneren. We moeten hier iets mee doen. <\/p>\n<h2>Redundantie<\/h2>\n<p>\nHet klassieke schema voorziet, in geval van uitval van de master, in het starten van verkiezingen voor een nieuwe via een van de<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\"> modieuze<\/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\">universele<\/a><\/noindex> algoritmen. Echter, dergelijke algoritmen hebben goed bekende problemen met convergentie in de tijd en de duur van het verkiezingsproces zelf. Dergelijke extra vertragingen konden we vermijden door gebruik te maken van een schema voor het vervangen van co\u00f6rdinatoren in een volledig verbonden netwerk:<\/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 \/>\nStel dat we een transactie willen uitvoeren in groep 50. We defini\u00ebren van tevoren het vervangingsschema, dat wil zeggen welke nodes de transacties van groep 50 zullen uitvoeren in het geval van uitval van de hoofdco\u00f6rdinator. Ons doel is om de werking van het systeem te behouden bij de uitval van een datacenter. We bepalen dat de eerste reserve een node uit een ander datacenter zal zijn, en de tweede reserve een node uit een derde. Dit schema wordt \u00e9\u00e9n keer gekozen en verandert niet totdat de topologie van het cluster verandert, dat wil zeggen totdat er nieuwe nodes bij komen (wat zeer zelden gebeurt). De volgorde van het kiezen van een nieuwe actieve master bij de uitval van de oude zal altijd als volgt zijn: de eerste reserve wordt de actieve master, en als deze ook stopt met functioneren, dan de tweede reserve. <\/p>\n<p>Dit schema is betrouwbaarder dan een universeel algoritme, aangezien voor het activeren van een nieuwe master het voldoende is om het feit van de uitval van de oude vast te stellen.<\/p>\n<p>Maar hoe begrijpen klanten welke meester momenteel aan het werk is? Het is onmogelijk om binnen 50 ms informatie naar duizenden klanten te verzenden. Er kan een situatie ontstaan waarin een klant een verzoek indient voor het openen van een transactie, zonder te weten dat deze meester al niet meer functioneert, en het verzoek blijft hangen in een time-out. Om dit te voorkomen, sturen klanten speculatief een verzoek naar de groep meester en beide reserves, maar alleen diegene die op dat moment actief is, zal op dit verzoek reageren. Alle verdere communicatie binnen de transactie zal de klant alleen met de actieve meester uitvoeren.<\/p>\n<p>Reserve-meesters plaatsen ontvangen verzoeken voor transacties die niet van henzelf zijn in de wachtrij van ongeboren transacties, waar ze enige tijd worden bewaard. Als de actieve meester sterft, verwerkt de nieuwe meester de verzoeken voor het openen van transacties uit zijn wachtrij en reageert op de klant. Als de klant al een transactie heeft geopend met de oude meester, wordt het tweede antwoord genegeerd (en zal deze transactie, uiteraard, niet worden voltooid en opnieuw door de klant worden uitgevoerd).<\/p>\n<h2>Hoe de transactie werkt<\/h2>\n<p>\nStel dat de klant een verzoek heeft gestuurd naar de co\u00f6rdinator om een transactie te openen voor een bepaalde entiteit met een bepaalde primaire sleutel. De co\u00f6rdinator blokkeert deze entiteit en plaatst deze in de blokkeringstabel in het geheugen. Indien nodig leest de co\u00f6rdinator deze entiteit uit de opslag en slaat de verkregen gegevens op in de status van de transactie in het geheugen van de co\u00f6rdinator.<\/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 \/>\nWanneer de klant gegevens in de transactie wil wijzigen, stuurt hij een verzoek voor modificatie van de entiteit naar de co\u00f6rdinator, die de nieuwe gegevens in de tabel van transactietoestanden in het geheugen plaatst. Hier eindigt de registratie \u2014 er vindt geen registratie in de opslag plaats.<\/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 \/>\nWanneer de klant binnen een actieve transactie om zijn eigen gewijzigde gegevens vraagt, handelt de co\u00f6rdinator als volgt: <\/p>\n<ul>\n<li>als het ID al in de transactie bestaat, worden de gegevens uit het geheugen gehaald; <\/li>\n<li>als het ID niet in het geheugen staat, worden de ontbrekende gegevens uit de opslagknopen gelezen, gecombineerd met de al aanwezige gegevens in het geheugen, en het resultaat wordt aan de klant gegeven. <\/li>\n<\/ul>\n<p>\nOp deze manier kan de klant zijn eigen wijzigingen lezen, terwijl andere klanten deze wijzigingen niet zien, omdat ze alleen in het geheugen van de co\u00f6rdinator worden opgeslagen; ze zijn nog niet in de Cassandra-knopen.<\/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 \/>\nWanneer een klant een commit verzendt, wordt de toestand die in het geheugen van de service aanwezig was door de co\u00f6rdinator opgeslagen in de logged batch, en deze wordt vervolgens in de vorm van een logged batch naar de opslaglocaties in Cassandra verzonden. De opslaglocaties zorgen ervoor dat deze batch atomair (volledig) wordt toegepast en retourneren een antwoord aan de co\u00f6rdinator, die vervolgens de vergrendelingen vrijgeeft en de succesvolle transactie aan de klant bevestigt.<\/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 \/>\nEn om terug te draaien, hoeft de co\u00f6rdinator alleen maar het geheugengebruik van de transactie vrij te geven.<\/p>\n<p>Als gevolg van de bovengenoemde verbeteringen hebben we de ACID-principes ge\u00efmplementeerd:<\/p>\n<ul>\n<li><b>Atomiciteit<\/b>. Dit garandeert dat geen enkele transactie gedeeltelijk in het systeem wordt vastgelegd, alle suboperaties worden ofwel allemaal uitgevoerd ofwel geen enkele. Dit principe wordt bij ons gehandhaafd door middel van de logged batch in Cassandra.<\/li>\n<li><b>Consistentie<\/b>. Elke succesvolle transactie legt per definitie alleen geldige resultaten vast. Als na het openen van de transactie en het uitvoeren van een deel van de operaties blijkt dat het resultaat ongeldig is, wordt er een terugrol uitgevoerd.<\/li>\n<li><b>Isolatie<\/b>. Bij het uitvoeren van een transactie mogen parallelle transacties geen invloed hebben op het resultaat. Concurrente transacties worden ge\u00efsoleerd door middel van pessimistische vergrendelingen op de co\u00f6rdinator. VoorLeesoperaties buiten de transactie wordt het isolatieprincipe op het niveau van Read Committed gehandhaafd.<\/li>\n<li><b>Veerkracht<\/b>. Ongeacht de problemen op lagere niveaus - systeemuitval, hardwarestoringen - moeten wijzigingen die door een succesvol voltooide transactie zijn aangebracht, bewaard blijven na het hervatten van de werking. <\/li>\n<\/ul>\n<p><\/p>\n<h2>Lezen via indexen<\/h2>\n<p>\nLaten we een eenvoudige tabel nemen: <\/p>\n<pre><code>CREATE TABLE photos (\nid bigint primary key,\neigenaar bigint,\ngewijzigd timestamp,\n\u2026)<\/code><\/pre>\n<p>\nDeze heeft een ID (primaire sleutel), een eigenaar en een wijzigingsdatum. We moeten een heel eenvoudige query maken - kies gegevens op basis van de eigenaar met de wijzigingsdatum 'in de afgelopen 24 uur'. <\/p>\n<pre><code>SELECT *\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nOm een dergelijke query snel uit te voeren, moet er in een klassieke SQL-database een index voor de kolommen (owner, modified) worden gemaakt. Dit kunnen we vrij eenvoudig doen, aangezien we nu garanties hebben voor ACID!<\/p>\n<h2>Indexen in C*One<\/h2>\n<p>\nEr is een oorsprongstabel met foto's, waarbij de ID van de record de primaire sleutel is. <\/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 \/>\nVoor de index cre\u00ebert C*One een nieuwe tabel die een kopie van de oorspronkelijke is. De sleutel komt overeen met de indexexpressie, bovendien omvat deze ook de primaire sleutel van de record uit de oorspronkelijke tabel:<\/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 \/>\nDe nu beschikbare query voor 'eigenaar van de laatste 24 uur' kan herschreven worden als select uit een andere tabel:<\/p>\n<pre><code>SELECT * FROM i1_test\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nDe consistentie van de oorspronkelijke tabel photos en de index tabel i1 wordt automatisch door de co\u00f6rdinator gehandhaafd. Op basis van alleen het datamodel genereert en onthoudt de co\u00f6rdinator wijzigingen niet alleen voor de hoofdtabel, maar ook voor de kopie\u00ebn. Er zijn geen extra handelingen nodig met de index tabel, logs worden niet gelezen, en er worden geen blokkeringen gebruikt. Dit betekent dat het toevoegen van indexen bijna geen middelen verbruikt en praktisch geen invloed heeft op de snelheid van de aanpassing van modificaties.<\/p>\n<p>Met behulp van ACID hebben we 'indexen zoals in SQL' kunnen realiseren. Ze zijn consistent, kunnen schalen, werken snel, kunnen samengesteld zijn en zijn ingebouwd in de CQL-querytaal. Voor de ondersteuning van indexen zijn er geen wijzigingen in de applicatiecode nodig. Het is zo eenvoudig als in SQL. En het belangrijkste is dat indexen geen invloed hebben op de snelheid van de uitvoering van modificaties van de transactiehoofdtabel.<\/p>\n<h2>Wat we hebben verkregen<\/h2>\n<p>\nWe hebben C*One drie jaar geleden ontwikkeld en in productie genomen. <\/p>\n<p>Wat hebben we uiteindelijk bereikt? Laten we dit evalueren aan de hand van het voorbeeld van het subsysteem voor de verwerking en opslag van foto's, een van de belangrijkste datatypes in sociale netwerken. Het gaat niet om de foto-inhoud zelf, maar om de verschillende metadata. Op dit moment zijn er in 'Od\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0438' ongeveer 20 miljard van dergelijke records, en het systeem verwerkt 80.000 leesverzoeken per seconde, tot 8.000 ACID-transacties per seconde gerelateerd aan datamodificaties. <\/p>\n<p>Toen we SQL gebruikte met een replicatiefactor = 1 (maar in RAID 10), werd de metadata van de foto's opgeslagen op een hoogbeschikbare cluster van 32 machines met Microsoft SQL Server (plus 11 back-ups). Daarnaast waren er 10 servers toegewezen voor het opslaan van back-ups. In totaal 50 dure machines. Het systeem werkte echter bij nominale belasting, zonder reserve.<\/p>\n<p>Na de migratie naar het nieuwe systeem hebben we een replicatiefactor = 3 gekregen \u2014 \u00e9\u00e9n kopie in elk datacenter. Het systeem bestaat uit 63 Cassandra-opslagnodes en 6 co\u00f6rdinatormachines, in totaal 69 servers. Maar deze machines zijn aanzienlijk goedkoper, hun totale kosten bedragen ongeveer 30% van de kosten van het systeem op SQL. De belasting blijft op ongeveer 30%.<\/p>\n<p>Met de implementatie van C*One zijn de vertragingen verminderd: in SQL duurde de schrijfbewerking ongeveer 4,5 ms. In C*One is dat ongeveer 1,6 ms. De transactieduur is gemiddeld minder dan 40 ms, de commit vindt plaats in 2 ms, de lees- en schrijfduren zijn gemiddeld 2 ms. De 99e percentiel is slechts 3-3,1 ms, het aantal time-outs is met 100 keer verminderd \u2014 alles dankzij het brede gebruik van speculaties. <\/p>\n<p>Op dit moment zijn de meeste SQL Server-nodes al uit gebruik genomen, nieuwe producten worden alleen ontwikkeld met gebruik van C*One. We hebben C*One aangepast voor gebruik in onze cloud. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/odnoklassniki\/blog\/346868\/\">one-cloud<\/a><\/noindex>, wat het mogelijk maakte om de implementatie van nieuwe clusters te versnellen, de configuratie te vereenvoudigen en het onderhoud te automatiseren. Zonder de broncode zou dit veel moeilijker en omslachtiger zijn geweest. <\/p>\n<p>Momenteel zijn we bezig met het migreren van andere opslagplaatsen naar de cloud \u2014 maar dat is al een heel ander verhaal.<br \/>\n<br \/>Bron: <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.3 - 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\/nl\/blog\/administrirovanie\/newsql-nosql-acid\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\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\/nl\/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":"Tot voor kort waren er ongeveer 50 TB aan gegevens in Odnoklassniki die werden verwerkt.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/newsql-nosql-acid","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/37956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=37956"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/37956\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/28484"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=37956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=37956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=37956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}