{"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\/sv\/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 \/>\nTills nyligen fanns det i Odnoklassniki cirka 50 TB data som bearbetades i realtid och lagrades i SQL Server. F\u00f6r en s\u00e5dan m\u00e4ngd \u00e4r det praktiskt taget om\u00f6jligt att s\u00e4kerst\u00e4lla snabb, p\u00e5litlig och \u00e4ven felresistent \u00e5tkomst till datacentret med hj\u00e4lp av SQL-databaser. Vanligtvis anv\u00e4nds en av NoSQL-lagringsl\u00f6sningarna i s\u00e5dana fall, men allt kan inte \u00f6verf\u00f6ras till NoSQL: vissa enheter kr\u00e4ver ACID-transaktionsgarantier. <\/p>\n<p>Detta ledde oss till att anv\u00e4nda ett NewSQL-lagringssystem, det vill s\u00e4ga en databas som erbjuder felresistens, skalbarhet och snabbhet av NoSQL-system, men samtidigt beh\u00e5ller de bekanta ACID-garantierna fr\u00e5n klassiska system. Det finns f\u00e5 fungerande industrisystem av denna nya typ, s\u00e5 vi utvecklade ett s\u00e5dant system sj\u00e4lva och tog det i kommersiell drift. <\/p>\n<p>Hur det fungerar och vad vi \u00e5stadkom \u2014 l\u00e4s vidare nedan.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nIdag har \"Odnoklassniki\" \u00f6ver 70 miljoner unika bes\u00f6kare varje m\u00e5nad. Vi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.similarweb.com\/top-websites\/category\/internet-and-telecom\/social-network\">h\u00f6r till de fem st\u00f6rsta<\/a><\/noindex> sociala n\u00e4tverken i v\u00e4rlden och \u00e4r bland de tjugo webbplatser d\u00e4r anv\u00e4ndare tillbringar mest tid. Infrastruktur f\u00f6r \"OK\" hanterar mycket h\u00f6ga belastningar: fler \u00e4n en miljon HTTP-f\u00f6rfr\u00e5gningar per sekund mot fronten. Delar av serverparken, som best\u00e5r av mer \u00e4n 8000 servrar, \u00e4r placerade n\u00e4ra varandra \u2014 i fyra datacenter i Moskva, vilket m\u00f6jligg\u00f6r en n\u00e4tverksf\u00f6rdr\u00f6jning p\u00e5 mindre \u00e4n 1 ms mellan dem.<\/p>\n<p>Vi har anv\u00e4nt Cassandra sedan 2010, fr\u00e5n version 0.6. Idag anv\u00e4nds flera tiotals kluster. Det snabbaste klustret hanterar mer \u00e4n 4 miljoner operationer per sekund, och det st\u00f6rsta lagrar 260 TB. <\/p>\n<p>Men allt detta \u00e4r vanliga NoSQL-kluster som anv\u00e4nds f\u00f6r lagring av <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 \u00f6verensst\u00e4mmande<\/a><\/noindex> data. Vi ville dock ers\u00e4tta det prim\u00e4ra konsistenta lagringssystemet, Microsoft SQL Server, som har anv\u00e4nts sedan \"Odnoklassniki\" grundades. Lagringssystemet bestod av mer \u00e4n 300 maskiner med SQL Server Standard Edition, som inneh\u00f6ll 50 TB data \u2014 aff\u00e4rsobjekt. Dessa data modifieras inom ramen f\u00f6r ACID-transaktioner och kr\u00e4ver <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">h\u00f6g \u00f6verensst\u00e4mmelse<\/a><\/noindex>.<\/p>\n<p>F\u00f6r att f\u00f6rdela data \u00f6ver noderna i SQL Server anv\u00e4nde vi b\u00e5de vertikal och horisontell <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Partition_(database)\">partionering<\/a><\/noindex> (sharding). Historiskt har vi anv\u00e4nt ett enkelt datashardningsschema: varje entitet tilldelades en token \u2013 en funktion av entitetens ID. Entiteter med samma token placerades p\u00e5 en SQL-server. Relationstypen master-detail realiserades s\u00e5 att token f\u00f6r huvudentiteten och den h\u00e4rledda posten alltid matchade och fanns p\u00e5 samma server. I sociala n\u00e4tverk genereras n\u00e4stan alla inl\u00e4gg av anv\u00e4ndaren \u2013 vilket inneb\u00e4r att all anv\u00e4ndardata inom ett funktionellt delsystem lagras p\u00e5 en och samma server. Det betyder att i aff\u00e4rstransaktioner deltog n\u00e4stan alltid tabeller fr\u00e5n en och samma SQL-server, vilket gjorde det m\u00f6jligt att s\u00e4kerst\u00e4lla datakonsistens genom lokala ACID-transaktioner utan behov av att anv\u00e4nda <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">l\u00e5ngsamma och op\u00e5litliga<\/a><\/noindex> distribuerade ACID-transaktioner.<\/p>\n<p>Genom sharding och f\u00f6r att \u00f6ka hastigheten p\u00e5 SQL:<\/p>\n<ul>\n<li>Anv\u00e4nder inte Foreign key constraints, eftersom ID f\u00f6r entiteten vid sharding kan finnas p\u00e5 en annan server.<\/li>\n<li>Anv\u00e4nder inte lagrade procedurer och triggers p\u00e5 grund av ytterligare belastning p\u00e5 DBMS CPU.<\/li>\n<li>Anv\u00e4nder inte JOINs p\u00e5 grund av allt ovanst\u00e5ende och m\u00e5nga slumpm\u00e4ssiga l\u00e4sningar fr\u00e5n disk.<\/li>\n<li>Utanf\u00f6r transaktionen anv\u00e4nder vi isoleringsniv\u00e5n Read Uncommitted f\u00f6r att minska deadlocks.<\/li>\n<li>Genomf\u00f6r endast korta transaktioner (i genomsnitt kortare \u00e4n 100 ms).<\/li>\n<li>Anv\u00e4nder inte flera rader UPDATE och DELETE p\u00e5 grund av det stora antalet deadlocks \u2013 vi uppdaterar endast en post i taget.<\/li>\n<li>Fr\u00e5gor utf\u00f6rs alltid endast efter index \u2013 en fr\u00e5ga med en fullst\u00e4ndig tabellgenoms\u00f6kningsplan inneb\u00e4r \u00f6verbelastning av databasen och dess avbrott.<\/li>\n<\/ul>\n<p>\nDessa steg har gjort det m\u00f6jligt att maximera prestandan p\u00e5 SQL-servrarna. Men problemen blev allt fler. L\u00e5t oss titta p\u00e5 dem.<\/p>\n<h2>Problem med SQL<\/h2>\n<p><\/p>\n<ul>\n<li>Eftersom vi anv\u00e4nde egenutvecklad sharding utf\u00f6rdes till\u00e4gget av nya shards manuellt av administrat\u00f6rerna. Under hela denna tid skulle de skalbara datakopiorna inte hantera f\u00f6rfr\u00e5gningar. <\/li>\n<li>N\u00e4r antalet poster i tabellen \u00f6kade minskade hastigheten f\u00f6r ins\u00e4ttning och modifiering, och n\u00e4r index lades till i den befintliga tabellen minskade hastigheten m\u00e5ngfalt; skapande och \u00e5terskapande av index skedde med driftstopp.<\/li>\n<li>N\u00e4rvaron av en begr\u00e4nsad m\u00e4ngd Windows f\u00f6r SQL Server i produktion komplicerar hanteringen av infrastrukturen.<\/li>\n<\/ul>\n<p>\nMen det st\u00f6rsta problemet \u00e4r \u2014 <\/p>\n<h2>Fel-tolerans<\/h2>\n<p>\nDen klassiska SQL-servern har d\u00e5lig redundans. Anta att du har en enda databasserver och den g\u00e5r s\u00f6nder var tredje \u00e5r. Under den tiden fungerar inte webbplatsen i 20 minuter, vilket \u00e4r acceptabelt. Om du har 64 servrar, fungerar inte webbplatsen en g\u00e5ng var tredje vecka. Och om du har 200 servrar, fungerar inte webbplatsen varje vecka. Det \u00e4r ett problem. <\/p>\n<p>Vad kan g\u00f6ras f\u00f6r att \u00f6ka redundansen hos SQL-servern? Wikipedia f\u00f6resl\u00e5r att vi bygger <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/High-availability_cluster\">ett h\u00f6g tillg\u00e4ngligt kluster<\/a><\/noindex>: d\u00e4r det finns en duplicering i h\u00e4ndelse av ett fel p\u00e5 n\u00e5gon av komponenterna.<\/p>\n<p>Detta kr\u00e4ver en park av dyr utrustning: omfattande duplicering, fiberoptik, lagring av gemensam data, och dessutom fungerar aktivering av reservsystem ofta os\u00e4kert: cirka 10% av aktiveringar slutar med att reservnoden som kopplas samman med huvudnoden g\u00e5r ner. <\/p>\n<p>Men den st\u00f6rsta nackdelen med ett s\u00e5dant h\u00f6g tillg\u00e4ngligt kluster \u00e4r att det \u00e4r helt otillg\u00e4ngligt vid en datacenterst\u00f6rning d\u00e4r det \u00e4r placerat. \"VKontakte\" har fyra datacenter, och vi m\u00e5ste s\u00e4kerst\u00e4lla drift \u00e4ven vid en fullst\u00e4ndig katastrof i n\u00e5got av dem.<\/p>\n<p>F\u00f6r detta skulle vi kunna anv\u00e4nda <noindex><a rel=\"nofollow\" href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms151196.aspx\">Multi-Master<\/a><\/noindex> replikation, inbyggd i SQL Server. Denna l\u00f6sning \u00e4r mycket dyrare p\u00e5 grund av mjukvarukostnaden och lider av v\u00e4lk\u00e4nda problem med replikation - of\u00f6ruts\u00e4gbara transaktionsf\u00f6rdr\u00f6jningar vid synkron replikation och f\u00f6rseningar vid till\u00e4mpning av replikationer (och som en konsekvens, f\u00f6rlorade modifieringar) vid asynkron. Dessutom <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\">manuell l\u00f6sning av konflikter<\/a><\/noindex> g\u00f6r detta alternativ helt oanv\u00e4ndbart f\u00f6r oss.<\/p>\n<p>Alla dessa problem kr\u00e4vde en grundl\u00e4ggande l\u00f6sning och vi b\u00f6rjade en detaljerad analys av dem. H\u00e4r beh\u00f6ver vi bekanta oss med vad SQL Server i huvudsak g\u00f6r - transaktioner.<\/p>\n<h2>En enkel transaktion<\/h2>\n<p>\nL\u00e5t oss titta p\u00e5 den enklaste transaktionen, sett fr\u00e5n en till\u00e4mpad SQL-programmerares perspektiv: att l\u00e4gga till ett foto i ett album. Album och foton lagras i olika tabeller. Ett album har en r\u00e4knare f\u00f6r offentliga foton. D\u00e5 delas en s\u00e5dan transaktion upp i f\u00f6ljande steg: <\/p>\n<ol>\n<li>L\u00e5s albumet genom nyckel.<\/li>\n<li>Skapa en post i fototabellen. <\/li>\n<li>Om fotot har offentlig status, \u00f6kar vi r\u00e4knaren f\u00f6r offentliga foton i albumet, uppdaterar posten och \u00e5tar transaktionen.<\/li>\n<\/ol>\n<p>\nEller i form av pseudokod:<\/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 att det vanligaste scenariot f\u00f6r aff\u00e4rstransaktioner \u00e4r att l\u00e4sa data fr\u00e5n databasen till serverns minne, g\u00f6ra n\u00e5gon f\u00f6r\u00e4ndring och spara de nya v\u00e4rdena tillbaka i databasen. Vanligtvis uppdaterar vi flera entiteter och flera tabeller i s\u00e5dan transaktion. <\/p>\n<p>Vid utf\u00f6randet av en transaktion kan konkurrerande modifieringar av samma data fr\u00e5n ett annat system intr\u00e4ffa. Till exempel kan Antispam besluta att en anv\u00e4ndare \u00e4r misst\u00e4nkt och att d\u00e4rf\u00f6r alla bilder som anv\u00e4ndaren har inte l\u00e4ngre ska vara offentliga, de m\u00e5ste skickas f\u00f6r granskning, vilket inneb\u00e4r att photo.status m\u00e5ste \u00e4ndras till ett annat v\u00e4rde och motsvarande r\u00e4kning m\u00e5ste justeras. Det \u00e4r uppenbart att om denna operation sker utan garantier f\u00f6r atom\u00e4r till\u00e4mpning och isolering av konkurrerande modifieringar, som i <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>, s\u00e5 kommer resultatet inte att vara som n\u00f6dv\u00e4ndigt \u2014 antingen kommer bildr\u00e4knaren att visa ett felaktigt v\u00e4rde eller s\u00e5 kommer inte alla bilder att skickas f\u00f6r granskning. <\/p>\n<p>Likas\u00e5 finns det mycket kod som manipulera med olika aff\u00e4rsentiteter inom en och samma transaktion, skrivet under hela Odnoklassniki's existens. Fr\u00e5n v\u00e5ra erfarenheter av migrationer till NoSQL med <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Eventual_consistency\">Eventual Consistency<\/a><\/noindex> , vet vi att de st\u00f6rsta sv\u00e5righeterna (och tidskostnaderna) orsakas av behovet av att utveckla kod f\u00f6r att uppr\u00e4tth\u00e5lla data\u00f6verensst\u00e4mmelse. D\u00e4rf\u00f6r ans\u00e5g vi att det viktigaste kravet p\u00e5 det nya lagringssystemet var att s\u00e4kerst\u00e4lla verkliga ACID-transaktioner f\u00f6r aff\u00e4rslogik. <\/p>\n<p>Andra, minst lika viktiga, krav var:<\/p>\n<ul>\n<li>Vid en datacenterfel m\u00e5ste b\u00e5de l\u00e4sning och skrivning till det nya lagringssystemet vara m\u00f6jligt.<\/li>\n<li>Att bevara den nuvarande utvecklingshastigheten. Det vill s\u00e4ga, n\u00e4r man arbetar med det nya lagringssystemet b\u00f6r m\u00e4ngden kod vara ungef\u00e4r densamma, det ska inte beh\u00f6vas skriva n\u00e5got ytterligare i lagringssystemet, eller utveckla algoritmer f\u00f6r konfliktl\u00f6sning, uppr\u00e4tth\u00e5llande av sekund\u00e4ra index etc. <\/li>\n<li>Hastigheten p\u00e5 det nya lagringssystemet m\u00e5ste vara tillr\u00e4ckligt h\u00f6g, b\u00e5de vid datal\u00e4sning och vid transaktionsbearbetning, vilket effektivt innebar att akademiskt strikta, universella men l\u00e5ngsamma l\u00f6sningar, som till exempel, <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_commit_protocol\">tv\u00e5fas\u00e5taganden<\/a><\/noindex>.<\/li>\n<li>Automatisk skalering i realtid. <\/li>\n<li>Anv\u00e4ndning av vanliga billiga servrar, utan behov av att k\u00f6pa exotisk h\u00e5rdvara. <\/li>\n<li>M\u00f6jlighet att utveckla lagring med hj\u00e4lp av f\u00f6retagets utvecklare. Med andra ord prioriterades egna eller \u00f6ppna l\u00f6sningar, helst p\u00e5 Java.<\/li>\n<\/ul>\n<p><\/p>\n<h2>L\u00f6sningar, l\u00f6sningar<\/h2>\n<p>\nEfter att ha analyserat m\u00f6jliga l\u00f6sningar kom vi fram till tv\u00e5 m\u00f6jliga val av arkitektur:<\/p>\n<p>Det f\u00f6rsta \u2014 att ta vilken SQL-server som helst och implementera n\u00f6dv\u00e4ndig redundans, skalningsmekanism, redundanta kluster, konflikthantering och distribuerade, p\u00e5litliga och snabba ACID-transaktioner. Vi bed\u00f6mde detta alternativ som ganska komplext och arbetskr\u00e4vande.<\/p>\n<p>Det andra alternativet \u2014 att ta en f\u00e4rdig NoSQL-lagring med implementerad skalning, redundanta kluster, konflikthantering och sj\u00e4lva implementera transaktioner och SQL. Vid f\u00f6rsta anblicken verkar \u00e4ven uppgiften att implementera SQL, f\u00f6r att inte tala om ACID-transaktioner, vara en uppgift f\u00f6r \u00e5ratal. Men sedan ins\u00e5g vi att upps\u00e4ttningen av SQL-m\u00f6jligheter som vi anv\u00e4nder i praktiken ligger l\u00e5ngt ifr\u00e5n ANSI SQL p\u00e5 samma s\u00e4tt som <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Apache_Cassandra#Cassandra_Query_Language\">Cassandra CQL<\/a><\/noindex> \u00e4r l\u00e5ngt ifr\u00e5n ANSI SQL. N\u00e4r vi tittade n\u00e4rmare p\u00e5 CQL ins\u00e5g vi att det \u00e4r tillr\u00e4ckligt n\u00e4ra det vi beh\u00f6ver.<\/p>\n<h2>Cassandra och CQL<\/h2>\n<p>\nS\u00e5, vad \u00e4r intressant med Cassandra, vilka m\u00f6jligheter har den?<\/p>\n<p>F\u00f6r det f\u00f6rsta kan man skapa tabeller med st\u00f6d f\u00f6r olika datatyper, man kan g\u00f6ra SELECT eller UPDATE baserat p\u00e5 prim\u00e4rnyckeln.<\/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>\nF\u00f6r att s\u00e4kerst\u00e4lla datakonsistens mellan repliker, anv\u00e4nder Cassandra <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Quorum_(distributed_computing)\">ett kvorumansats<\/a><\/noindex>. I det enklaste fallet inneb\u00e4r detta att n\u00e4r man placerar tre repliker av samma rad p\u00e5 olika noder i klustret, anses upptagningen vara framg\u00e5ngsrik om majoriteten av noderna (dvs. tv\u00e5 av tre) har bekr\u00e4ftat att denna skrivoperation var lyckad. Data i raden anses vara konsistenta om majoriteten av noderna har tillfr\u00e5gats och bekr\u00e4ftat detta vid avl\u00e4sning. S\u00e5ledes garanteras fullst\u00e4ndig och omedelbar datakonsistens vid avbrott av en nod n\u00e4r det finns tre repliker. Denna metod har gjort det m\u00f6jligt f\u00f6r oss att implementera en \u00e4nnu mer p\u00e5litlig strategi: alltid skicka f\u00f6rfr\u00e5gningar till alla tre repliker och v\u00e4nta p\u00e5 svar fr\u00e5n de tv\u00e5 snabbaste. Det f\u00f6rsenade svaret fr\u00e5n den tredje repliken avvisas i s\u00e5dana fall. Den f\u00f6rsenade noden kan ha allvarliga problem \u2013 f\u00f6rdr\u00f6jningar, skr\u00e4psamling i JVM, direkt minnes\u00e5tervinning i linux-k\u00e4rnan, h\u00e5rdvarufel, n\u00e4tverksavbrott. Men detta p\u00e5verkar inte klientoperationen eller datan alls.<\/p>\n<p>Metoden d\u00e4r vi riktar oss till tre noder men f\u00e5r svar fr\u00e5n tv\u00e5 kallas <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Speculative_execution\">speklulation<\/a><\/noindex>: beg\u00e4ran om extra repliker skickas innan den \"det faller av\". <\/p>\n<p>En annan f\u00f6rdel med Cassandra \u00e4r Batchlog \u2013 en mekanism som garanterar antingen fullst\u00e4ndig till\u00e4mpning eller fullst\u00e4ndig avslag av paketet med de \u00e4ndringar du g\u00f6r. Detta g\u00f6r att vi kan l\u00f6sa A i ACID \u2013 atom\u00e4ritet direkt.<\/p>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0431\u043b\u0438\u0437\u043a\u043e\u0435 \u043a \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c \u0432 Cassandra \u2014 \u044d\u0442\u043e \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 &#171;<noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_using\/useInsertLWT.html\">lightweight transactions<\/a><\/noindex>&#171;. \u041d\u043e \u043e\u0442 \u00ab\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445\u00bb ACID-\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u043e\u043d\u0438 \u0434\u0430\u043b\u0435\u043a\u0438: \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compare-and-swap\">CAS<\/a><\/noindex> p\u00e5 data f\u00f6r endast en post, med anv\u00e4ndning av konsensus via det tunga protokollet Paxos. D\u00e4rf\u00f6r \u00e4r hastigheten p\u00e5 s\u00e5dana transaktioner l\u00e5g. <\/p>\n<h2>Vad vi saknade i Cassandra<\/h2>\n<p>\nS\u00e5, vi beh\u00f6vde implementera riktiga ACID-transaktioner i Cassandra. Med hj\u00e4lp av vilka vi enkelt skulle kunna uppn\u00e5 tv\u00e5 andra bekv\u00e4ma funktioner fr\u00e5n klassiska DBMS: konsistenta snabba index, vilket skulle l\u00e5ta oss h\u00e4mta data inte bara efter prim\u00e4rnyckel och en vanlig generator av monoton autoinkrementella ID.<\/p>\n<h4>C*One<\/h4>\n<p>\nS\u00e5 f\u00f6ddes en ny databas <b>C*One<\/b>, best\u00e5ende av tre typer servernoder:<\/p>\n<ul>\n<li>Lagringsenheter \u2013 (n\u00e4stan) standard Cassandra-servrar som ansvarar f\u00f6r att lagra data p\u00e5 lokala diskar. Allteftersom belastningen och datavolymerna v\u00e4xer kan deras antal enkelt skalas upp till tiotals och hundratals.<\/li>\n<li>Transaktionskoordinatorer - s\u00e4kerst\u00e4ller utf\u00f6randet av transaktioner. <\/li>\n<li>Kunder - applikationsservrar som genomf\u00f6r aff\u00e4rsprocesser och initierar transaktioner. Det kan finnas tusentals s\u00e5dana kunder.<\/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 \/>\nServrar av alla typer ing\u00e5r i en gemensam kluster, anv\u00e4nder det interna meddelandeprotokollet Cassandra f\u00f6r att kommunicera med varandra och <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gossip_protocol\">gossip<\/a><\/noindex> f\u00f6r att utbyta klusterinformation. Med hj\u00e4lp av Heartbeat f\u00e5r servrarna k\u00e4nnedom om \u00f6msesidiga fel, uppr\u00e4tth\u00e5ller en gemensam dataskema - tabeller, deras struktur och replikering; partitionschema, kluster topologi, osv.<\/p>\n<h4>Kunder<\/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 \/>\nIst\u00e4llet f\u00f6r standarddrivrutiner anv\u00e4nds l\u00e4get Fat Client. En s\u00e5dan nod lagrar inte data men kan agera som koordinator f\u00f6r fr\u00e5geutf\u00f6rande, det vill s\u00e4ga kunden sj\u00e4lv utf\u00f6r funktionen att koordinera sina fr\u00e5gor: fr\u00e5gar lagringskopior och l\u00f6ser konflikter. Detta \u00e4r inte bara mer p\u00e5litligt och snabbare \u00e4n standarddrivrutinen som kr\u00e4ver kommunikation med en fj\u00e4rrkoordinator, utan till\u00e5ter ocks\u00e5 hantering av fr\u00e5gor. Utanf\u00f6r en \u00f6ppen kundtransaktion dirigeras fr\u00e5gor till lagringssystemen. Om kunden har \u00f6ppnat en transaktion dirigeras alla fr\u00e5gor inom transaktionen till transaktionskoordinatore.<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>\nKoordinatorn \u00e4r det vi har implementerat f\u00f6r C*One fr\u00e5n grunden. Den ansvarar f\u00f6r hantering av transaktioner, l\u00e5s och ordning f\u00f6r till\u00e4mpning av transaktioner.<\/p>\n<p>F\u00f6r varje behandlad transaktion genererar koordinatorn en tidsst\u00e4mpel: varje efterf\u00f6ljande \u00e4r st\u00f6rre \u00e4n den f\u00f6reg\u00e5ende transaktionen. Eftersom Cassandra-systemets konfliktl\u00f6sning \u00e4r baserad p\u00e5 tidsst\u00e4mplar (av tv\u00e5 konfliktande poster anses den med den senaste tidsst\u00e4mpeln som aktuell), kommer konflikten alltid att l\u00f6sas till f\u00f6rm\u00e5n f\u00f6r den efterf\u00f6ljande transaktionen. P\u00e5 s\u00e5 s\u00e4tt har vi implementerat <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-klockor<\/a><\/noindex> - en kostnadseffektiv metod f\u00f6r konfliktl\u00f6sning i ett distribuerat system.<\/p>\n<h2>L\u00e5s<\/h2>\n<p>\nF\u00f6r att s\u00e4kerst\u00e4lla isolering beslutade vi att anv\u00e4nda den enklaste metoden - pessimistiska l\u00e5s baserade p\u00e5 den prim\u00e4ra nyckeln av posten. Med andra ord, i en transaktion m\u00e5ste posten f\u00f6rst l\u00e5sas, d\u00e4refter l\u00e4sas, modifieras och sparas. Endast efter en framg\u00e5ngsrik committ kan posten l\u00e5sas upp s\u00e5 att konkurrerande transaktioner kan anv\u00e4nda den.<\/p>\n<p>Implementeringen av s\u00e5dan l\u00e5sning \u00e4r enkel i en icke-distribuerad milj\u00f6. I ett distribuerat system finns det tv\u00e5 huvudsakliga v\u00e4gar: antingen implementera en distribuerad l\u00e5sning p\u00e5 klustret, eller f\u00f6rdela transaktioner s\u00e5 att transaktioner som involverar en och samma post alltid hanteras av samma koordinator.<\/p>\n<p>Eftersom v\u00e5ra data redan \u00e4r distribuerade i grupper av lokala transaktioner i SQL, beslutades det att koppla koordinatorer till grupper av lokala transaktioner: en koordinator utf\u00f6r alla transaktioner med en token fr\u00e5n 0 till 9, den andra med en token fr\u00e5n 10 till 19, och s\u00e5 vidare. Som ett resultat blir varje instans av koordinatorn m\u00e4stare \u00f6ver gruppen av transaktioner. <\/p>\n<p>D\u00e5 kan l\u00e5sningar implementeras som en enkel HashMap i minnet av koordinatorn.<\/p>\n<h2>Koordinatorers fel<\/h2>\n<p>\nEftersom en koordinator exklusivt hanterar en grupp av transaktioner \u00e4r det mycket viktigt att snabbt kunna fastst\u00e4lla om den har slutat fungera, s\u00e5 att ett f\u00f6rs\u00f6k att verkst\u00e4lla transaktionen g\u00f6rs inom timeout. F\u00f6r att detta ska vara snabbt och p\u00e5litligt till\u00e4mpade vi en fullt sammanl\u00e4nkad kvorum heartbeat-protokoll:<\/p>\n<p>I varje datacenter finns det minst tv\u00e5 noder av koordinatorn. Regelbundet skickar varje koordinator ett heartbeat-meddelande till de andra koordinatorerna och informerar dem om sin funktion, samt om vilket heartbeat-meddelande fr\u00e5n vilka koordinatorer i klustret han f\u00e5tt senast. <\/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 \/>\nGenom att ta emot liknande information fr\u00e5n de andra i sina heartbeat-meddelanden avg\u00f6r varje koordinator f\u00f6r sig sj\u00e4lv vilka noder i klustret som fungerar, och vilka som inte g\u00f6r det, utifr\u00e5n kvorumprincipen: om nod X har f\u00e5tt information om normal mottagning av meddelanden fr\u00e5n nod Y fr\u00e5n majoriteten av noderna i klustret, betyder det att Y fungerar. Och vice versa, s\u00e5 snart majoriteten meddelar om att de inte mottar meddelanden fr\u00e5n nod Y, betyder det att Y har slutat fungera. Det \u00e4r intressant att om kvorumet meddelar nod X att den inte l\u00e4ngre f\u00e5r n\u00e5gra meddelanden fr\u00e5n den, kommer sj\u00e4lva nod X att betrakta sig som felaktig.<\/p>\n<p>Heartbeat-meddelanden skickas med h\u00f6g frekvens, ungef\u00e4r 20 g\u00e5nger per sekund, med en period p\u00e5 50 ms. I Java \u00e4r det sv\u00e5rt att garantera appens svar inom 50 ms p\u00e5 grund av j\u00e4mf\u00f6rbar l\u00e4ngd p\u00e5 pauser orsakade av skr\u00e4psamlaren. Vi lyckades uppn\u00e5 s\u00e5dan svarstid med hj\u00e4lp av G1-skr\u00e4psamlaren, som g\u00f6r det m\u00f6jligt att st\u00e4lla in m\u00e5l f\u00f6r l\u00e4ngden av GC-pausar. Men ibland, ganska s\u00e4llan, \u00f6verskrider skr\u00e4psamlarens pauser 50 ms, vilket kan leda till falska felregistreringar. F\u00f6r att undvika detta rapporterar koordinatorsystemet inte om en fj\u00e4rrnods fel om den f\u00f6rsta heartbeat-meddelandet f\u00f6rsvinner, utan bara om flera f\u00f6rsvinner i rad. P\u00e5 s\u00e5 s\u00e4tt lyckades vi uppt\u00e4cka fel f\u00f6r koordinatorsystemet inom 200 ms. <\/p>\n<p>Men det \u00e4r inte tillr\u00e4ckligt att snabbt f\u00f6rst\u00e5 vilken nod som har slutat fungera. N\u00e5got m\u00e5ste g\u00f6ras \u00e5t detta. <\/p>\n<h2>Reservkraft<\/h2>\n<p>\nDen klassiska schemat f\u00f6resl\u00e5r att vid en masters fel, starta valet av en ny med hj\u00e4lp av en av<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\">universella<\/a><\/noindex> algoritmerna. Men s\u00e5dana algoritmer har v\u00e4lk\u00e4nda problem med konvergens \u00f6ver tid och l\u00e4ngden av sj\u00e4lva valprocessen. Dessa ytterligare f\u00f6rdr\u00f6jningar lyckades vi undvika genom att anv\u00e4nda en schema f\u00f6r att ers\u00e4tta koordinatorer i ett fullst\u00e4ndigt anslutet n\u00e4tverk:<\/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 \/>\nAnta att vi vill utf\u00f6ra en transaktion i grupp 50. L\u00e5t oss i f\u00f6rv\u00e4g definiera ers\u00e4ttningsschemat, det vill s\u00e4ga vilka noder som kommer att utf\u00f6ra transaktioner f\u00f6r grupp 50 i h\u00e4ndelse av att huvudkoordinatorn misslyckas. V\u00e5rt m\u00e5l \u00e4r att bevara systemets funktionalitet vid ett datacenters fel. Vi definierar att den f\u00f6rsta reservnoden kommer att vara en nod fr\u00e5n ett annat datacenter, och den andra reservnoden kommer att vara en fr\u00e5n det tredje. Detta schema v\u00e4ljs en g\u00e5ng och \u00e4ndras inte f\u00f6rr\u00e4n klusterets topologi \u00e4ndras, det vill s\u00e4ga tills nya noder ansluts (vilket intr\u00e4ffar mycket s\u00e4llan). Ordningen f\u00f6r att v\u00e4lja en ny aktiv master vid det gamla felet kommer alltid att vara: den aktiva mastern blir den f\u00f6rsta reservnoden, och om den ocks\u00e5 har slutat fungera - blir den andra reservnoden aktiv. <\/p>\n<p>Ett s\u00e5dant schema \u00e4r mer p\u00e5litligt \u00e4n en universell algoritm, eftersom det f\u00f6r att aktivera en ny master bara kr\u00e4ver att man fastst\u00e4ller faktumet av den gamla masters fel.<\/p>\n<p>Men hur f\u00f6rst\u00e5r kunderna vilken av m\u00e4starna som arbetar just nu? Det \u00e4r om\u00f6jligt att skicka information till tusentals kunder p\u00e5 50 ms. Det kan h\u00e4nda att kunden skickar en beg\u00e4ran om att \u00f6ppna en transaktion, utan att veta att denne m\u00e4stare redan har slutat fungera, och beg\u00e4ran kommer att h\u00e4nga p\u00e5 en timeout. F\u00f6r att f\u00f6rhindra detta skickar kunderna spekulativt en beg\u00e4ran om att \u00f6ppna en transaktion direkt till gruppens m\u00e4stare och b\u00e5da hans reserver, men bara den som \u00e4r den aktiva m\u00e4staren just nu kommer att svara p\u00e5 denna beg\u00e4ran. All efterf\u00f6ljande kommunikation inom transaktionen kommer kunden endast att ha med den aktiva m\u00e4staren.<\/p>\n<p>Reservm\u00e4starna som f\u00e5r beg\u00e4rningar p\u00e5 transaktioner som inte tillh\u00f6r dem sj\u00e4lva placerar dessa i k\u00f6n f\u00f6r ej skapade transaktioner, d\u00e4r de lagras under en viss tid. Om den aktiva m\u00e4staren d\u00f6r, tar den nya m\u00e4staren hand om beg\u00e4rningarna om att \u00f6ppna transaktioner fr\u00e5n sin k\u00f6 och svarar kunden. Om kunden redan har lyckats \u00f6ppna en transaktion med den gamla m\u00e4staren, ignoreras det andra svaret (och uppenbarligen kommer en s\u00e5dan transaktion inte att slutf\u00f6ras och kommer att upprepas av kunden).<\/p>\n<h2>Hur en transaktion fungerar<\/h2>\n<p>\nAntag att kunden har skickat en beg\u00e4ran till koordinatorn om att \u00f6ppna en transaktion f\u00f6r en viss entitet med en viss prim\u00e4rnyckel. Koordinatorn l\u00e5ser denna entitet och placerar den i l\u00e5stables i minnet. Om det beh\u00f6vs, l\u00e4ser koordinatorn in denna entitet fr\u00e5n lagringssystemet och sparar de erh\u00e5llna data i transaktionens tillst\u00e5nd i minnet hos koordinatorn.<\/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\u00e4r kunden vill \u00e4ndra data i transaktionen skickar hen en beg\u00e4ran om att modifiera entiteten till koordinatorn, som d\u00e5 placerar de nya uppgifterna i transaktionens tillst\u00e5ndstabell i minnet. H\u00e4r slutf\u00f6rs skrivningen \u2014 ingen skrivning till lagringssystemet g\u00f6rs.<\/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\u00e4r kunden beg\u00e4r sina \u00e4ndrade data inom en aktiv transaktion, agerar koordinatorn s\u00e5 h\u00e4r: <\/p>\n<ul>\n<li>om ID redan finns i transaktionen, tas data fr\u00e5n minnet; <\/li>\n<li>om ID inte finns i minnet, l\u00e4ses de saknade uppgifterna in fr\u00e5n nodlagringssystemen, kombineras med de redan befintliga i minnet, och resultatet ges till kunden. <\/li>\n<\/ul>\n<p>\nP\u00e5 s\u00e5 s\u00e4tt kan kunden l\u00e4sa sina egna \u00e4ndringar, medan andra kunder inte ser dessa f\u00f6r\u00e4ndringar, eftersom de endast lagras i koordinatorns minne och \u00e4nnu inte finns i Cassandra-noderna.<\/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\u00e4r en klient skickar en commit, sparas det tillst\u00e5nd som fanns i tj\u00e4nstens minne av koordinat\u00f6ren i den registrerade batchen, och i form av registrerad batch skickas det till Cassandra-lagringarna. Lagringarna g\u00f6r allt som kr\u00e4vs f\u00f6r att denna batch ska till\u00e4mpas atom\u00e4rt (fullst\u00e4ndigt) och returnerar svaret till koordinat\u00f6ren, som sedan frig\u00f6r l\u00e5sningarna och bekr\u00e4ftar transaktionens framg\u00e5ng f\u00f6r 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 \/>\nF\u00f6r att \u00e5ngra beh\u00f6ver koordinat\u00f6ren bara frig\u00f6ra minnet som upptas av transaktionens tillst\u00e5nd.<\/p>\n<p>Som ett resultat av ovanst\u00e5ende f\u00f6rb\u00e4ttringar har vi implementerat ACID-principerna:<\/p>\n<ul>\n<li><b>Atom\u00e4rt<\/b>. Detta \u00e4r en garanti f\u00f6r att ingen transaktion kommer att registreras i systemet delvis; antingen kommer alla underoperationer att utf\u00f6ras eller ingen av dem. Denna princip uppr\u00e4tth\u00e5lls av den registrerade batchen i Cassandra.<\/li>\n<li><b>Konsistens<\/b>. Varje framg\u00e5ngsrik transaktion registrerar per definition endast giltiga resultat. Om det efter att ha \u00f6ppnat transaktionen och utf\u00f6rt en del operationer uppt\u00e4cks att resultatet \u00e4r ogiltigt, utf\u00f6rs en \u00e5ngring.<\/li>\n<li><b>Isolering<\/b>. Vid utf\u00f6rande av en transaktion f\u00e5r parallella transaktioner inte p\u00e5verka dess resultat. Konkurrerande transaktioner isoleras med hj\u00e4lp av pessimistiska l\u00e5s p\u00e5 koordinat\u00f6ren. F\u00f6r l\u00e4sningar utanf\u00f6r transaktionen f\u00f6ljs isoleringsprincipen p\u00e5 niv\u00e5n Read Committed.<\/li>\n<li><b>Best\u00e4ndighet<\/b>. Oavsett problem p\u00e5 l\u00e4gre niv\u00e5er \u2014 str\u00f6mavbrott, maskinvarufel \u2014 ska \u00e4ndringar som gjorts av en framg\u00e5ngsrikt avslutad transaktion f\u00f6rbli kvar efter att verksamheten \u00e5terupptagit. <\/li>\n<\/ul>\n<p><\/p>\n<h2>L\u00e4sning via index<\/h2>\n<p>\nL\u00e5t oss ta en enkel tabell: <\/p>\n<pre><code>CREATE TABLE photos (\nid bigint primary key,\ne \u00e4gare bigint,\n\u00e4ndrad timestamp,\n\u2026)<\/code><\/pre>\n<p>\nDen har ett ID (prim\u00e4rnyckel), \u00e4gare och datum f\u00f6r \u00e4ndring. Vi beh\u00f6ver g\u00f6ra en mycket enkel fr\u00e5ga \u2014 h\u00e4mta data per \u00e4gare med \u00e4ndringsdatum \"de senaste 24 timmarna\". <\/p>\n<pre><code>SELECT *\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nF\u00f6r att en s\u00e5dan fr\u00e5ga ska fungera snabbt, m\u00e5ste en klassisk SQL-databas skapa ett index p\u00e5 kolumnerna (owner, modified). Detta kan vi g\u00f6ra ganska enkelt, eftersom vi nu har garantier f\u00f6r ACID!<\/p>\n<h2>Index i C*One<\/h2>\n<p>\nDet finns en ursprunglig tabell med foton, d\u00e4r postens ID \u00e4r prim\u00e4rnyckeln. <\/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 \/>\nF\u00f6r C*One skapar en ny tabell som \u00e4r en kopia av den ursprungliga. Nyckeln \u00f6verensst\u00e4mmer med det indexuttryck som dessutom inkluderar den prim\u00e4ra nyckeln f\u00f6r posten fr\u00e5n den ursprungliga tabellen:<\/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 \/>\nNu kan fr\u00e5gan om \"\u00e4garen under de senaste 24 timmarna\" skrivas om som en select fr\u00e5n en annan tabell:<\/p>\n<pre><code>SELECT * FROM i1_test\nWHERE owner=?\nAND modified&gt;?<\/code><\/pre>\n<p>\nKonsistensen mellan den ursprungliga tabellen photos och indexet i1 uppr\u00e4tth\u00e5lls automatiskt av koordinatorn. Utifr\u00e5n bara datamodellen, vid \u00e4ndringar, genererar koordinatorn och sparar f\u00f6r\u00e4ndringar inte bara f\u00f6r huvudtabellen utan \u00e4ven f\u00f6r kopiorna. Inga ytterligare \u00e5tg\u00e4rder g\u00f6rs med indextabellen, loggar l\u00e4ses inte, och l\u00e5s anv\u00e4nds inte. Det betyder att till\u00e4gg av index i stort sett inte f\u00f6rbrukar resurser och i praktiken inte p\u00e5verkar hastigheten p\u00e5 till\u00e4mpningen av modifieringar.<\/p>\n<p>Med hj\u00e4lp av ACID har vi lyckats implementera index \"som i SQL\". De har konsistens, kan skalas, fungerar snabbt, kan vara sammansatta och integreras i CQL-fr\u00e5gespr\u00e5ket. Inga \u00e4ndringar beh\u00f6ver g\u00f6ras i applikationskoden f\u00f6r att st\u00f6dja index. Allt \u00e4r enkelt, som i SQL. Och kanske viktigast av allt, index p\u00e5verkar inte hastigheten p\u00e5 exekveringen av modifieringar i den ursprungliga transaktionstabellen.<\/p>\n<h2>Vad som blev resultatet<\/h2>\n<p>\nVi utvecklade C*One f\u00f6r tre \u00e5r sedan och lanserade det i produktionsdrift. <\/p>\n<p>Vad har vi f\u00e5tt som resultat? L\u00e5t oss bed\u00f6ma detta baserat p\u00e5 delsystemet f\u00f6r hantering och lagring av foton, en av de mest kritiska datatyperna i sociala n\u00e4tverk. Det handlar inte om sj\u00e4lva fotona, utan om all m\u00f6jlig metadata. Just nu finns det cirka 20 miljarder s\u00e5dana poster i \"Odnoklassniki\", systemet hanterar 80 000 l\u00e4sf\u00f6rfr\u00e5gningar per sekund, och upp till 8 000 ACID-transaktioner per sekund relaterade till datamodifiering. <\/p>\n<p>N\u00e4r vi anv\u00e4nde SQL med replication factor = 1 (men i RAID 10), lagrades metadata f\u00f6r foton i en h\u00f6gtillg\u00e4nglig kluster av 32 maskiner med Microsoft SQL Server (plus 11 reservmaskiner). Dessutom avsattes 10 servrar f\u00f6r lagring av s\u00e4kerhetskopior. Totalt 50 kostsamma maskiner. Systemet fungerade under nominell belastning, utan marginal.<\/p>\n<p>Efter migreringen till det nya systemet har vi f\u00e5tt en replikationsfaktor = 3 \u2013 en kopia i varje datacenter. Systemet best\u00e5r av 63 noder i Cassandra-lagring och 6 koordinatormaskiner, totalt 69 servrar. Dessa maskiner \u00e4r dock betydligt billigare, deras totala kostnad uppg\u00e5r till cirka 30 % av kostnaden f\u00f6r systemet p\u00e5 SQL. Samtidigt h\u00e5lls belastningen p\u00e5 en niv\u00e5 av 30 %.<\/p>\n<p>Med implementeringen av C*One har ocks\u00e5 latensen minskat: i SQL tog en skrivoperation cirka 4,5 ms. I C*One \u2013 cirka 1,6 ms. Transaktionstiden \u00e4r i genomsnitt mindre \u00e4n 40 ms, commit utf\u00f6rs p\u00e5 2 ms, och l\u00e4s- och skrivtiden ligger i genomsnitt p\u00e5 2 ms. 99:e percentilen ligger p\u00e5 endast 3-3,1 ms, antalet timeouts har minskat med 100 g\u00e5nger \u2013 allt tack vare det omfattande anv\u00e4ndningen av spekulationer. <\/p>\n<p>Vid denna tidpunkt har en stor del av SQL Server-noderna tagits ur drift, nya produkter utvecklas endast med hj\u00e4lp av C*One. Vi har anpassat C*One f\u00f6r att fungera i v\u00e5rt moln. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/odnoklassniki\/blog\/346868\/\">one-cloud<\/a><\/noindex>, vilket har gjort det m\u00f6jligt att p\u00e5skynda distributionsprocessen av nya kluster, f\u00f6renkla konfigurationen och automatisera driften. Utan k\u00e4llkoden skulle detta varit betydligt sv\u00e5rare och mer klumpigt. <\/p>\n<p>Just nu arbetar vi med att migrera v\u00e5ra andra lagringsl\u00f6sningar till molnet \u2013 men det \u00e4r en helt annan historia.<br \/>\n<br \/>K\u00e4lla: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/odnoklassniki\/blog\/417593\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0445\u0440\u0430\u043d\u0438\u043b\u043e\u0441\u044c \u0432 SQL Server. \u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439, \u0434\u0430 \u0435\u0449\u0435 \u0438 \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a \u043e\u0442\u043a\u0430\u0437\u0443 \u0426\u041e\u0414 \u0434\u043e\u0441\u0442\u0443\u043f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f SQL \u0421\u0423\u0411\u0414, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u041e\u0431\u044b\u0447\u043d\u043e \u0432 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0434\u043d\u043e \u0438\u0437 NoSQL-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449, \u043d\u043e \u043d\u0435 \u0432\u0441\u0451 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 NoSQL: \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28484,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-37956","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u041e\u0434\u043d\u043e\u043a\u043b\u0430\u0441\u0441\u043d\u0438\u043a\u0430\u0445 \u043e\u043a\u043e\u043b\u043e 50 \u0422\u0411 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/newsql-nosql-acid\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sv_SE\" \/>\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\/sv\/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":"Tills nyligen fanns det omkring 50 TB data som behandlades i Odnoklassniki.","canonical_url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/newsql-nosql-acid","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sv_SE","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\/sv\/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\/sv\/wp-json\/wp\/v2\/posts\/37956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/comments?post=37956"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/37956\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media\/28484"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media?parent=37956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/categories?post=37956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/tags?post=37956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}