Как стать автором
Обновить

Cassandra для хранения метаданных: успехи и провалы

Время на прочтение31 мин
Количество просмотров20K
Всего голосов 38: ↑37 и ↓1+36
Комментарии16

Комментарии 16

Очень интересная статья! Почему вы её не написали пару лет назад? ))) Почему-то очень мало находил в сети информации именно о возможных затыках работы с C*.
Получается, что C* нельзя в лоб использовать для хранения time-series данных, например значений данных с датчиков? (Я о проблеме Large Partition).
Другими словами структура данных вида:
CREATE TABLE sensor_data (
   device_id uuid, 
   date_time timestamp, 
   data double, 
   PRIMARY KEY (device_id, date_time)
);

является очень и очень неэффективной.

Что можете посоветовать для данного случая, основываясь на вашем опыте?
является очень и очень неэффективной.

Так используйте композитный Partition Key:
PRIMARY KEY ((device_id, date_time))

В вашем же случае партиционирование идет только по device_id.

Если и этого недостаточно — можно добавить еще какой-нибудь искусственный ключ.
Но надо не забывать что в этом случае запросы должны будут включать и device_id и date_time. Либо делать запросы с полным сканированием.

Можно использовать не timestamp, а, например, номер дня года. Или номер дня с начала эпохи :) Тогда можно получить данные за нужный период запросом по первичному ключу.
Композитный Partition Key не позволяет делать выборки вида:
SELECT * FROM sensor_data WHERE device_id=? and date_time > ? and date_time < ?

а это единственное, что мне нужно делать с этими данными
Ну сделай что-нибудь вроде PRIMARY KEY ((device_id, day_start_timestamp), date_time) например. Где day_start_timestamp — date_time округленная до начала дня. Тогда можно запрашивать данные по конкретным дням без проблем и каждый новый день для каждого девайса будет отдельной партицией. Чтобы получить за несколько дней — нужно несколько запросов, да. Но они быстрые.
Ну так я уже и сделал. Думал, может есть всё-таки более элегантное решение…
Спасибо!
Кстати, после какого размера партиции начинается проседание? с точностью до порядка, можете подсказать. 1K, 10K, 100K, 500K?
Думал, может есть всё-таки более элегантное решение…

На кластерных ключах его не может быть в принципе, т.к. он определяет на каком хосте в кластере лежат данные. А если они размазаны по более чем 1 хосту, то выборка уже не будет быстрой и это нарушает принципы Кассандры. Для range-выборок в идеале нужно юзать вторичные ключи, но у них свои проблемы. SASI-индексы решили многие из их проблем, но у них свои косяки (см ниже).

Кстати, после какого размера партиции начинается проседание? с точностью до порядка, можете подсказать. 1K, 10K, 100K, 500K?

It depends :) Посмотри вот эту презентацию: www.slideshare.net/DataStax/myths-of-big-partitions-robert-stupp-datastax-cassandra-summit-2016

Общий принцип — на каждые Х GB партиции нужно Y MB кеша в хипе.
Спасибо большое! То что надо!

Зависит от того какие запросы на чтение должны поддерживаться. Зачастую time-series данные имеет смысл разбивать по периодам, например, по дням, неделям и тому подобное, в зависимости от того как много данных добавляется в этот период и как для пользователя имеет смысл отображать эти данные. Этот подход иногда называют бакетированием (от bucket). Для вашего примера можно использовать составной partition key из device_id и, например, даты.


CREATE TABLE sensor_data (
   device_id uuid,
   data_date date
   date_time timestamp, 
   data double, 
   PRIMARY KEY ((device_id, date), date_time)
);

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


При этом понадобится вторая таблица для хранения самих дат, чтобы была возможность по device_id найти даты.


CREATE TABLE sensor_dates (
   device_id uuid,
   data_date date
   PRIMARY KEY (device_id, date)
);

При добавлении значение делаем два Insert в обе таблицы.
При чтении есть варианты:


  • Когда диапазон не задан и нужно получить все данные, то запрашиваем все даты по device_id из sensor_dates, затем по каждой дате запрашиваем сами значение из sensor_data. Это может быть долго, если дат много, так как придется сделать много запросов.
  • Когда указан диапазон, то даты можно получить из указанного диапазона и опять же запросить данные по датам из sensor_data.

Этот подход не всегда работает, например если данных для одного устройства очень много и есть требование в реальном времени получать все эти данные, например для подсчета статистики. Но тут уж как ни крути будет медленно.


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

Не встречал такую несколько лет назад. Сейчас посмотрю.
ScyllaDB — новая производительная NoSQL, совместимая с Apache Cassandra, от создателей Linux KVM

Если я правильно понимаю — я могу её использовать без изменений вместо C*? Просто вот так взять поменять адреса подключения и всё?
И там не будет проблем с Large Partiton? Или все перечисленные в статье недостатки останутся, только пошустрее будет? (если верить разработчикам )))
Как я понял, внутренняя структура хранения данных не поменялась, значит все проблемы в принципе остались. Или я не прав?
Да, это по сути просто переписанная на Си Кассандра 2.х
Тоже нахватали багов с сабжем — причем многие из них не фиксят годами. Вот, например, зарепортил баг о том что repair ломает SASI-индексы: issues.apache.org/jira/browse/CASSANDRA-13403
Почти полтора года прошло…

Но во многом — крайне удобная БД и да, практически без альтернатив. Разве что Aerospike подошел бы, но только в энтерпрайз версии — в опенсурсную даже Tombstone не завезли…
На Aerospike я тоже смотрел и даже пробовал, но это же БД для кеширования. Она все данные при старте в память грузит (по крайней мере так было 4 года назад) — не для этого решения.
Она все данные при старте в память грузит (по крайней мере так было 4 года назад) — не для этого решения.

Нет. Она вполне умеет персистить на диск. Но из-за отсутствия Tombstone в opensource-версии все удаленные данные приезжают обратно после перезапуска ноды. Единственный выход этого избежать — удалять всё с ноды и давать ей отреплицироваться после запуска. Но это по понятным причинам занимает много времени. Если твой юзкейс только добавление — то вполне может прокатить.
Как вариант можно попробовать Яндексовский КликХаус — он немного сложнее в использовании т.к. партиционирование нужно делать вручную, но скорость у него просто космос — быстрее ничего нет по-моему. На моих бенчмарках он сканировал таблицы со скоростью до миллиарда записей в секунду всего на нескольких нодах.

И еще Apache Kudu сейчас дошла до продакшена — сравнима с кликхаусом. Индексов там также пока нет (хотя планируются), но скорость выборки и без них огромная.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий