NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
Fins fa poc a Odnoklassniki, uns 50 TB de dades processades en temps real s'emmagatzemaven a SQL Server. Per a aquest volum, és gairebé impossible proporcionar un accés ràpid i fiable al centre de dades i fins i tot tolerant a errors mitjançant SQL DBMS. Normalment, en aquests casos s'utilitza una de les botigues NoSQL, però no tot es pot transferir a NoSQL: algunes entitats requereixen garanties de transacció ACID.

Això ens va portar a utilitzar l'emmagatzematge NewSQL, és a dir, un SGBD que proporciona tolerància a errors, escalabilitat i rendiment dels sistemes NoSQL, però que alhora conserva les garanties ACID familiars als sistemes clàssics. Hi ha pocs sistemes industrials en funcionament d'aquesta nova classe, així que vam implementar aquest sistema nosaltres mateixos i el vam posar en funcionament comercial.

Com funciona i què va passar: llegiu sota el tall.

Avui, l'audiència mensual d'Odnoklassniki és de més de 70 milions de visitants únics. Nosaltres entra als cinc primers xarxes socials més grans del món i entre els vint llocs principals on els usuaris passen més temps. La infraestructura "OK" gestiona càrregues molt elevades: més d'un milió de sol·licituds HTTP/s per front. Parts del parc de servidors de més de 8000 peces es troben a prop les unes de les altres, en quatre centres de dades de Moscou, la qual cosa permet proporcionar un retard de xarxa de menys d'1 ms entre ells.

Utilitzem Cassandra des del 2010, començant amb la versió 0.6. Avui dia, diverses desenes de clústers estan en funcionament. El clúster més ràpid processa més de 4 milions d'operacions per segon, mentre que el més gran emmagatzema 260 TB.

Tanmateix, tots aquests són clústers NoSQL normals que s'utilitzen per emmagatzemar poc coordinats dades. També volíem substituir l'emmagatzematge consistent principal, Microsoft SQL Server, que s'ha utilitzat des de la fundació d'Odnoklassniki. L'emmagatzematge constava de més de 300 màquines SQL Server Standard Edition, que contenien 50 TB de dades: entitats empresarials. Aquestes dades es modifiquen com a part de les transaccions d'ACID i requereixen alta consistència.

Per distribuir dades entre nodes d'SQL Server, hem utilitzat tant verticals com horitzontals partició (fragmentació). Històricament, hem utilitzat un esquema de fragmentació de dades senzill: cada entitat estava associada amb un testimoni, una funció de l'ID de l'entitat. Les entitats amb el mateix testimoni es van col·locar al mateix servidor SQL. La relació mestre-detall es va implementar de tal manera que els testimonis dels registres mestre i fill sempre coincideixen i es troben al mateix servidor. En una xarxa social, gairebé tots els registres es generen en nom de l'usuari, el que significa que totes les dades d'usuari dins d'un subsistema funcional s'emmagatzemen en un servidor. És a dir, una transacció comercial gairebé sempre implicava taules d'un servidor SQL, la qual cosa va permetre garantir la coherència de les dades mitjançant transaccions locals ACID, sense necessitat d'utilitzar lent i poc fiable transaccions distribuïdes d'ACID.

Gràcies al sharding i per accelerar SQL:

  • No fem servir restriccions de clau estrangera, ja que quan es divideix, l'identificador de l'entitat es pot localitzar en un altre servidor.
  • No fem servir procediments emmagatzemats i activadors a causa de la càrrega addicional de la CPU del SGBD.
  • No fem servir JOIN per tot l'anterior i moltes lectures aleatòries del disc.
  • Fora d'una transacció, utilitzem el nivell d'aïllament Read Uncommitted per reduir els bloquejos.
  • Només executem transaccions curtes (menys de 100 ms de mitjana).
  • No utilitzem UPDATE i DELETE de diverses files a causa d'un gran nombre de bloquejos; només actualitzem un registre alhora.
  • Les consultes sempre s'executen només mitjançant índexs: una consulta amb un pla d'exploració de taula completa significa per a nosaltres una sobrecàrrega de la base de dades i la seva fallada.

Aquests passos ens van permetre extreure gairebé el màxim rendiment dels servidors SQL. No obstant això, els problemes van anar augmentant. Fem-los una ullada.

Problemes amb SQL

  • Com que vam fer servir fragments escrits per nosaltres mateixos, els administradors van afegir nous fragments manualment. Durant tot aquest temps, les rèpliques de dades escalables no han atès sol·licituds.
  • A mesura que el nombre de registres de la taula creix, la velocitat d'inserció i modificació disminueix, quan s'afegeixen índexs a una taula existent, la velocitat disminueix en un múltiple, la creació i la recreació d'índexs pren un temps d'inactivitat.
  • Tenir una petita quantitat de Windows per a SQL Server en producció dificulta la gestió de la infraestructura

Però el principal problema és

falta de tolerància

SQL Server clàssic té una mala tolerància a errors. Suposem que només teniu un servidor de bases de dades i que falla cada tres anys. En aquest moment, el lloc està caigut durant 20 minuts, això és acceptable. Si teniu 64 servidors, aleshores el lloc es desactiva una vegada cada tres setmanes. I si teniu 200 servidors, el lloc no funciona cada setmana. Això és un problema.

Què es pot fer per millorar la tolerància a errors del servidor SQL? La Viquipèdia ens convida a construir clúster d'alta disponibilitat: on en cas de fallada d'algun dels components hi ha una còpia de seguretat.

Això requereix una flota d'equipaments cars: nombrosa duplicació, fibra òptica, emmagatzematge compartit i la inclusió de la reserva no funciona de manera fiable: al voltant del 10% de les inclusions acaben en la fallada del node de seguretat amb un tren darrere del node principal.

Però el principal desavantatge d'un clúster tan altament disponible és la disponibilitat zero en cas de fallada del centre de dades on es troba. Odnoklassniki té quatre centres de dades i hem de garantir el treball en un d'ells en cas de fallada total.

Per a això es podria aplicar Multi Master replicació integrada a SQL Server. Aquesta solució és molt més cara a causa del cost del programari i pateix problemes de replicació coneguts: retards de transaccions impredictibles amb replicació síncrona i retards en l'aplicació de la replicació (i, com a resultat, modificacions perdudes) amb replicació asíncrona. implicat resolució manual de conflictes fa que aquesta opció ens sigui totalment inaplicable.

Tots aquests problemes van requerir una solució cardinal i vam procedir a la seva anàlisi detallada. Aquí ens hem de familiaritzar amb el que fa bàsicament SQL Server: transaccions.

Transacció senzilla

Penseu en la transacció més senzilla des del punt de vista d'un programador SQL aplicat: afegir una foto a un àlbum. Els àlbums i les fotos s'emmagatzemen en plaques diferents. L'àlbum té un comptador de fotos públic. Aleshores, aquesta transacció es divideix en els passos següents:

  1. Bloquegem l'àlbum per clau.
  2. Creeu una entrada a la taula de fotos.
  3. Si la foto té un estat públic, tanquem el comptador de fotos públiques de l'àlbum, actualitzem el registre i cometem la transacció.

O en pseudocodi:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

Veiem que l'escenari més comú per a una transacció comercial és llegir dades de la base de dades a la memòria del servidor d'aplicacions, canviar alguna cosa i desar els nous valors a la base de dades. Normalment, en aquesta transacció actualitzem diverses entitats, diverses taules.

Quan s'executa una transacció, es pot produir una modificació simultània de les mateixes dades d'un altre sistema. Per exemple, Antispam pot decidir que l'usuari és d'alguna manera sospitós i, per tant, totes les fotos de l'usuari ja no haurien de ser públiques, s'han d'enviar per a la moderació, el que significa canviar photo.status per algun altre valor i apagar els comptadors corresponents. Òbviament, si aquesta operació es produirà sense garanties d'atomicitat d'aplicació i aïllament de modificacions competidores, com en ÀCID, aleshores el resultat no serà el que necessiteu: el comptador de fotos mostrarà el valor incorrecte o no s'enviaran totes les fotos per a la moderació.

Al llarg de l'existència d'Odnoklassniki s'ha escrit una gran quantitat d'aquest codi que manipula diverses entitats comercials dins d'una sola transacció. Segons l'experiència de les migracions a NoSQL amb Coherència de l'esdeveniment sabem que el repte més gran (i que consumeix temps) és la necessitat de desenvolupar codi per mantenir la coherència de les dades. Per tant, vam considerar que el principal requisit per al nou emmagatzematge era la disposició per a la lògica d'aplicació de les transaccions reals d'ACID.

Altres requisits igualment importants eren:

  • En cas d'error del centre de dades, tant la lectura com l'escriptura al nou emmagatzematge han d'estar disponibles.
  • Mantenir la velocitat actual de desenvolupament. És a dir, quan es treballa amb un repositori nou, la quantitat de codi hauria de ser aproximadament la mateixa, no hauria d'haver d'afegir res al repositori, desenvolupar algorismes per resoldre conflictes, mantenir índexs secundaris, etc.
  • La velocitat del nou emmagatzematge hauria de ser prou ràpida, tant a l'hora de llegir dades com a l'hora de processar transaccions, la qual cosa significava efectivament que les solucions acadèmicament rigoroses, de propòsit general, però lentes, com ara compromisos en dues fases.
  • Escalat automàtic sobre la marxa.
  • Utilitzant servidors barats habituals, sense necessitat de comprar peces de ferro exòtiques.
  • Possibilitat de desenvolupament d'emmagatzematge per part dels desenvolupadors de l'empresa. En altres paraules, es va donar prioritat a les solucions pròpies o de codi obert, preferiblement en Java.

Decisions, decisions

Analitzant possibles solucions, vam plantejar dues opcions d'arquitectura possibles:

El primer és prendre qualsevol servidor SQL i implementar la tolerància a errors requerida, el mecanisme d'escalat, l'agrupació de failover, la resolució de conflictes i les transaccions ACID distribuïdes, fiables i ràpides. Vam valorar aquesta opció com a molt no trivial i que requereix molt de temps.

La segona opció és prendre un emmagatzematge NoSQL ja fet amb escalat implementat, clustering de failover, resolució de conflictes i implementar transaccions i SQL tu mateix. A primera vista, fins i tot la tasca d'implementar SQL, per no parlar de les transaccions ACID, sembla una tasca durant anys. Però aleshores ens vam adonar que el conjunt de funcions SQL que utilitzem a la pràctica està tan lluny d'ANSI SQL com Cassandra CQL lluny d'ANSI SQL. Fent una ullada més de prop a CQL, ens vam adonar que està prou a prop del que necessitem.

Cassandra i CQL

Aleshores, què és interessant de Cassandra, quines característiques té?

En primer lloc, aquí podeu crear taules amb suport per a diversos tipus de dades, podeu fer SELECT o UPDATE per clau primària.

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

Per garantir la coherència de les rèpliques de dades, Cassandra utilitza enfocament del quòrum. En el cas més senzill, això vol dir que quan es col·loquen tres rèpliques de la mateixa fila en diferents nodes del clúster, l'escriptura es considera reeixida si la majoria dels nodes (és a dir, dos de cada tres) van confirmar l'èxit d'aquesta operació d'escriptura. Les dades d'una sèrie es consideren coherents si, en llegir, la majoria dels nodes van ser sondejats i confirmats. Així, si hi ha tres rèpliques, es garanteix la coherència completa i instantània de les dades si falla un node. Aquest enfocament ens va permetre implementar un esquema encara més fiable: enviar sempre peticions a les tres rèpliques, esperant una resposta de les dues més ràpides. Aleshores es descarta la resposta tardana de la tercera rèplica. Al mateix temps, un node que arriba tard amb una resposta pot tenir problemes greus: frens, recollida d'escombraries a la JVM, recuperació directa de memòria al nucli de Linux, fallada del maquinari, desconnexió de la xarxa. Tanmateix, les operacions i les dades del client no es veuen afectades de cap manera.

L'enfocament quan accedim a tres nodes i rebem una resposta de dos s'anomena l'especulació: s'envia una sol·licitud de rèpliques addicionals abans que "caigui".

