Моделирование данных в БД Cassandra 2.0 на CQL3

от автора

Статья предназначена в основном для новичков.

Ликбез

  • Cassandra (далее C*) — распределённая NoSQL БД, поэтому все решения «почему так, а не вот так» всегда принимаются с оглядкой на кластеризацию.
  • CQL — это SQL-подобный язык. Аббревиатура от Cassandra Query Language.
  • Node (нода) — инстанс C*, или java процесс в терминах операционных систем. На одной машине можно запустить несколько нод, например.
  • Основная единица хранения — строка. Строка может динамически раширятся до 2 миллиардов колонок. Это важно.
  • cqlsh — коммандная строка для CQL. Все примеры ниже выполняются именно в ней. Является частью дистрибутива C*.

Первый пример.

У нас есть сотрудники какой-то компании. Создадим таблицу на CQL и заполним данными:

CREATE TABLE employees (     name text,     age int,     role text,     PRIMARY KEY (name) ); INSERT INTO employees (name, age, role) VALUES ('john', 37, 'dev'); INSERT INTO employees (name, age, role) VALUES ('eric', 38, 'ceo'); 

Таблицы в C* обязаны иметь PRIMARY KEY. Он используется для поиска ноды, в которой хранится искомая строка.

Прочитаем данные:

SELECT * FROM employees; 

Эта картинка — руками разукрашенный вывод cqlsh.

Выглядит как обычная таблица из реляционной БД. C* создаст две строки.

Внимание! Это две внутренние структуры строк, а не таблицы. Если чуть слукавить, то можно сказать, что каждая строка — это как маленькая таблица. Далее понятней.

Второй пример.

Усложняем.
Добавим название компании.

CREATE TABLE employees (   company text,   name text,   age int,   role text,   PRIMARY KEY (company,name) ); INSERT INTO employees (company, name, age, role) VALUES ('OSC', 'john', 37, 'dev'); INSERT INTO employees (company, name, age, role) VALUES ('OSC', 'eric', 38, 'ceo'); INSERT INTO employees (company, name, age, role) VALUES ('RKG', 'anya', 38, 'lead'); INSERT INTO employees (company, name, age, role) VALUES ('RKG', 'ben', 38, 'dev'); INSERT INTO employees (company, name, age, role) VALUES ('RKG', 'chan', 38, 'ops'); 

Прочитаем данные:

SELECT * FROM employees; 


Внимание на PRIMARY KEY. Первый из параметров — company — это главный ключ, именно он будет использоваться для поиска ноды с этих пор. Второй ключ — name — превращается в колонку. Т.е. мы данные превращаем в название колонки. Был ‘eric’ обычными четырмя байтами, а стал частью названия колонки.

Вот так теперь выглядит внутреняя структура.

Как видите у нас:

  • Две компании — OSC и RKG. Здесь создалось всего две строки.
  • Зелёный eric хранит свой возраст и роль в двух ячейках. Аналогично все остальные.
  • Получается с такой структурой мы можем хранить 1 млрд сотрудников в каждой компании (строке). Помним же, что лимит количества колонок — 2 млрд?
  • Может показаться, что мы лишний раз храним одни и те же данные. Это так, но в C* такой дизайн — правильный паттерн моделирования.
  • Раширять строки — это основная фича при моделировании в С*.

Третий пример.

Ещё сложнее.

CREATE TABLE example (   A text,   B text,   C text,   D text,   E text,   F text,   PRIMARY KEY ((A,B), C, D) ); INSERT INTO example (A, B, C, D, E, F) VALUES ('a', 'b', 'c', 'd', 'e', 'f'); INSERT INTO example (A, B, C, D, E, F) VALUES ('a', 'b', 'c', 'g', 'h', 'i'); INSERT INTO example (A, B, C, D, E, F) VALUES ('a', 'b', 'j', 'k', 'l', 'm'); INSERT INTO example (A, B, C, D, E, F) VALUES ('a', 'n', 'o', 'p', 'q', 'r'); INSERT INTO example (A, B, C, D, E, F) VALUES ('s', 't', 'u', 'v', 'w', 'x'); 

