Top Banner
Делаем очередь поверх Кассандры Максим Кирюшкин telecan.ru 12-я конференция .NET разработчиков 15 мая 2016 dotnetconf.ru
29

Делаем очередь поверх Кассандры

Mar 21, 2017

Download

Software

dotnetconf
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Делаем очередь поверх Кассандры

Делаем очередь поверх

Кассандры

Максим Кирюшкин

telecan.ru

12-я конференция .NET разработчиков

15 мая 2016

dotnetconf.ru

Page 2: Делаем очередь поверх Кассандры

2

Постановка задачи

LPWAN

low-power wide-area network

Page 3: Делаем очередь поверх Кассандры

3

Постановка задачи

• Множество источников сообщений

• Многоступенчатая обработка в реальном

времени

• Длительное хранение

• Выдача данных по запросу

• Подписка сторонних клиентов на события

• Высокая надёжность

Page 4: Делаем очередь поверх Кассандры

4

Варианты решения

Очередь:

• RabbitMq

• ActiveMQ Apollo

• Kafka

Хранение:

• SQL

• NoSQL

Page 5: Делаем очередь поверх Кассандры

5

Зачем искать альтернативы?

• Очереди удаляют сообщения после

обработки

• Гибкие правила обработки – сложно

• Повторная обработка => повторное

добавление в очередь

• Требуется очередь + хранение – иметь

две системы накладно

• Лишние операции копирования

Page 6: Делаем очередь поверх Кассандры

6

Несколько слов про Кассандру

RowKey: { SuperColumnKey: { ColumKey: Value } } Децентрализованная база (модель BigTable) с настраиваемой целостностью для чтения и записи.

Page 7: Делаем очередь поверх Кассандры

7

Общая идея очереди в Кассандре

• Wide rows

• Обработка в один или несколько потоков

• Помечаем обрабатываемые сообщения

• Результат в той же или отдельной таблице

Page 8: Делаем очередь поверх Кассандры

8

Очереди в Кассандре – антипаттерн

• Cassandra создана для хранения

• Выборка с условием не предусмотрена

• Удаление – сложная задача для

распределённого хранилища

• Нет системы подписки на события

(временно)

Page 9: Делаем очередь поверх Кассандры

9

Решение проблемы с удалением

Использовать отложенное удаление (TTL)

INSERT INTO tab (rkey, clkey, val) VALUES ('rawhash', 'cluster', 42) USING TTL 86400;

UPDATE tab USING TTL 86400 SET val=42 WHERE rkey='some' AND clkey='any';

Page 10: Делаем очередь поверх Кассандры

10

Полезная вещь: транзакции

INSERT INTO rawdata (row_date, moment, handled, message) VALUES ('2016-05-15', '2016-05-15 11:23:00', 0, 'message') IF NOT EXISTS;

UPDATE rawdata SET handled=2 WHERE row_date='2016-05-15' AND moment='2016-05-15 11:23:00' IF handled=1;

[applied] true [applied] | raw_date | moment | handled | message false | 2016-05-15 | '2016-05-15 11:23:00' | 0 | message

Page 11: Делаем очередь поверх Кассандры

11

Общая идея очереди в Кассандре

• Wide rows

• Обработка в один или несколько потоков

• Помечаем обрабатываемые сообщения

• Результат в той же или отдельной таблице

Page 12: Делаем очередь поверх Кассандры

12

Наполнение с переменной нагрузкой

CREATE TABLE IF NOT EXISTS rawdata ( row_date date, -- дата, определяющая строку, yyyy-mm-dd moment timeUUID, -- момент поступления в систему, идентификатор handled tinyint, -- 0 - unhandled, 1 - handling, 2 - handled, 3... – error message blob, -- данные пакета PRIMARY KEY (row_date, moment) ) WITH CLUSTERING ORDER BY (moment ASC);

Page 13: Делаем очередь поверх Кассандры

13

Наполнение с переменной нагрузкой CREATE TABLE IF NOT EXISTS rawdata ( row_date date, -- дата, определяющая строку, yyyy-mm-dd row_sec int, -- начальная секунда строки, [0..86400) moment timeUUID, -- момент поступления в систему, идентификатор handled tinyint, -- 0 - unhandled, 1 - handling, 2 - handled, 3... - error message blob, -- данные пакета PRIMARY KEY ((row_date, row_sec), moment) ) WITH CLUSTERING ORDER BY (moment ASC);

CREATE TABLE IF NOT EXISTS rawdata_meta_rows ( row_date date, -- дата строки row_sec int, -- начальная секунда строки, [0..86400) PRIMARY KEY ((row_date), row_sec) ) WITH CLUSTERING ORDER BY (row_sec DESC);

CREATE TABLE IF NOT EXISTS rawdata_meta ( mkey text, -- варианты: csec (current second), nsec (next second) msubkey text, -- ключ ячейки в строке (csec: yyyy-mm-dd) mval text, -- значение PRIMARY KEY ((mkey), msubkey) );

хранит все ключи партиций (строк) из rawdata

кэш значений переменных

Page 14: Делаем очередь поверх Кассандры

14

Наполнение с переменной нагрузкой

curS := ТекущаяСекундаДня( ) или 0

nextS := СекундаПерехода( )

ЦИКЛ добавления сообщений

msg := СформироватьСообщение( )

ЕСЛИ сработал таймер ТОГДА

nextS := СекундаПерехода( )

ЕСЛИ ТекущееВремя( ) >= nextS ТОГДА

curS := nextS

ЗаписатьСообщение(msg, curS)

Page 15: Делаем очередь поверх Кассандры

15