Un altre avantatge de Cassandra és Batchlog, un mecanisme que garanteix que els canvis que feu s'apliquen completament o no s'apliquen completament al paquet. Això ens permet resoldre A en ÀCID - atomicitat fora de la caixa.

El més proper a les transaccions a Cassandra és l'anomenat "transaccions lleugeres". Però estan lluny de ser transaccions amb ACID "reals": de fet, aquesta és una oportunitat per fer CAS sobre les dades d'un sol registre, utilitzant el consens del protocol de pes pesat de Paxos. Per tant, la velocitat d'aquestes transaccions és baixa.

El que vam trobar a faltar a Cassandra

Per tant, vam haver d'implementar transaccions reals d'ACID a Cassandra. Amb l'ajuda de les quals podríem implementar fàcilment altres dues funcions convenients del SGBD clàssic: índexs ràpids consistents, que ens permetrien seleccionar dades no només per la clau primària, i el generador habitual d'ID d'increment automàtic monòton.

C*Un

Així va néixer el nou DBMS C*Un, que consta de tres tipus de nodes de servidor:

  • Els emmagatzematges són servidors Cassandra (gairebé) estàndards responsables d'emmagatzemar dades a les unitats locals. A mesura que la càrrega i el volum de dades creixen, el seu nombre es pot escalar fàcilment fins a desenes i centenars.
  • Coordinadors de transaccions: garanteixen l'execució de les transaccions.
  • Els clients són servidors d'aplicacions que implementen operacions comercials i inicien transaccions. Hi pot haver milers d'aquests clients.

NewSQL = NoSQL+ACID

Els servidors de tot tipus estan en un clúster comú, utilitzen el protocol de missatge intern de Cassandra per comunicar-se entre ells i xafarderies per a l'intercanvi d'informació de clúster. Amb l'ajuda de Heartbeat, els servidors aprenen sobre falles mútues, mantenen un únic esquema de dades: taules, la seva estructura i replicació; esquema de particions, topologia de clúster, etc.

Clients

NewSQL = NoSQL+ACID

En lloc dels controladors estàndard, s'utilitza el mode Fat Client. Aquest node no emmagatzema dades, però pot actuar com a coordinador d'execució de sol·licituds, és a dir, el propi Client actua com a coordinador de les seves peticions: consulta les rèpliques d'emmagatzematge i resol els conflictes. Això no només és més fiable i ràpid que el controlador estàndard, que requereix comunicació amb un coordinador remot, sinó que també us permet controlar la transmissió de sol·licituds. Fora d'una transacció oberta al client, les sol·licituds s'envien als magatzems. Si el client va obrir una transacció, totes les sol·licituds de la transacció s'envien al coordinador de transaccions.
NewSQL = NoSQL+ACID

C*Coordinador d'una transacció

El coordinador és el que hem implementat per a C*One des de zero. És responsable de gestionar les transaccions, els bloquejos i l'ordre en què s'apliquen les transaccions.

Per a cada transacció atesa, el coordinador genera una marca de temps: cada transacció posterior és més gran que la de la transacció anterior. Com que el sistema de resolució de conflictes a Cassandra es basa en marques de temps (de dos registres en conflicte, es considera rellevant la marca de temps més recent), el conflicte sempre es resoldrà a favor de la transacció posterior. Així ho hem implementat rellotge lamport és una manera barata de resoldre conflictes en un sistema distribuït.

Panys

Per garantir l'aïllament, vam decidir utilitzar la manera més senzilla: bloquejos pessimistes a la clau primària del registre. En altres paraules, en una transacció, primer s'ha de bloquejar un registre, només després llegir-lo, modificar-lo i desar-lo. Només després d'una confirmació exitosa es pot desbloquejar un registre perquè les transaccions competidores puguin utilitzar-lo.

Implementar aquest bloqueig és senzill en un entorn no distribuït. En un sistema distribuït, hi ha dues maneres principals: implementar el bloqueig distribuït en un clúster o distribuir transaccions de manera que les transaccions que involucren el mateix registre siguin sempre gestionades pel mateix coordinador.