Прочитаем данные:

SELECT * FROM example; 

Как видите, теперь наш главный ключ составной — (A,B).

Внутрення структура усложнилась:

  • Как видите, теперь каждая уникальная комбинация A и B — это ключ к строке.
  • У нас всего три уникальных ключа — a:b, a:n и s:t.
  • Колонки тоже размножились. В строке a:b у нас три уникальных комбинации — c:d, c:g, j:k — которые хранят в колонках E и F собственно данные — e:f, h:i, l:m.
  • Аналогично две другие строки.

Почему так сложно?

Это самый быстрый способ записи и хранения бесконечного количества данных в распределённой БД. C* как раз была разработана с упором на скорость записи/чтения. Вот, например, сравнение скоростей MongoDB, HBase и С*.

Примеры из реальной жизни

У нас есть некие события, которые происходят 1000 раз в секунду. Например с датчиков уровня шума снимаются показатели. 100 датчиков. Каждый из них присылает данные 10 раз в секунду. У нас 3 задачи:

  1. Продолжать записывать, если сервер БД (нода) остановит свою работу.
  2. Предоставлять график любого датчика за любой день за пару-тройку миллисекунд.
  3. Предоставлять график любого датчика за последние несколько часов за пару-тройку миллисекунд.

Первый пункт — легко. Нам нужно установить несколько нод, сделать каждую автономной. Может даже вынесту одну из них в облако.

Второй пункт — леко. Когда будем добавлять данные в таблицу укажем TTL:

INSERT INTO table_name (...) VALUES (...) TTL 3628800; -- 42 days 

Теперь по истечению указанного количества секунд вставленные данные сами по себе исчезнут из всех нод раз и навсегда.

Третий пункт — основная хитрость. Мы будем хранить данные одного дня в одной строке.

CREATE TABLE temperature_events_by_day (   day text, -- Text of the following format: 'YYYY-MM-DD'   sensor_id uuid,   event_time timestamp,   temperature double,   PRIMARY KEY ((day,sensor_id), event_time) ) WITH CLUSTERING ORDER BY event_time DESC; -- reverse sort the temperature values 

Так как главным ключём является уникальная комбинация день+датчик, то данные за один день будут храниться для каждого датчика в отдельной строке. Благодаря обратной сортировке внутри строки мы получаем самые важные для нас данные (последние) «на кончике пальцев».

Одновременно создадим вторую таблицу, где будем хранить те же самый данные, но без учета дней.

CREATE TABLE temperature_events (   sensor_id uuid,   event_time timestamp,   temperature double,   PRIMARY KEY (sensor_id, event_time) ) WITH CLUSTERING ORDER BY event_time DESC; 

«Что за бред! Зачем вторую таблицу?» — подумаете вы. Повторюсь: в БД С* хранить одно и то же значение по нескольку раз — это норма, правильная модель. Выигрыши следующие:

  • Запись данных очень и очень быстрая. Тысячи операций в секунду без каких-либо усилий по оптимизации.
  • Чтение данных тоже очень быстрое. В разы превосходит обычную индексированную, нормированную SQL БД.
  • Кластеру достаточно найти одну лишь строку по её ключу, чтобы получить моментальный доступ ко всем данным датчика.

Источники

Рекомендую к просмотру именно в этом порядке.

  1. Вебинар — Understanding How CQL3 Maps to Cassandra’s Internal Data Structure.
  2. Вебинар — The Data Model is Dead, Long Live the Data Model
  3. Вебинар — Become a Super Modeler
  4. Вебинар — The World’s Next Top Data Model
  5. Полная документация по CQL3- Cassandra Query Language (CQL) v3.1.1

ссылка на оригинал статьи http://habrahabr.ru/post/203200/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *