Моделирование данных в Cassandra

1. Обзор

Cassandra - это база данных NoSQL, которая обеспечивает высокую доступность и горизонтальную масштабируемость без снижения производительности.

Чтобы получить максимальную производительность от Cassandra, нам необходимо тщательно спроектировать схему на основе шаблонов запросов, специфичных для конкретной бизнес-задачи.

В этой статье мы рассмотрим некоторые ключевые концепции подхода к моделированию данных в Cassandra .

Прежде чем продолжить, вы можете прочитать нашу статью «Кассандра с Java», чтобы понять основы и понять, как подключиться к Cassandra с помощью Java.

2. Ключ раздела

Cassandra - это распределенная база данных, в которой данные разделены и хранятся на нескольких узлах в кластере.

Ключ раздела состоит из одного или нескольких полей данных и используется разделителем для генерации токена посредством хеширования для равномерного распределения данных по кластеру .

3. Ключ кластеризации

Ключ кластеризации состоит из одного или нескольких полей и помогает кластеризовать или группировать строки с одним и тем же ключом раздела и сохранять их в отсортированном порядке.

Допустим, мы храним данные временных рядов в Cassandra и хотим получить данные в хронологическом порядке. Ключ кластеризации, который включает поля данных временных рядов, будет очень полезен для эффективного извлечения данных для этого варианта использования.

Примечание. Комбинация ключа раздела и ключа кластеризации составляет первичный ключ и однозначно идентифицирует любую запись в кластере Cassandra.

4. Рекомендации по шаблонам запросов

Прежде чем начать моделирование данных в Cassandra, мы должны определить шаблоны запросов и убедиться, что они соответствуют следующим рекомендациям:

  1. Каждый запрос должен получать данные из одного раздела
  2. Мы должны отслеживать, сколько данных хранится в разделе, так как Cassandra имеет ограничения на количество столбцов, которые могут храниться в одном разделе.
  3. Можно денормализовать и дублировать данные для поддержки различных типов шаблонов запросов к одним и тем же данным.

Основываясь на приведенных выше рекомендациях, давайте рассмотрим некоторые реальные варианты использования и то, как мы будем моделировать для них модели данных Cassandra.

5. Примеры моделирования данных в реальном мире

5.1. Сообщения в Facebook

Предположим, что мы храним сообщения Facebook разных пользователей в Cassandra. Один из распространенных шаблонов запросов - получение первых N сообщений, созданных данным пользователем.

Таким образом, нам нужно хранить все данные для конкретного пользователя в одном разделе в соответствии с приведенными выше рекомендациями.

Кроме того, использование отметки времени публикации в качестве ключа кластеризации будет полезно для более эффективного извлечения первых N сообщений.

Давайте определим схему таблицы Cassandra для этого варианта использования:

CREATE TABLE posts_facebook ( user_id uuid, post_id timeuuid, content text, PRIMARY KEY (user_id, post_id) ) WITH CLUSTERING ORDER BY (post_id DESC);

Теперь давайте напишем запрос, чтобы найти 20 лучших сообщений для пользователя Anna :

SELECT content FROM posts_facebook WHERE user_id = "Anna_id" LIMIT 20

5.2. Спортивные залы по всей стране

Предположим, что мы храним информацию о различных партнерских спортзалах в разных городах и штатах многих стран и хотим получить спортзалы для данного города.

Кроме того, предположим, что нам нужно вернуть результаты, отсортировав залы по дате открытия.

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

Давайте определим схему таблицы Cassandra для этого примера:

CREATE TABLE gyms_by_city ( country_code text, state text, city text, gym_name text, opening_date timestamp, PRIMARY KEY ( (country_code, state_province, city), (opening_date, gym_name)) WITH CLUSTERING ORDER BY (opening_date ASC, gym_name ASC);

Теперь давайте посмотрим на запрос, который выбирает первые десять тренажерных залов по дате их открытия для города Феникс в американском штате Аризона:

SELECT * FROM gyms_by_city WHERE country_code = "us" AND state = "Arizona" AND city = "Phoenix" LIMIT 10

Затем давайте посмотрим на запрос, который выбирает десять последних открытых спортивных залов в городе Феникс в американском штате Аризона:

SELECT * FROM gyms_by_city WHERE country_code = "us" and state = "Arizona" and city = "Phoenix" ORDER BY opening_date DESC LIMIT 10

Примечание. Поскольку порядок сортировки последнего запроса противоположен порядку сортировки, определенному во время создания таблицы, запрос будет выполняться медленнее, поскольку Cassandra сначала извлечет данные, а затем сортирует их в памяти.

5.3. Клиенты и продукты электронной коммерции

Допустим, у нас есть магазин электронной коммерции, и мы храним информацию о клиентах и продуктах в Cassandra. Давайте посмотрим на некоторые из распространенных шаблонов запросов для этого варианта использования:

  1. Получить клиентов информацию
  2. Получить информацию о продукте
  3. Получите всех клиентов, которым нравится данный продукт
  4. Получите все продукты, которые нравятся данному клиенту

Мы начнем с использования отдельных таблиц для хранения информации о клиенте и продукте . Однако нам нужно ввести изрядную денормализацию для поддержки третьего и четвертого запросов, показанных выше.

We will create two more tables to achieve this – “Customer_by_Product” and “Product_by_Customer“.

Let's look at the Cassandra table schema for this example:

CREATE TABLE Customer ( cust_id text, first_name text, last_name text, registered_on timestamp, PRIMARY KEY (cust_id)); CREATE TABLE Product ( prdt_id text, title text, PRIMARY KEY (prdt_id)); CREATE TABLE Customer_By_Liked_Product ( liked_prdt_id text, liked_on timestamp, title text, cust_id text, first_name text, last_name text, PRIMARY KEY (prdt_id, liked_on)); CREATE TABLE Product_Liked_By_Customer ( cust_id text, first_name text, last_name text, liked_prdt_id text, liked_on timestamp, title text, PRIMARY KEY (cust_id, liked_on));

Note: To support both the queries, recently-liked products by a given customer and customers who recently liked a given product, we have used the “liked_on” column as a clustering key.

Let's look at the query to find the ten Customers who most recently liked the product “Pepsi“:

SELECT * FROM Customer_By_Liked_Product WHERE title = "Pepsi" LIMIT 10

And let's see the query that finds the recently-liked products (up to ten) by a customer named “Anna“:

SELECT * FROM Product_Liked_By_Customer WHERE first_name = "Anna" LIMIT 10

6. Inefficient Query Patterns

Due to the way that Cassandra stores data, some query patterns are not at all efficient, including the following:

  • Получение данных из нескольких разделов - для этого потребуется, чтобы координатор извлек данные из нескольких узлов, временно сохранил их в куче, а затем агрегировал данные перед возвратом результатов пользователю.
  • Запросы на основе соединений - из-за своей распределенной природы Cassandra не поддерживает объединения таблиц в запросах так же, как это делает реляционная база данных, и в результате запросы с объединениями будут медленнее, а также могут привести к проблемам с несогласованностью и доступностью.

7. Заключение

В этом руководстве мы рассмотрели несколько лучших практик подхода к моделированию данных в Cassandra.

Понимание основных концепций и заблаговременное определение шаблонов запросов необходимо для разработки правильной модели данных, обеспечивающей максимальную производительность кластера Cassandra.