Com que en el nostre cas les dades ja es distribueixen entre grups de transaccions locals en SQL, es va decidir assignar grups de transaccions locals als coordinadors: un coordinador realitza totes les transaccions amb un testimoni del 0 al 9, el segon amb un testimoni de del 10 al 19, i així successivament. Com a resultat, cadascuna de les instàncies del coordinador es converteix en el mestre del grup de transaccions.

Aleshores, els bloquejos es poden implementar com un HashMap banal a la memòria del coordinador.

Denegacions dels coordinadors

Com que un coordinador serveix exclusivament a un grup de transaccions, és molt important determinar ràpidament el fet de la seva fallada perquè l'intent repetit d'executar la transacció estigui dins del temps d'espera. Per fer-ho ràpid i fiable, hem fet servir un protocol de ritme de quòrum totalment mallat:

Cada centre de dades allotja almenys dos nodes coordinadors. Periòdicament, cada coordinador envia un missatge de ritme cardíac als altres coordinadors i els informa sobre el seu funcionament, així com sobre l'última vegada que va rebre missatges de ritme cardíac de quins coordinadors del clúster.

NewSQL = NoSQL+ACID

En rebre informació similar de la resta com a part dels seus missatges de batec del cor, cada coordinador decideix per si mateix quins nodes del clúster funcionen i quins no, guiat pel principi de quòrum: si el node X va rebre informació de la majoria dels nodes del clúster sobre la recepció normal de missatges del node Y, aleshores, Y funciona. Per contra, tan aviat com la majoria informa que falten missatges del node Y, llavors Y ha fallat. Curiosament, si el quòrum diu al node X que no està rebent més missatges d'ell, llavors el mateix node X considerarà que ha fallat.

Els missatges de batecs del cor s'envien a una freqüència alta, unes 20 vegades per segon, amb un període de 50 ms. A Java, és difícil garantir una resposta de l'aplicació en 50 ms a causa dels temps de pausa comparables causats pel col·lector d'escombraries. Hem pogut aconseguir aquest temps de resposta utilitzant el col·lector d'escombraries G1, que us permet especificar un objectiu per a la durada de les pauses de GC. Tanmateix, de vegades, molt poques vegades, les pauses del col·lector superen els 50 ms, la qual cosa pot provocar una detecció de fallades falses. Per evitar-ho, el coordinador no informa de la fallada del node remot quan es perd el primer missatge de batec del mateix, només si en falten diversos seguits, així que hem aconseguit detectar la fallada del node coordinador en 200 ms.

Però no n'hi ha prou per entendre ràpidament quin node ha deixat de funcionar. S'ha de fer alguna cosa al respecte.

Reserva

L'esquema clàssic suposa que, en cas de fracàs del mestre per llançar l'elecció d'un de nou utilitzant una de les de moda universal algorismes. Tanmateix, aquests algorismes tenen problemes coneguts amb la convergència en el temps i la durada del propi procés electoral. Hem aconseguit evitar aquests retards addicionals mitjançant l'esquema de substitució del coordinador en una xarxa completament connectada:

NewSQL = NoSQL+ACID

Suposem que volem executar una transacció al grup 50. Definim per endavant un esquema de substitució, és a dir, quins nodes executaran les transaccions del grup 50 en cas de fallada del coordinador principal. El nostre objectiu és mantenir el sistema en funcionament en cas de fallada del centre de dades. Definim que la primera reserva serà un node d'un altre centre de dades i la segona reserva serà un node del tercer. Aquest esquema es selecciona una vegada i no canvia fins que canvia la topologia del clúster, és a dir, fins que hi entren nous nodes (cosa que passa molt poques vegades). L'ordre d'elecció d'un nou mestre actiu en cas de fallada de l'antic serà sempre el següent: la primera reserva es convertirà en mestre actiu, i si ha deixat de funcionar, es convertirà en la segona reserva.

Aquest esquema és més fiable que un algorisme universal, ja que per activar un nou mestre n'hi ha prou per determinar el fet de la fallada de l'antic.

