{"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\/da\/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 \/>\nIndtil for nylig opbevarede Odnoklassniki omkring 50 TB data, der blev behandlet i realtid, i SQL Server. At sikre hurtig, p\u00e5lidelig og fejltolerant adgang til datacenteret for en s\u00e5 stor m\u00e6ngde data ved hj\u00e6lp af en SQL-database er praktisk talt umuligt. I s\u00e5danne tilf\u00e6lde bruger man typisk et af NoSQL-lagringssystemerne, men ikke alt kan overf\u00f8res til NoSQL: nogle enheder kr\u00e6ver garantier for ACID-transaktioner. <\/p>\n<p>Dette f\u00f8rte os til at bruge et NewSQL-lagringssystem, dvs. en database, der tilbyder fejltolerance, skalerbarhed og hastighed fra NoSQL-systemer, men samtidig bevarer de klassiske systems ACID-garantier. Der er ikke mange fungerende industrielle systemer af denne nye klasse, s\u00e5 vi har selv implementeret et s\u00e5dant system og taget det i drift. <\/p>\n<p>Hvordan det fungerer, og hvad vi har opn\u00e5et \u2013 l\u00e6s videre.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nI dag har \u00abOdnoklassniki\u00bb mere end 70 millioner unikke bes\u00f8gende om m\u00e5neden. Vi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.similarweb.com\/top-websites\/category\/internet-and-telecom\/social-network\">er blandt de fem bedste<\/a><\/noindex> st\u00f8rste sociale netv\u00e6rk i verden og i top tyve over de websites, hvor brugerne bruger mest tid. Infrastrukturene i \u00abOK\u00bb behandler meget h\u00f8je belastninger: mere end en million HTTP-anmodninger\/sekund til fronten. Delene af serverparken, som t\u00e6ller over 8000 enheder, er placeret t\u00e6t p\u00e5 hinanden \u2013 i fire datacentre i Moskva, hvilket g\u00f8r det muligt at opretholde en netv\u00e6rksforsinkelse p\u00e5 mindre end 1 ms mellem dem.<\/p>\n<p>Vi har brugt Cassandra siden 2010, startende med version 0.6. I dag er der flere dusin klynger i drift. Den hurtigste klynge h\u00e5ndterer mere end 4 millioner operationer i sekundet, og den st\u00f8rste gemmer 260 TB. <\/p>\n<p>Men alt dette er almindelige NoSQL-klynger, der bruges til lagring af <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\">svagt konsistente<\/a><\/noindex> data. Vi \u00f8nskede derimod at erstatte det prim\u00e6re konsistente lager, Microsoft SQL Server, som har v\u00e6ret brugt siden Odnoklassniki's grundl\u00e6ggelse. Lagringen bestod af mere end 300 SQL Server Standard Edition-maskiner, der indeholdt 50 TB data \u2013 forretningsenheder. Disse data modificeres inden for ACID-transaktioner og kr\u00e6ver <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">h\u00f8j konsistens<\/a><\/noindex>.<\/p>\n<p>For at fordele dataene mellem noderne i SQL Server brugte vi b\u00e5de vertikal og horisontal <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Partition_(database)\">partitionering<\/a><\/noindex> (sharding). Historisk har vi brugt en simpel skema for sharding af data: hver enhed fik tildelt en token \u2014 en funktion af enhedens ID. Enheder med samme token blev placeret p\u00e5 den samme SQL-server. Master-detail-forholdet blev implementeret, s\u00e5 tokens for hoved- og afledte optegnelser altid stemte overens og befandt sig p\u00e5 den samme server. I sociale netv\u00e6rk bliver n\u00e6sten alle optegnelser genereret p\u00e5 vegne af brugeren \u2014 hvilket betyder, at al brugerens data inden for et funktionelt subsystem opbevares p\u00e5 den samme server. Det vil sige, at der n\u00e6sten altid var involveret tabeller fra den samme SQL-server i forretningstransaktioner, hvilket gjorde det muligt at sikre datakonsistens ved hj\u00e6lp af lokale ACID-transaktioner, uden behov for at bruge <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">langsomme og up\u00e5lidelige<\/a><\/noindex> fordelte ACID-transaktioner.<\/p>\n<p>Takket v\u00e6re sharding og for at fremskynde SQL-operationer:<\/p>\n<ul>\n<li>Bruger ikke foreign key constraints, da enhedens ID ved sharding kan befinde sig p\u00e5 en anden server.<\/li>\n<li>Bruger ikke lagrede procedurer og triggers p\u00e5 grund af den ekstra belastning p\u00e5 CPU'en i databasen.<\/li>\n<li>Bruger ikke JOINs p\u00e5 grund af alt det ovenst\u00e5ende og mange tilf\u00e6ldige l\u00e6sninger fra disk.<\/li>\n<li>Uden for transaktioner bruger vi isolationsniveauet Read Uncommitted for at reducere deadlocks.<\/li>\n<li>Udf\u00f8rer kun korte transaktioner (i gennemsnit kortere end 100 ms).<\/li>\n<li>Bruger ikke multi-row UPDATE og DELETE p\u00e5 grund af det store antal deadlocks \u2014 opdaterer kun \u00e9n post ad gangen.<\/li>\n<li>Foresp\u00f8rgsler udf\u00f8res altid kun baseret p\u00e5 indekser \u2014 en foresp\u00f8rgsel med en plan for fuld tabelscanning betyder for os en overbelastning af databasen og dens nedbrud.<\/li>\n<\/ul>\n<p>\nDisse skridt har gjort det muligt at presse n\u00e6sten maksimal ydeevne ud af SQL-serverne. Men problemerne blev gradvist flere. Lad os se p\u00e5 dem.<\/p>\n<h2>Problemer med SQL<\/h2>\n<p><\/p>\n<ul>\n<li>Da vi brugte en brugerdefineret sharding, blev tilf\u00f8jelse af nye shards udf\u00f8rt af administratorer manuelt. I hele denne tid har skalerbare datakopier ikke betjent foresp\u00f8rgsler. <\/li>\n<li>Efterh\u00e5nden som antallet af poster i tabellen voksede, faldt hastigheden for inds\u00e6ttelse og \u00e6ndring, og n\u00e5r der tilf\u00f8jedes indekser til den eksisterende tabel, faldt hastigheden dramatisk, oprettelse og genoprettelse af indekser skete med downtime.<\/li>\n<li>Tilstedev\u00e6relsen af et lille antal Windows-servere til SQL Server i produktion vanskeligg\u00f8r h\u00e5ndteringen af infrastrukturen.<\/li>\n<\/ul>\n<p>\nMen det st\u00f8rste problem er \u2014 <\/p>\n<h2>Fejltolerance<\/h2>\n<p>\nEn klassisk SQL-server har d\u00e5rlig fejltolerance. Antag, at du kun har \u00e9n database, og den fejler \u00e9n gang hvert tredje \u00e5r. I den tid er hjemmesiden nede i 20 minutter, hvilket kan accepteres. Hvis du har 64 servere, er hjemmesiden nede hver tredje uge. Og hvis du har 200 servere, er hjemmesiden nede hver uge. Det er et problem. <\/p>\n<p>Hvad kan der g\u00f8res for at forbedre fejltolerance for SQL-serveren? Wikipedia foresl\u00e5r, at vi opstiller <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/High-availability_cluster\">et h\u00f8jtilg\u00e6ngeligt cluster<\/a><\/noindex>: hvor der er duplikerende komponenter i tilf\u00e6lde af fejl i nogen af dem.<\/p>\n<p>Dette kr\u00e6ver en park af dyrt udstyr: omfattende duplication, fiberoptik, f\u00e6lles lagre, og det at aktivere reservedele er ikke p\u00e5lideligt: omkring 10% af aktiveringerne ender med fejl i den redundant node efter den prim\u00e6re node. <\/p>\n<p>Men hovedn\u00e6vnet ved et s\u00e5dant h\u00f8jtilg\u00e6ngeligt cluster er - nul tilg\u00e6ngelighed ved fejl i datacentret, hvor det st\u00e5r. \u00bbOdnoklassniki\u00ab har fire datacentre, og vi skal sikre drift i tilf\u00e6lde af en totalfejl i et af dem.<\/p>\n<p>Til dette kunne vi anvende <noindex><a rel=\"nofollow\" href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms151196.aspx\">Multi-Master<\/a><\/noindex> replikation, som er indbygget i SQL Server. Denne l\u00f8sning er meget dyrere p\u00e5 grund af softwareomkostningerne og lider af velkendte problemer med replikation - uforudsigelige transaktionsforsinkelser ved synkron replikation og forsinkelser i anvendelsen af replikationer (og som f\u00f8lge heraf, tabte \u00e6ndringer) ved asynkron. Det underforst\u00e5ede <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\">manuelle konfliktl\u00f8sninger<\/a><\/noindex> g\u00f8r denne mulighed helt uanvendelig for os.<\/p>\n<p>Alle disse problemer kr\u00e6vede en radikal l\u00f8sning, og vi begyndte at analysere dem grundigt. Her skal vi g\u00f8re os bekendt med, hvad SQL Server prim\u00e6rt besk\u00e6ftiger sig med - transaktioner.<\/p>\n<h2>En simpel transaktion<\/h2>\n<p>\nLad os overveje den enkleste transaktion fra en applikations-SQL-programm\u00f8rs perspektiv: tilf\u00f8jelse af et billede til et album. Albummet og billederne gemmes i forskellige tabeller. Et album har en t\u00e6ller for offentlige billeder. S\u00e5dan en transaktion opdeles i f\u00f8lgende trin: <\/p>\n<ol>\n<li>Vi l\u00e5ser albummet efter n\u00f8gle.<\/li>\n<li>Vi opretter en post i billedtabellen. <\/li>\n<li>Hvis billedet har offentlig status, s\u00e5 t\u00e6ller vi op i albummets t\u00e6ller for offentlige billeder, opdaterer posten og committer transaktionen.<\/li>\n<\/ol>\n<p>\nEller i form af pseudokode:<\/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>\nVi ser, at det mest udbredte scenarie for en forretningstransaktion er at l\u00e6se data fra databasen til applikationsserverens hukommelse, \u00e6ndre noget og gemme de nye v\u00e6rdier tilbage i databasen. Normalt opdaterer vi i en s\u00e5dan transaktion flere enheder, flere tabeller. <\/p>\n<p>Under udf\u00f8relsen af en transaktion kan der ske konkurrerende \u00e6ndringer af de samme data fra et andet system. For eksempel kan Antispam beslutte, at en bruger er mist\u00e6nkelig og derfor ikke l\u00e6ngere \u00f8nsker, at alle brugerens billeder skal v\u00e6re offentlige; de skal sendes til moderation, hvilket betyder, at photo.status skal \u00e6ndres til en anden v\u00e6rdi, og de relevante t\u00e6llere skulle justeres. Det er \u00e5benlyst, at hvis denne operation finder sted uden garantier for atomaritet og isolering af konkurrerende \u00e6ndringer, som i <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>, vil resultatet ikke v\u00e6re det \u00f8nskede - enten vil foto-t\u00e6lleren vise en forkert v\u00e6rdi, eller ogs\u00e5 vil ikke alle billeder blive sendt til moderation. <\/p>\n<p>Der er skrevet meget kode, der manipulerer med forskellige forretningsenheder inden for en enkelt transaktion i l\u00f8bet af Odnoklassnikis eksistens. Ud fra erfaringerne med migrationer til NoSQL fra <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">Eventual Consistency<\/a><\/noindex> ved vi, at de st\u00f8rste udfordringer (og tidsomkostninger) skyldes n\u00f8dvendigheden af at udvikle kode, der sigter mod at opretholde datakonsistens. Derfor ans\u00e5 vi, at det vigtigste krav til det nye lager var at sikre \u00e6gte ACID-transaktioner for den applikationslogik. <\/p>\n<p>Andre, ikke mindre vigtige krav var:<\/p>\n<ul>\n<li>I tilf\u00e6lde af datacenterfejl skal b\u00e5de l\u00e6sning og skrivning i det nye lager v\u00e6re tilg\u00e6ngelige.<\/li>\n<li>Bevarelse af den nuv\u00e6rende udviklingshastighed. Det vil sige, at m\u00e6ngden af kode, der arbejdes med i det nye lager, skal v\u00e6re omtrent den samme, og der m\u00e5 ikke v\u00e6re behov for at skrive noget ekstra i lageret, udvikle algoritmer til konfliktl\u00f8sning, vedligeholdelse af sekund\u00e6re indekser osv. <\/li>\n<li>Hastigheden p\u00e5 det nye lager skal v\u00e6re tilstr\u00e6kkeligt h\u00f8j b\u00e5de ved l\u00e6sning af data og ved behandling af transaktioner, hvilket effektivt bet\u00f8d, at akademisk strenge, universelle, men langsomme l\u00f8sninger, s\u00e5som <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">to-fase commits<\/a><\/noindex>.<\/li>\n<li>Automatisk skalering under drift. <\/li>\n<li>Brug af almindelige billige servere uden behov for at k\u00f8be eksotisk hardware. <\/li>\n<li>Mulighed for udvikling af lagring gennem virksomhedens udviklere. Med andre ord blev der givet prioritet til interne eller open-source l\u00f8sninger, helst i Java.<\/li>\n<\/ul>\n<p><\/p>\n<h2>L\u00f8sninger, l\u00f8sninger<\/h2>\n<p>\nVed at analysere de mulige l\u00f8sninger kom vi frem til to mulige arkitekturvalg:<\/p>\n<p>Det f\u00f8rste var at tage en hvilken som helst SQL-server og implementere den n\u00f8dvendige fejltolerance, skalering, fejltolerant klynge, konfliktl\u00f8sning og distribuerede, p\u00e5lidelige og hurtige ACID-transaktioner. Vi vurderede denne mulighed som temmelig ikke-triviel og arbejdsintensiv.<\/p>\n<p>Den anden mulighed var at tage et f\u00e6rdigt NoSQL-lager med implementeret skalering, fejltolerant klynge og konfliktl\u00f8sning og selv implementere transaktioner og SQL. Ved f\u00f8rste \u00f8jekast virker selv opgaven med at implementere SQL, for ikke at n\u00e6vne ACID-transaktioner, som en opgave, der tager \u00e5r. Men senere inds\u00e5 vi, at det s\u00e6t af SQL-muligheder, vi bruger i praksis, er langt fra ANSI SQL lige s\u00e5 langt som <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Apache_Cassandra#Cassandra_Query_Language\">Cassandra CQL<\/a><\/noindex> er langt fra ANSI SQL. Da vi kiggede n\u00e6rmere p\u00e5 CQL, inds\u00e5 vi, at det er tilstr\u00e6kkeligt n\u00e6rt, hvad vi har brug for.<\/p>\n<h2>Cassandra og CQL<\/h2>\n<p>\nS\u00e5 hvad er det interessante ved Cassandra, hvilke funktioner har den?<\/p>\n<p>For det f\u00f8rste kan man oprette tabeller med underst\u00f8ttelse af forskellige datatyper, man kan udf\u00f8re SELECT eller UPDATE ved hj\u00e6lp af den prim\u00e6re n\u00f8gle.<\/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>\nFor at sikre konsistens af datareplikker anvender Cassandra <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Quorum_(distributed_computing)\">en quorum tilgang<\/a><\/noindex>I de enkleste tilf\u00e6lde betyder det, at n\u00e5r man placerer tre replikaer af den samme r\u00e6kke p\u00e5 forskellige noder i klyngen, anses skrivningen for at v\u00e6re succesfuld, hvis flertallet af noderne (dvs. to ud af tre) har bekr\u00e6ftet, at operationen er gennemf\u00f8rt. Dataene i r\u00e6kken anses for at v\u00e6re konsistente, hvis flertallet af noderne blev forespurgt ved l\u00e6sning og bekr\u00e6ftede dem. Dermed garanterer tilstedev\u00e6relsen af tre replikaer fuld og \u00f8jeblikkelig datakonsistens, hvis en node svigter. Denne tilgang har gjort det muligt for os at implementere en endnu mere p\u00e5lidelig ordning: altid at sende foresp\u00f8rgsler til alle tre replikaer og vente p\u00e5 svar fra de to hurtigste. Det forsinkede svar fra den tredje replika bliver i dette tilf\u00e6lde forkastet. Den forsinkede node kan have alvorlige problemer \u2014 forsinkelser, affaldssamling i JVM, direct memory reclaim i Linux-kernen, hardwarefejl, frakobling fra netv\u00e6rket. Men dette p\u00e5virker hverken klientoperationen eller dataene.<\/p>\n<p>Den tilgang, hvor vi henvender os til tre noder og f\u00e5r svar fra to, kaldes <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Speculative_execution\">speklulation<\/a><\/noindex>: foresp\u00f8rgslen til de overskydende replikaer sendes, f\u00f8r man 'falder fra'. <\/p>\n<p>En anden fordel ved Cassandra er Batchlog \u2014 en mekanisme, der garanterer, at enten hele pakken anvendes eller slet ikke. Dette g\u00f8r det muligt for os at l\u00f8se A i ACID \u2014 atomaritet lige ud af boksen.<\/p>\n<p>Det n\u00e6rmeste til transaktioner i Cassandra er det s\u00e5kaldte &#171;<noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_using\/useInsertLWT.html\">lightweight transactions<\/a><\/noindex>&#171;. Men de er langt fra \"\u00e6gte\" ACID-transaktioner: i virkeligheden er det en mulighed for at lave <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compare-and-swap\">CAS<\/a><\/noindex> p\u00e5 dataene kun for \u00e9n post ved at bruge konsensus gennem den tunge protokol Paxos. Derfor er hastigheden p\u00e5 s\u00e5danne transaktioner ikke h\u00f8j. <\/p>\n<h2>Hvad vi savnede i Cassandra<\/h2>\n<p>\nS\u00e5 vi skulle implementere \u00e6gte ACID-transaktioner i Cassandra. Med brug af hvilke vi nemt kunne implementere to andre praktiske funktioner fra klassiske DBMS: konsistente hurtige indekser, der ville g\u00f8re det muligt for os at udf\u00f8re dataudtr\u00e6k ikke kun efter den prim\u00e6re n\u00f8gle og en almindelig generator af monotont autoincrement ID.<\/p>\n<h4>C*One<\/h4>\n<p>\nS\u00e5dan blev den nye DBMS f\u00f8dt <b>C*One<\/b>, best\u00e5ende af tre typer servernoder:<\/p>\n<ul>\n<li>Opbevaring \u2014 (n\u00e6sten) standard Cassandra-servere, der er ansvarlige for at gemme data p\u00e5 lokale diske. I takt med at belastningen og datam\u00e6ngden vokser, kan deres antal let skaleres til dusinvis og hundreder.<\/li>\n<li>Transaktionskoordinatorer sikrer gennemf\u00f8relsen af transaktioner. <\/li>\n<li>Klienter er applikationsservere, der udf\u00f8rer forretningsoperationer og initierer transaktioner. Der kan v\u00e6re tusindvis af s\u00e5danne klienter.<\/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 \/>\nServere af alle typer er en del af et f\u00e6lles klynge, bruger den interne beskedprotokol Cassandra til at kommunikere med hinanden og <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip<\/a><\/noindex> til at udveksle klyngeinformation. Ved hj\u00e6lp af Heartbeat bliver serverne opm\u00e6rksomme p\u00e5 gensidige fejlfunktioner, opretholder et ensartet dataskema - tabeller, deres struktur og replikation; partitionsskema, klyngetopologi osv.<\/p>\n<h4>Klienter<\/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 \/>\nI stedet for standarddrivere bruges Fat Client-tilstand. Denne node gemmer ikke data, men kan fungere som koordinator for udf\u00f8relsen af anmodninger, hvilket betyder, at klienten selv udf\u00f8rer funktionen som koordinator for sine anmodninger: den foresp\u00f8rger lagringsreplikater og l\u00f8ser konflikter. Dette er ikke kun mere p\u00e5lideligt og hurtigere end den standarddriver, der kr\u00e6ver kommunikation med en fjernkoordinator, men giver ogs\u00e5 mulighed for at styre overf\u00f8rsel af anmodninger. Uden for en \u00e5ben transaktion p\u00e5 klienten sendes anmodningerne til lagrene. Hvis klienten \u00e5bner en transaktion, sendes alle anmodninger inden for transaktionen til transaktionskoordinatoren.<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>Transaktionskoordinator C*One<\/h2>\n<p>\nKoordinatoren er det, vi har implementeret for C*One fra bunden. Den er ansvarlig for styringen af transaktioner, l\u00e5sninger og r\u00e6kkef\u00f8lgen for anvendelsen af transaktioner.<\/p>\n<p>For hver h\u00e5ndteret transaktion genererer koordinatoren et tidsstempel: hvert efterf\u00f8lgende er st\u00f8rre end det for den tidligere transaktion. Da konfliktl\u00f8sning i Cassandra-systemet er baseret p\u00e5 tidsstempler (blandt to konfliktende poster betragtes den med det seneste tidsstempel som g\u00e6ldende), vil konflikten altid blive l\u00f8st til fordel for den efterf\u00f8lgende transaktion. P\u00e5 den m\u00e5de har vi implementeret <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\">Lamport-timere<\/a><\/noindex> \u2014 en billig metode til konfliktl\u00f8sning i et distribueret system.<\/p>\n<h2>L\u00e5se<\/h2>\n<p>\nFor at sikre isolering besluttede vi at bruge den simpleste metode \u2014 pessimistiske l\u00e5se baseret p\u00e5 den prim\u00e6re n\u00f8gle til posten. Med andre ord skal posten l\u00e5ses i transaktionen, inden den l\u00e6ses, modificeres og gemmes. F\u00f8rst efter en vellykket commit kan posten l\u00e5ses op, s\u00e5 konkurrerende transaktioner kan bruge den.<\/p>\n<p>Implementeringen af en s\u00e5dan l\u00e5s er enkel i et ikke-distribueret milj\u00f8. I et distribueret system er der to hovedmetoder: enten at implementere en distribueret l\u00e5s i klyngen eller at distribuere transaktioner, s\u00e5 transaktioner, der involverer den samme post, altid betjenes af den samme koordinator.<\/p>\n<p>Da vores data allerede er fordelt p\u00e5 grupper af lokale transaktioner i SQL, blev det besluttet at tildele koordinatorer til grupperne af lokale transaktioner: \u00e9n koordinator udf\u00f8rer alle transaktioner med token fra 0 til 9, den anden fra 10 til 19, og s\u00e5 videre. Som et resultat bliver hver af koordinatorerne chef for gruppen af transaktioner. <\/p>\n<p>S\u00e5 l\u00e5sene kan implementeres som en simpel HashMap i hukommelsen hos koordinatoren.<\/p>\n<h2>Koordinatorernes fejl<\/h2>\n<p>\nDa en koordinator udelukkende betjener en gruppe transaktioner, er det meget vigtigt hurtigt at kunne identificere dens fejl, s\u00e5 genpr\u00f8vningen af transaktionen kan ske inden for tidsgr\u00e6nsen. For at g\u00f8re dette hurtigt og p\u00e5lideligt anvendte vi en fuldt forbundet quorum heartbeat-protokol:<\/p>\n<p>I hver datacenter placeres der mindst to koordinator-noder. Periodisk sender hver koordinator et heartbeat-besked til de andre koordinatorer og informerer dem om sin funktionalitet samt hvilke heartbeat-beskeder fra hvilke koordinatorer i klyngen, den har modtaget sidst. <\/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 \/>\nVed at modtage lignende information fra de andre i deres heartbeat-beskeder, beslutter hver koordinator for sig selv, hvilke noder i klyngen der fungerer, og hvilke der ikke g\u00f8r, baseret p\u00e5 quorum-princippet: hvis node X har modtaget information om normal modtagelse af beskeder fra node Y fra flertallet af noderne i klyngen, s\u00e5 fungerer Y. Omvendt, s\u00e5 snart flertallet meddeler, at de ikke modtager beskeder fra node Y, s\u00e5 er Y failed. Interessant nok, hvis quorum informerer node X om, at den ikke l\u00e6ngere modtager beskeder fra den, vil node X selv betragte sig som failed.<\/p>\n<p>Heartbeat-beskeder sendes med h\u00f8j frekvens, omkring 20 gange i sekundet, med et interval p\u00e5 50 ms. I Java er det sv\u00e6rt at garantere applikationens respons inden for 50 ms p\u00e5 grund af de sammenlignelige varigheder af pauserne for\u00e5rsaget af affaldsamleren. Vi har form\u00e5et at opn\u00e5 en s\u00e5dan responstid ved at bruge G1-affaldsamleren, som tillader at angive et m\u00e5l for varigheden af GC-pauser. Dog, nogle gange, ganske sj\u00e6ldent, overskrider affaldssamlerens pauser 50 ms, hvilket kan f\u00f8re til falsk detektion af fejl. For at undg\u00e5 dette, rapporterer koordinatoren ikke om fejl fra den fjerne node ved tab af det f\u00f8rste heartbeat-besked fra den, kun hvis flere g\u00e5r tabt i tr\u00e6k. P\u00e5 den m\u00e5de har vi form\u00e5et at detektere fejl hos koordinators noden inden for 200 ms. <\/p>\n<p>Men det er ikke nok bare at forst\u00e5 hurtigt, hvilken node der er stoppet med at fungere. Vi skal g\u00f8re noget ved det. <\/p>\n<h2>Redundans<\/h2>\n<p>\nDen klassiske ordning indeb\u00e6rer, at der i tilf\u00e6lde af masterfejl indkaldes valg af en ny ved hj\u00e6lp af en af<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\"> de trendy<\/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\">universelle<\/a><\/noindex> algoritmer. Men s\u00e5danne algoritmer har velkendte problemer med konvergens i tiden og varigheden af selve valgprocessen. Disse ekstra forsinkelser har vi v\u00e6ret i stand til at undg\u00e5 med en ordning for udskiftning af koordinatorer i et fuld forbindelse netv\u00e6rk:<\/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 \/>\nLad os sige, at vi \u00f8nsker at udf\u00f8re en transaktion i gruppe 50. Vi vil p\u00e5 forh\u00e5nd definere udskiftningsordningen, dvs. hvilke noder der vil udf\u00f8re transaktionerne i gruppe 50 i tilf\u00e6lde af fejl hos den prim\u00e6re koordinator. Vores m\u00e5l er at opretholde systemets funktionalitet ved fejl i datacenteret. Vi bestemmer, at den f\u00f8rste reserve vil v\u00e6re en node fra et andet datacenter, og den anden reserve vil v\u00e6re en node fra et tredje. Denne ordning v\u00e6lges \u00e9n gang og \u00e6ndres ikke, medmindre topologi i klyngen \u00e6ndres, dvs. s\u00e5 l\u00e6nge nye noder ikke tilf\u00f8jes (hvilket sj\u00e6ldent sker). R\u00e6kkef\u00f8lgen for valg af en ny aktiv master ved fejl hos den gamle vil altid v\u00e6re den samme: den aktive master bliver den f\u00f8rste reserve, og hvis den ogs\u00e5 er stoppet med at fungere - den anden reserve. <\/p>\n<p>Denne ordning er mere p\u00e5lidelig end den universelle algoritme, da det for at aktivere en ny master kun kr\u00e6ver fastl\u00e6ggelse af, at den gamle er fejlet.<\/p>\n<p>Men hvordan skal kunderne forst\u00e5, hvilken af mestre der arbejder i \u00f8jeblikket? Det er umuligt at sende information til tusindvis af kunder p\u00e5 50 ms. Der kan opst\u00e5 en situation, hvor en kunde sender en anmodning om at \u00e5bne en transaktion, uden at vide at den p\u00e5g\u00e6ldende mester allerede ikke fungerer, og anmodningen h\u00e6nger i timeout. For at undg\u00e5 dette sender kunderne spekulativt anmodningen til den gruppe mester samt begge hans reserver, men kun den, der er den aktive mester i \u00f8jeblikket, vil svare p\u00e5 anmodningen. Al efterf\u00f8lgende kommunikation i forbindelse med transaktionen vil kunden kun f\u00f8re med den aktive mester.<\/p>\n<p>Reserve mestre placerer de modtagne anmodninger om ikke deres egne transaktioner i k\u00f8en for uf\u00f8dt transaktioner, hvor de opbevares i nogen tid. Hvis den aktive mester d\u00f8r, vil den nye mester h\u00e5ndtere anmodningerne om at \u00e5bne transaktioner fra sin k\u00f8 og svare kunden. Hvis kunden allerede har \u00e5bnet en transaktion med den gamle mester, ignoreres det andet svar (og \u00e5benlyst vil en s\u00e5dan transaktion ikke blive afsluttet og vil blive gentaget af kunden).<\/p>\n<h2>Hvordan fungerer en transaktion<\/h2>\n<p>\nLad os sige, at kunden har sendt en anmodning til koordinatoren om at \u00e5bne en transaktion for en bestemt enhed med en bestemt prim\u00e6r n\u00f8gle. Koordinatoren l\u00e5ser denne enhed og placerer den i blokeringstabellen i hukommelsen. Om n\u00f8dvendigt l\u00e6ser koordinatoren denne enhed fra lageret og gemmer de modtagne data i transaktionens tilstand i koordinatorens hukommelse.<\/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 \/>\nN\u00e5r kunden \u00f8nsker at \u00e6ndre data i transaktionen, sender han en anmodning til koordinatoren om at \u00e6ndre enheden, og denne placerer de nye data i tilstandstabellen for transaktionerne i hukommelsen. P\u00e5 dette tidspunkt er optagelsen afsluttet \u2014 der laves ikke nogen optagelse i lageret.<\/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 \/>\nN\u00e5r kunden anmoder om sine \u00e6ndrede data inden for en aktiv transaktion, handler koordinatoren s\u00e5ledes: <\/p>\n<ul>\n<li>hvis ID allerede findes i transaktionen, tages data fra hukommelsen; <\/li>\n<li>hvis ID ikke findes i hukommelsen, l\u00e6ses de manglende data fra node-lagre, samles med de allerede eksisterende i hukommelsen, og resultatet gives til kunden. <\/li>\n<\/ul>\n<p>\nS\u00e5ledes kan kunden l\u00e6se sine egne \u00e6ndringer, mens andre kunder ikke ser disse \u00e6ndringer, fordi de kun opbevares i koordinatorens hukommelse, de findes endnu ikke i Cassandra-noderne.<\/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 \/>\nN\u00e5r en klient sender et commit, gemmer koordinatoren den tilstand, der var i hukommelsen hos tjenesten, i et logged batch, som derefter sendes til Cassandra-lagrene. Lagrene g\u00f8r alt n\u00f8dvendigt for, at dette batch bliver anvendt atomart (fuldst\u00e6ndigt), og returnerer et svar til koordinatoren, som derefter frigiver l\u00e5sene og bekr\u00e6fter transaktionens succes til klienten.<\/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 \/>\nOg for at rulle tilbage skal koordinatoren blot frigive den hukommelse, der er optaget af transaktionens tilstand.<\/p>\n<p>Som et resultat af de ovenfor beskrevne forbedringer har vi implementeret ACID-principperne:<\/p>\n<ul>\n<li><b>Atomaritet<\/b>. Dette er garantien for, at ingen transaktion vil blive registreret delvist i systemet; enten udf\u00f8res alle dens underoperationer, eller ingen af dem udf\u00f8res. Vi overholder dette princip ved hj\u00e6lp af logged batch i Cassandra.<\/li>\n<li><b>Konsistens<\/b>. Hver vellykket transaktion registrerer pr. definition kun gyldige resultater. Hvis det efter \u00e5bningen af transaktionen og udf\u00f8relsen af nogle operationer opdages, at resultatet er ugyldigt, udf\u00f8res der en tilbagef\u00f8rsel.<\/li>\n<li><b>Isolering<\/b>. Under udf\u00f8relsen af en transaktion m\u00e5 parallelle transaktioner ikke p\u00e5virke dens resultat. Konkurrerende transaktioner isoleres ved hj\u00e6lp af pessimistische l\u00e5se hos koordinatoren. For l\u00e6sninger uden for transaktionen overholdes isolationsprincippet p\u00e5 niveauet Read Committed.<\/li>\n<li><b>Holdbarhed<\/b>. Uanset problemer p\u00e5 de lavere niveauer \u2014 str\u00f8mafbrydelser, hardwarefejl \u2014 skal \u00e6ndringer foretaget af en succesfuld transaktion forblive gemt efter genoptagelsen af driften. <\/li>\n<\/ul>\n<p><\/p>\n<h2>L\u00e6sning efter indekser<\/h2>\n<p>\nLad os tage et simpelt tabel: <\/p>\n<pre><code>CREATE TABLE photos (\nid bigint primary key,\nejer bigint,\n\u00e6ndret timestamp,\n\u2026)<\/code><\/pre>\n<p>\nDen har et ID (prim\u00e6r n\u00f8gle), ejer og \u00e6ndringsdato. Vi skal lave en meget simpel foresp\u00f8rgsel \u2014 hente data efter ejer med \u00e6ndringsdatoen \"i de seneste 24 timer\". <\/p>\n<pre><code>SELECT *\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nFor at en s\u00e5dan foresp\u00f8rgsel skal k\u00f8re hurtigt, skal der i en klassisk SQL-database bygges et indeks over kolonnerne (ejer, \u00e6ndret). Dette kan vi g\u00f8re forholdsvis enkelt, da vi nu har ACID-garantier!<\/p>\n<h2>Indekser i C*One<\/h2>\n<p>\nDer er en original tabel med billeder, hvor ID'et for posten er den prim\u00e6re n\u00f8gle. <\/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 \/>\nFor the index, C*One creates a new table that is a copy of the original. The key matches the index expression, which also includes the primary key of the record from the original table:<\/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 \/>\nNow the query for \"the owner for the last day\" can be rewritten as a select from another table:<\/p>\n<pre><code>SELECT * FROM i1_test\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nThe data consistency of the original photos table and the index i1 is maintained automatically by the coordinator. Based only on the data schema, when changes are received, the coordinator generates and remembers changes not only for the main table but also for copies. No additional actions are performed with the index table, logs are not read, and locks are not used. This means that adding indexes consumes almost no resources and has practically no impact on the speed of applying modifications.<\/p>\n<p>With the help of ACID, we managed to implement indexes \"as in SQL.\" They have consistency, can scale, work quickly, can be composite, and are embedded in the CQL query language. No changes to the application code are needed to support indexes. It\u2019s as simple as in SQL. And most importantly, indexes do not affect the speed of executing modifications to the transactions of the original table.<\/p>\n<h2>What we achieved<\/h2>\n<p>\nWe developed C*One three years ago and launched it into production. <\/p>\n<p>So what did we achieve in the end? Let's evaluate it using the example of the subsystem for processing and storing photos, one of the most important data types in a social network. It\u2019s not about the actual images, but the various metadata. Currently, there are about 20 billion such records in \"Odnoklassniki\", the system processes 80,000 read requests per second, and up to 8,000 ACID transactions per second related to data modification. <\/p>\n<p>When we used SQL with a replication factor of 1 (but in RAID 10), the metadata for photos was stored on a highly available cluster of 32 machines with Microsoft SQL Server (plus 11 backups). Additionally, 10 servers were allocated for backup storage. In total, 50 expensive machines. Meanwhile, the system operated under nominal load, without spare capacity.<\/p>\n<p>Efter migrationen til det nye system har vi opn\u00e5et en replikeringsfaktor p\u00e5 3 \u2013 \u00e9n kopi i hvert datacenter. Systemet best\u00e5r af 63 Cassandra-lagringsnoder og 6 koordineringsmaskiner, i alt 69 servere. Men disse maskiner er betydeligt billigere, da deres samlede omkostning udg\u00f8r cirka 30 % af omkostningerne ved SQL-systemet. Belastningen ligger samtidig p\u00e5 et niveau p\u00e5 30 %.<\/p>\n<p>Med implementeringen af C*One er latensen ogs\u00e5 blevet reduceret: i SQL tog en skriveoperation cirka 4,5 ms. I C*One er det omkring 1,6 ms. Transaktionens varighed er i gennemsnit mindre end 40 ms, commit udf\u00f8res p\u00e5 2 ms, og l\u00e6se- og skrivevarigheden ligger i gennemsnit p\u00e5 2 ms. 99. percentilen er kun 3-3,1 ms, og antallet af timeouts er reduceret med 100 gange \u2013 alt sammen takket v\u00e6re den brede anvendelse af spekulationer. <\/p>\n<p>Indtil nu er den st\u00f8rste del af SQL Server-noderne taget ud af drift, og nye produkter udvikles kun ved hj\u00e6lp af C*One. Vi har tilpasset C*One til at fungere i vores cloud. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/odnoklassniki\/blog\/346868\/\">one-cloud<\/a><\/noindex>, hvilket har gjort det muligt at fremskynde implementeringen af nye klynger, forenkle konfigurationen og automatisere driften. Uden kildekoden ville det have v\u00e6ret betydeligt mere kompliceret og klodset. <\/p>\n<p>Vi arbejder nu p\u00e5 at migrere vores andre lagre til skyen \u2013 men det er en helt anden historie.<br \/>\n<br \/>Kilde: <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\/da\/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=\"da_DK\" \/>\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\/da\/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":"Indtil for nylig har der v\u00e6ret omkring 50 TB data behandlet i Odnoklassniki.","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/newsql-nosql-acid","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","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\/da\/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\/da\/wp-json\/wp\/v2\/posts\/37956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=37956"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/37956\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/28484"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=37956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=37956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=37956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}