Cassandra. Como non morrer se só coñeces a Oracle

Ola Habr.

Chámome Misha Butrimov, gustaríame falarche un pouco sobre Cassandra. A miña historia será útil para aqueles que nunca atoparon bases de datos NoSQL: ten moitas funcións de implementación e trampas que debes coñecer. E se non viu nada máis que Oracle ou calquera outra base de datos relacional, estas cousas salvarán a súa vida.

Que ten de bo Cassandra? É unha base de datos NoSQL deseñada sen un único punto de falla que se escala ben. Se necesitas engadir un par de terabytes para algunha base de datos, simplemente engade nodos ao anel. Queres expandilo a outro centro de datos? Engade nodos ao clúster. Queres aumentar o RPS procesado? Engade nodos ao clúster. Tamén funciona na dirección oposta.

Cassandra. Como non morrer se só coñeces a Oracle

En que máis é boa? Trátase de atender moitas solicitudes. Pero canto é moito? 10, 20, 30, 40 mil solicitudes por segundo non son moito. 100 mil solicitudes por segundo para gravar tamén. Hai empresas que dixeron que manteñen 2 millóns de solicitudes por segundo. Probablemente terán que crelo.

E en principio, Cassandra ten unha gran diferenza cos datos relacionais: non se parecen en absoluto a eles. E isto é moi importante lembralo.

Non todo o que parece igual funciona igual

Unha vez que un compañeiro veu a min e preguntou: "Aquí está unha linguaxe de consulta CQL Cassandra, e ten unha declaración select, ten onde, ten e. Escribo cartas e non funciona. Por que?". Tratar a Cassandra como unha base de datos relacional é a forma perfecta de suicidarse violentamente. E non o estou promovendo, está prohibido en Rusia. Só deseñarás algo mal.

Por exemplo, un cliente achégase a nós e di: “Construamos unha base de datos para series de televisión ou unha base de datos para un directorio de receitas. Teremos alí pratos de comida ou unha lista de series de televisión e actores nela". Dicimos con alegría: "Imos!" Só ten que enviar dous bytes, un par de sinais e xa está, todo funcionará de forma moi rápida e fiable. E todo está ben ata que veñen os clientes e din que as amas de casa tamén están a resolver o problema contrario: teñen unha lista de produtos, e queren saber que prato queren cociñar. Estás morto.

Isto débese a que Cassandra é unha base de datos híbrida: proporciona ao mesmo tempo un valor clave e almacena os datos en columnas amplas. En Java ou Kotlin, podería describirse así:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

É dicir, un mapa que contén tamén un mapa ordenado. A primeira clave deste mapa é a clave de fila ou chave de partición, a clave de partición. A segunda clave, que é a clave dun mapa xa ordenado, é a clave de agrupación.

Para ilustrar a distribución da base de datos, debuxemos tres nodos. Agora cómpre comprender como descompoñer os datos en nodos. Porque se ateigamos todo nun só (por certo, pode haber mil, dous mil, cinco, tantos como queiras), non se trata realmente de distribución. Polo tanto, necesitamos unha función matemática que devolverá un número. Só un número, un int longo que caerá nalgún rango. E teremos un nodo responsable dun rango, o segundo para o segundo, o enésimo para o enésimo.

Cassandra. Como non morrer se só coñeces a Oracle

Este número tómase mediante unha función hash, que se aplica ao que chamamos clave de partición. Esta é a columna que se especifica na directiva Clave primaria, e esta é a columna que será a primeira e máis básica clave do mapa. Determina que nodo recibirá que datos. En Cassandra créase unha táboa case coa mesma sintaxe que en SQL:

CREATE TABLE users (
	user_id uu id,
	name text,
	year int,
	salary float,
	PRIMARY KEY(user_id)

)

Neste caso, a chave primaria consta dunha columna e tamén é a clave de partición.

Como actuarán os nosos usuarios? Algúns irán a un nodo, outros a outro e outros a un terceiro. O resultado é unha táboa hash común, tamén coñecida como mapa, tamén coñecida como dicionario en Python, ou unha estrutura simple de valores de clave desde a que podemos ler todos os valores, ler e escribir por clave.

Cassandra. Como non morrer se só coñeces a Oracle

Seleccionar: cando permitir o filtrado se converte nunha exploración completa ou o que non se debe facer

Escribamos algunha declaración seleccionada: select * from users where, userid = . Resulta como en Oracle: escribimos select, especificamos as condicións e todo funciona, os usuarios obtéñeno. Pero se seleccionas, por exemplo, un usuario cun determinado ano de nacemento, Cassandra quéixase de que non pode cumprir a solicitude. Porque non sabe nada de como distribuímos os datos sobre o ano de nacemento, só ten unha columna indicada como clave. Entón ela di: "Está ben, aínda podo cumprir esta solicitude. Engadir filtrado permitido." Engadimos a directiva, todo funciona. E neste momento acontece algo terrible.

Cando utilizamos datos de proba, todo está ben. E cando executas unha consulta en produción, onde temos, por exemplo, 4 millóns de rexistros, entón non todo é moi bo para nós. Porque permitir filtrado é unha directiva que permite a Cassandra recoller todos os datos desta táboa de todos os nodos, todos os centros de datos (se hai moitos deles neste clúster) e só despois filtralos. Este é un análogo de Full Scan, e case ninguén está encantado con el.

Se só necesitásemos usuarios por DNI, estaríamos ben con isto. Pero ás veces necesitamos escribir outras consultas e impoñer outras restricións á selección. Por iso, lembramos: todo isto é un mapa que ten unha clave de partición, pero no seu interior hai un mapa ordenado.

E tamén ten unha chave, que chamamos Chave de agrupación. Esta clave, que, á súa vez, está formada polas columnas que seleccionamos, coa axuda das cales Cassandra entende como se ordenan fisicamente os seus datos e se situarán en cada nodo. É dicir, para algunha chave de partición, a chave de agrupación indicarache exactamente como meter os datos nesta árbore, o lugar que ocupará alí.

Esta é realmente unha árbore, simplemente chámase alí un comparador, ao que pasamos un determinado conxunto de columnas en forma de obxecto, e tamén se especifica como unha lista de columnas.

CREATE TABLE users_by_year_salary_id (
	user_id uuid,
	name text,
	year int,
	salary float,
	PRIMARY KEY((year), salary, user_id)

Preste atención á directiva de chave primaria; o seu primeiro argumento (no noso caso, o ano) é sempre a clave de partición. Pode constar dunha ou máis columnas, non importa. Se hai varias columnas, cómpre eliminar de novo entre corchetes para que o preprocesador de linguaxe entenda que esta é a chave primaria e, detrás dela, todas as demais columnas están a chave de agrupación. Neste caso, transmitiranse no comparador na orde en que aparecen. É dicir, a primeira columna é máis significativa, a segunda é menos significativa, etc. Como escribimos, por exemplo, é igual aos campos para as clases de datos: enumeramos os campos e para eles escribimos cales son máis grandes e cales son máis pequenas. En Cassandra, estes son, relativamente falando, os campos da clase de datos, aos que se aplicarán os iguais escritos para ela.

Establecemos a clasificación e impoñemos restricións

Debe lembrar que a orde de ordenación (descendente, ascendente, o que sexa) establécese no mesmo momento en que se crea a clave e non se pode cambiar máis tarde. Determina fisicamente como se ordenarán os datos e como se almacenarán. Se precisa cambiar a clave de agrupación ou a orde de clasificación, terá que crear unha nova táboa e transferir os datos a ela. Isto non funcionará cun existente.

Cassandra. Como non morrer se só coñeces a Oracle

Enchemos a nosa táboa de usuarios e vimos que caían nun anel, primeiro por ano de nacemento, e despois dentro de cada nodo por salario e ID de usuario. Agora podemos seleccionar impoñendo restricións.

Volve aparecer o noso de traballo where, and, e temos usuarios, e todo está ben de novo. Pero se tentamos usar só unha parte da clave de agrupación, e outra menos significativa, entón Cassandra queixarase inmediatamente de que non pode atopar o lugar do noso mapa onde este obxecto, que ten estes campos para o comparador nulo, e este. que se acaba de establecer, - onde está. Terei que sacar todos os datos deste nodo de novo e filtralos. E este é un análogo da exploración completa dentro dun nodo, isto é malo.

En calquera situación pouco clara, crea unha nova táboa

Se queremos poder orientarnos aos usuarios por DNI, ou por idade, ou por salario, que debemos facer? Nada. Só usa dúas táboas. Se precisas chegar aos usuarios de tres formas diferentes, haberá tres táboas. Atrás quedaron os tempos nos que aforrabamos espazo no parafuso. Este é o recurso máis barato. Custa moito menos que o tempo de resposta, o que pode ser prexudicial para o usuario. É moito máis agradable para o usuario recibir algo nun segundo que en 10 minutos.

Intercambiamos espazo innecesario e datos desnormalizados pola capacidade de escalar ben e funcionar de forma fiable. Despois de todo, de feito, un clúster que consta de tres centros de datos, cada un dos cales ten cinco nodos, cun nivel aceptable de conservación de datos (cando nada se perde), é capaz de sobrevivir á morte dun centro de datos por completo. E dous nodos máis en cada un dos dous restantes. E só despois comezan os problemas. Esta é unha redundancia bastante boa, paga a pena un par de unidades SSD e procesadores adicionais. Polo tanto, para usar Cassandra, que nunca é SQL, no que non hai relacións, chaves estranxeiras, cómpre coñecer regras sinxelas.

Deseñamos todo segundo a túa solicitude. O principal non son os datos, senón como vai funcionar a aplicación con eles. Se precisa recibir diferentes datos de diferentes xeitos ou os mesmos datos de diferentes xeitos, debemos poñelos de forma conveniente para a aplicación. En caso contrario, fallaremos na exploración completa e Cassandra non nos dará ningunha vantaxe.

Desnormalizar os datos é a norma. Esquecémonos das formas normais, xa non temos bases de datos relacionais. Se botamos algo 100 veces, deitarase 100 veces. Aínda é máis barato que parar.

Seleccionamos as claves para particionar para que se distribúan normalmente. Non queremos que o hash das nosas chaves caia nun rango estreito. É dicir, o ano de nacemento do exemplo anterior é un mal exemplo. Máis precisamente, é bo que os nosos usuarios se distribúan normalmente por ano de nacemento, e malo se falamos de alumnos de 5o de primaria: a partición alí non será moi boa.

A clasificación se selecciona unha vez na fase de creación da clave de agrupación. Se hai que cambiar, teremos que actualizar a nosa táboa cunha clave diferente.

E o máis importante: se necesitamos recuperar os mesmos datos de 100 formas diferentes, entón teremos 100 táboas diferentes.

Fonte: www.habr.com

Engadir un comentario