Però, com entendran els clients quin dels mestres treballa actualment? És impossible enviar informació a milers de clients en 50 ms. És possible que un client enviï una sol·licitud per obrir una transacció, sense saber encara que aquest mestre ja no funciona, i la sol·licitud es penjarà en un temps d'espera. Per evitar que això succeeixi, els clients envien de manera especulativa una sol·licitud per obrir una transacció al mestre del grup i a les dues reserves alhora, però només el que és el mestre actiu en aquest moment respondrà a aquesta sol·licitud. Tota la comunicació posterior dins de la transacció serà realitzada pel client només amb el mestre actiu.

Els mestres d'espera col·loquen les sol·licituds rebudes de transaccions que no són pròpies a la cua de transaccions no nascudes, on s'emmagatzemen durant un temps. Si el mestre actiu mor, el nou mestre processa les sol·licituds d'obertura de transaccions des de la seva cua i respon al client. Si el client ja ha aconseguit obrir una transacció amb l'antic mestre, la segona resposta s'ignora (i, òbviament, aquesta transacció no es completarà i el client la repetirà).

Com funciona una transacció

Suposem que el client va enviar una sol·licitud al coordinador per obrir una transacció per a tal o tal entitat amb tal o tal clau primària. El coordinador bloqueja aquesta entitat i la col·loca a la taula de bloqueig a la memòria. Si cal, el coordinador llegeix aquesta entitat de la botiga i desa les dades rebudes en un estat transaccional a la memòria del coordinador.

NewSQL = NoSQL+ACID

Quan un client vol canviar les dades d'una transacció, envia una sol·licitud al coordinador perquè modifiqui l'entitat, i el coordinador col·loca les noves dades a la taula d'estat de la transacció a la memòria. Això completa l'enregistrament: no s'escriu l'emmagatzematge.

NewSQL = NoSQL+ACID

Quan un client sol·licita les seves pròpies dades modificades com a part d'una transacció activa, el coordinador actua així:

  • si l'identificador ja està a la transacció, les dades s'extreuen de la memòria;
  • si no hi ha cap identificador a la memòria, les dades que falten es llegeixen dels nodes d'emmagatzematge, combinades amb les que ja estan a la memòria, i el resultat es retorna al client.

Així, el client pot llegir els seus propis canvis, i altres clients no veuen aquests canvis, perquè només s'emmagatzemen a la memòria del coordinador, encara no es troben als nodes Cassandra.

NewSQL = NoSQL+ACID

Quan el client envia una confirmació, el coordinador emmagatzema l'estat que el servei tenia a la memòria en un lot registrat i s'envia a les botigues Cassandra com a lot registrat. Els repositoris fan tot el necessari perquè aquest paquet s'apliqui atòmicament (completament) i retornen una resposta al coordinador, que allibera els bloquejos i confirma l'èxit de la transacció al client.

NewSQL = NoSQL+ACID

I per a la recuperació, el coordinador només necessita alliberar la memòria ocupada per l'estat de la transacció.

Com a resultat de les millores descrites anteriorment, hem implementat els principis d'ACID:

  • Atomicitat. Això és una garantia que cap transacció no es fixarà parcialment al sistema, o s'executaran totes les seves suboperacions o no s'executarà cap d'elles. En el nostre cas, aquest principi s'observa a causa del lot registrat a Cassandra.
  • Coherència. Cada transacció reeixida, per definició, només compromet resultats vàlids. Si, després d'obrir una transacció i realitzar algunes de les operacions, es constata que el resultat no és vàlid, es realitza un rollback.
  • aïllament. Quan s'executa una transacció, les transaccions paral·leles no haurien d'afectar el seu resultat. Les transaccions concurrents estan aïllades amb bloquejos pessimistes al coordinador. Per a lectures fora d'una transacció, es respecta el principi d'aïllament al nivell Read Committed.
  • Resiliència. Independentment dels problemes als nivells inferiors (un apagament del sistema, una fallada de maquinari), els canvis fets per una transacció completada amb èxit s'han de conservar després de la represa del funcionament.

Lectura per índexs

Prenguem una taula senzilla:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

Té un identificador (clau primària), un propietari i una data de modificació. Heu de fer una sol·licitud molt senzilla: seleccioneu les dades del propietari amb la data del canvi "per a l'últim dia".

