Лучшая модель данных Cassandra для ведения ограниченных списков на пользователя - PullRequest
1 голос
/ 06 марта 2020

У меня есть потоки Kafka, содержащие взаимодействия пользователей с веб-сайтом, поэтому каждое событие имеет метку времени и информацию о событии. Для каждого пользователя я хочу сохранить последние K событий в Cassandra (например, 100 событий).

На нашем веб-сайте постоянно работают боты / активные пользователи, поэтому мы хотим ограничить события, просто рассматривая «обычных» пользователей. .

В настоящее время у меня есть текущая модель данных в Кассандре:

 user_id, event_type, timestamp, event_blob 

, где

 <user_id, event_type> = partition key,   timestamp = clustering key

Пока мы пишем новую запись в Кассандре, как только новая событие происходит, а затем мы go и очищаем «более тяжелые» разделы (то есть количество событий> 100). Это не происходит в реальном времени, и пока мы не убираем тяжелые разделы, у нас иногда возникают плохие задержки при чтении.

Есть ли у вас какие-либо предложения по улучшению дизайна таблицы для такого случая? Есть ли способ заставить Cassandra хранить только максимум K элементов для разделения и истекать старые FIFO? Или есть лучший дизайн стола, который я могу выбрать?

Ответы [ 2 ]

1 голос
/ 11 марта 2020

Есть ли у вас какие-либо предложения по улучшению дизайна таблицы для такого случая?

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

  • Значение TTL по умолчанию, установленное для таблицы.
  • Кластеризация по временному компоненту в порядке убывания.
  • Настройка запроса на использование диапазона временной метки, никогда не запрашивая данные за TTL.

TTL:

позже мы go и очистим "более тяжелые" разделы

Сколько времени (в среднем) до очистки? Одна вещь, которую я хотел бы сделать, это использовать TTL на этом столе, установленный где-то около максимального количества времени, прежде чем ваша команда обычно должна их очистить.

Ключ кластеризации, Порядок убывания:

Итак, ваше определение PRIMARY KEY выглядит следующим образом:

PRIMARY KEY ((user_id,event_type),timestamp)

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

WITH CLUSTERING ORDER BY (timestamp DESC)

This важно использовать в сочетании с вашим TTL. Здесь ваши надгробия находятся в «нижней части» раздела (при сортировке по timestamp descinding), а последние данные (данные, которые вас интересуют) находятся в «верхней части» раздела.

Range Query:

Наконец, убедитесь, что ваш запрос имеет компонент диапазона в timestamp.

Например: если сегодня 11-е число, а мой TTL составляет 5 дней, я могу запросить данные за последние 4 дня, не возвращая надгробия:

SELECT * FROM events
WHERE user_id = 11111 AND event_type = 'B'
AND timestamp > '2020-03-07 00:00:00';
1 голос
/ 11 марта 2020

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

Реализация FIFO на основе количества (количество строк на раздел) невозможна. Лучший подход для вашего варианта использования - не удалять записи в одной таблице. Используйте Spark, чтобы перенести таблицу в новую временную таблицу и удалить дополнительные записи в процессе миграции. Что-то вроде:

1) Создать новую таблицу

2) Используя Spark, прочитать из исходной таблицы, перенести все необходимые записи (отфильтровать дополнительные записи) и записать в новую временную таблицу.

3) Обрезать оригинальную таблицу. Обратите внимание, что операция усечения не создает надгробия.

4) Переносит все из временной таблицы обратно в исходную таблицу с помощью Spark.

5) Усекает временную таблицу.

Вы можете делать это в окне обслуживания вашего приложения (примерно раз в месяц), пока вы не сможете ограничить чтение с помощью лимита 100 на раздел.

...