Наполнение с переменной нагрузкой

ЦИКЛ проверки

curBlock := НаполняемыйБлок( )

cnt := КоличествоЗаписей(curBlock)

ЕСЛИ cnt > N ТОГДА

nextS := ТекущееВремя( ) + K

ЗадатьСекундуПерехода(nextS)

УснутьНа(Z) // Z <= K

Page 16: Делаем очередь поверх Кассандры

16

Наполнение с переменной нагрузкой

Если не был задан переход nextS

Если был задан переход и посчитали новый

INSERT INTO rawdata_meta (mkey, msubkey, mval) VALUES ('nsec', '2016-05-15', nextS) IF NOT EXISTS USING TTL 86400;

UPDATE rawdata_meta USING TTL 86400 SET mval=nextS WHERE mkey='nsec' AND msubkey='2016-05-15‘ IF mval=oldNextS;

Page 17: Делаем очередь поверх Кассандры

17

Наполнение с переменной нагрузкой

Page 18: Делаем очередь поверх Кассандры

18

Обработка сообщений

Однопоточная:

• Любой язык

выборка –> обработка –> сохранение

Многопоточная:

• Hadoop (MapReduce)

• Apache Spark

• Другое решение

Page 19: Делаем очередь поверх Кассандры

19

Однопоточная обработка: выборка

1. Определение ключа партиции и кластера по rawdata_meta_rows

2. Выборка из конкретной строки с условием и сортировкой

3. Пагинация (LIMIT, OFFSET)

CREATE TABLE IF NOT EXISTS rawdata ( row_date date, -- дата, определяющая строку, yyyy-mm-dd row_sec int, -- начальная секунда строки, [0..86400) moment timeUUID, -- момент поступления в систему, идентификатор handled tinyint, -- 0 - unhandled, 1 - handling, 2 - handled, 3... - error message blob, -- данные пакета PRIMARY KEY ((row_date, row_sec), moment) ) WITH CLUSTERING ORDER BY (moment ASC);

Page 20: Делаем очередь поверх Кассандры

20

Неочевидные проблемы выборки

Сложности прямых запросов:

• Сортировка доступна только по ключу

• Нет понятия OFFSET

• Нельзя просто взять и применить условия

SELECT * FROM rawdata WHERE row_date='2016-05-10‘ AND row_sec=0 AND handled=0;

No supported secondary index found for the non primary key columns restrictions

Page 21: Делаем очередь поверх Кассандры

21

Неочевидные проблемы выборки

Можно применить индексы, но индекс по

флагу не эффективен

Each value in the index becomes a single row in the index, resulting in a huge row for all the false values, for example. Indexing a multitude of indexed columns having foo = true and foo = false is not useful.

Page 22: Делаем очередь поверх Кассандры

22

Неочевидные проблемы выборки

Есть в Кассандре materialized views, но их

функционал пока слишком слаб: нет условий

выборки, сортировки и т.д.

CREATE MATERIALIZED VIEW rawdata_unhandled AS SELECT row_date, row_sec, handled, moment, message FROM rawdata WHERE row_date IS NOT NULL AND row_sec IS NOT NULL AND moment IS NOT NULL AND handled IS NOT NULL PRIMARY KEY ((row_date, row_sec), handled, moment);

Page 23: Делаем очередь поверх Кассандры

23

Решение проблем с выборкой

Внешнее приложение должно взять полный контроль на себя и точно знать, что запрашивать

SELECT row_date, row_sec, moment, handled FROM rawdata WHERE row_date='2016-05-15' AND row_sec=0 LIMIT 100;

row_date | row_sec | moment | handled ... 2016-05-15 | 0 | d6686343-1804-11e6-bebe-87c17418206b | 0

SELECT row_date, row_sec, moment, handled FROM rawdata WHERE row_date='2016-05-15' AND row_sec=0 AND moment > d6686343-1804-11e6-bebe-87c17418206b LIMIT 100;

Page 24: Делаем очередь поверх Кассандры

24

Многопоточная обработка

Hadoop, Apache Spark:

• Отлично подходят для Big Data Analytics

• Вся обработка через запуск обработчика на одно или группу сообщений

• Возврат в очередь, смена последовательности, отложенная обработка – затруднены

• Много копирований в процессе разделения и передачи сообщений

Page 25: Делаем очередь поверх Кассандры

25

Многопоточная обработка

• Простой вариант – сколько угодно потоков, читаем несколько записей вперёд, ставим флаг обработки, обрабатываем, ставим флаг готовности

• Сложный вариант – потоки договариваются между собой, кто какие записи берёт; разбивка по миллисекундам

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

Page 26: Делаем очередь поверх Кассандры

26

Оповещение о событиях

• Триггеры

• CDC (Change Data Capture)

• Внешний источник оповещений

CREATE TRIGGER IF NOT EXISTS trigger_name ON table_name USING 'java_class';

Page 27: Делаем очередь поверх Кассандры

27

Когда Кассандра не подходит

• Низкая нагрузка и малое количество узлов

системы

• Сохранение сообщений не требуется

• Необходима гибкая подписка и система

оповещения

• Привычность решения важнее

производительности и отказоустойчивости

Page 28: Делаем очередь поверх Кассандры

28

Когда решение имеет смысл

• Очень высокая нагрузка

• Децентрализованная распределённая

среда

• Сообщения сохраняются после обработки

• Необходима повторная обработка

сообщений

• Сложная зависимая обработка (например,

цепочки сообщений)

Page 29: Делаем очередь поверх Кассандры

29

Спасибо за внимание

Максим Кирюшкин

[email protected]

telecan.ru