SELECT *
WHERE owner=?
AND modified>?

Per processar aquesta consulta ràpidament, en un SGBD SQL clàssic, cal crear un índex a les columnes (propietari, modificat). Ho podem fer de manera senzilla, ja que ara tenim garanties d'ÀCID!

Índexs en C*One

Hi ha una taula inicial amb fotos en què l'identificador de registre és una clau primària.

NewSQL = NoSQL+ACID

Per a un índex, C*One crea una taula nova que és una còpia de la taula original. La clau és la mateixa que l'expressió d'índex, però també inclou la clau primària del registre de la taula d'origen:

NewSQL = NoSQL+ACID

Ara la consulta de "propietari en les últimes XNUMX hores" es pot reescriure com una selecció d'una altra taula:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

La coherència de les dades entre les fotos de la taula d'origen i l'índex i1 es manté automàticament pel coordinador. Basant-se només en l'esquema de dades, quan es rep un canvi, el coordinador genera i recorda el canvi no només de la taula principal, sinó també els canvis de les còpies. No es realitza cap acció addicional amb la taula d'índex, no es llegeixen els registres, no s'utilitzen bloquejos. És a dir, afegir índexs gairebé no consumeix recursos i pràcticament no afecta la velocitat d'aplicació de modificacions.

Amb l'ajuda d'ACID, vam aconseguir implementar índexs "com en SQL". Són coherents, escalables, ràpids, componibles i integrats en el llenguatge de consulta CQL. El suport de l'índex no requereix cap canvi al codi de l'aplicació. Tot és senzill, com en SQL. I el més important, els índexs no afecten la velocitat d'execució de les modificacions a la taula de transaccions original.

Què va passar

Vam desenvolupar C*One fa tres anys i el vam posar en funcionament comercial.

Amb què hem acabat? Avaluem-ho amb l'exemple d'un subsistema per processar i emmagatzemar fotografies, un dels tipus de dades més importants d'una xarxa social. No es tracta dels cossos de les fotografies en si, sinó de tot tipus de metainformació. Ara a Odnoklassniki hi ha uns 20 mil milions d'aquests registres, el sistema processa 80 mil sol·licituds de lectura per segon, fins a 8 mil transaccions ACID per segon relacionades amb la modificació de dades.

Quan vam utilitzar SQL amb factor de replicació = 1 (però a RAID 10), la metainformació de la foto es va emmagatzemar en un clúster d'alta disponibilitat de 32 màquines Microsoft SQL Server (més 11 de recanvi). A més, es van assignar 10 servidors per emmagatzemar còpies de seguretat. Un total de 50 cotxes cars. Al mateix temps, el sistema funcionava a càrrega nominal, sense marge.

Després de migrar a un sistema nou, vam obtenir un factor de replicació = 3: una còpia a cada centre de dades. El sistema consta de 63 nodes d'emmagatzematge Cassandra i 6 màquines coordinadores, per un total de 69 servidors. Però aquestes màquines són molt més barates, amb un total d'aproximadament el 30% del cost d'un sistema SQL. En aquest cas, la càrrega es manté al nivell del 30%.

Amb la introducció de C*One, la latència també va disminuir: en SQL, una operació d'escriptura trigava uns 4,5 ms. En C * Un: uns 1,6 ms. La durada d'una transacció és de mitjana inferior a 40 ms, la confirmació es completa en 2 ms, la durada de lectura i escriptura és de 2 ms de mitjana. El percentil 99 és només de 3-3,1 ms, el nombre de temps morts ha disminuït 100 vegades, tot a causa de l'ús generalitzat de l'especulació.

Fins ara, la majoria dels nodes SQL Server s'han donat de baixa, els nous productes només es desenvolupen utilitzant C * One. Hem adaptat C*One perquè funcioni al nostre núvol un sol núvol, que va permetre accelerar el desplegament de nous clústers, simplificar la configuració i automatitzar el funcionament. Sense el codi font, això seria molt més difícil i triturat.

Ara estem treballant per transferir els nostres altres emmagatzematges al núvol, però aquesta és una història completament diferent.

Font: www.habr.com

Afegeix comentari