Делаем очередь поверх Кассандры
-
Upload
dotnetconf -
Category
Software
-
view
188 -
download
4
Transcript of Делаем очередь поверх Кассандры
![Page 1: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/1.jpg)
Делаем очередь поверх
Кассандры
Максим Кирюшкин
telecan.ru
12-я конференция .NET разработчиков
15 мая 2016
dotnetconf.ru
![Page 2: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/2.jpg)
2
Постановка задачи
LPWAN
low-power wide-area network
![Page 3: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/3.jpg)
3
Постановка задачи
• Множество источников сообщений
• Многоступенчатая обработка в реальном
времени
• Длительное хранение
• Выдача данных по запросу
• Подписка сторонних клиентов на события
• Высокая надёжность
![Page 4: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/4.jpg)
4
Варианты решения
Очередь:
• RabbitMq
• ActiveMQ Apollo
• Kafka
Хранение:
• SQL
• NoSQL
![Page 5: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/5.jpg)
5
Зачем искать альтернативы?
• Очереди удаляют сообщения после
обработки
• Гибкие правила обработки – сложно
• Повторная обработка => повторное
добавление в очередь
• Требуется очередь + хранение – иметь
две системы накладно
• Лишние операции копирования
![Page 6: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/6.jpg)
6
Несколько слов про Кассандру
RowKey: { SuperColumnKey: { ColumKey: Value } } Децентрализованная база (модель BigTable) с настраиваемой целостностью для чтения и записи.
![Page 7: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/7.jpg)
7
Общая идея очереди в Кассандре
• Wide rows
• Обработка в один или несколько потоков
• Помечаем обрабатываемые сообщения
• Результат в той же или отдельной таблице
![Page 8: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/8.jpg)
8
Очереди в Кассандре – антипаттерн
• Cassandra создана для хранения
• Выборка с условием не предусмотрена
• Удаление – сложная задача для
распределённого хранилища
• Нет системы подписки на события
(временно)
![Page 9: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/9.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/10.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/11.jpg)
11
Общая идея очереди в Кассандре
• Wide rows
• Обработка в один или несколько потоков
• Помечаем обрабатываемые сообщения
• Результат в той же или отдельной таблице
![Page 12: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/12.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/13.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/14.jpg)
14
Наполнение с переменной нагрузкой
curS := ТекущаяСекундаДня( ) или 0
nextS := СекундаПерехода( )
ЦИКЛ добавления сообщений
msg := СформироватьСообщение( )
ЕСЛИ сработал таймер ТОГДА
nextS := СекундаПерехода( )
ЕСЛИ ТекущееВремя( ) >= nextS ТОГДА
curS := nextS
ЗаписатьСообщение(msg, curS)
![Page 15: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/15.jpg)
15
Наполнение с переменной нагрузкой
ЦИКЛ проверки
curBlock := НаполняемыйБлок( )
cnt := КоличествоЗаписей(curBlock)
ЕСЛИ cnt > N ТОГДА
nextS := ТекущееВремя( ) + K
ЗадатьСекундуПерехода(nextS)
УснутьНа(Z) // Z <= K
![Page 16: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/16.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/17.jpg)
17
Наполнение с переменной нагрузкой
![Page 18: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/18.jpg)
18
Обработка сообщений
Однопоточная:
• Любой язык
выборка –> обработка –> сохранение
Многопоточная:
• Hadoop (MapReduce)
• Apache Spark
• Другое решение
![Page 19: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/19.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/20.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/21.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/22.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/23.jpg)
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: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/24.jpg)
24
Многопоточная обработка
Hadoop, Apache Spark:
• Отлично подходят для Big Data Analytics
• Вся обработка через запуск обработчика на одно или группу сообщений
• Возврат в очередь, смена последовательности, отложенная обработка – затруднены
• Много копирований в процессе разделения и передачи сообщений
![Page 25: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/25.jpg)
25
Многопоточная обработка
• Простой вариант – сколько угодно потоков, читаем несколько записей вперёд, ставим флаг обработки, обрабатываем, ставим флаг готовности
• Сложный вариант – потоки договариваются между собой, кто какие записи берёт; разбивка по миллисекундам
• Сложный вариант улучшенный – очередь изначально разбивается на уровне ключа, потоки оповещают друг друга о вхождении в работу
![Page 26: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/26.jpg)
26
Оповещение о событиях
• Триггеры
• CDC (Change Data Capture)
• Внешний источник оповещений
CREATE TRIGGER IF NOT EXISTS trigger_name ON table_name USING 'java_class';
![Page 27: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/27.jpg)
27
Когда Кассандра не подходит
• Низкая нагрузка и малое количество узлов
системы
• Сохранение сообщений не требуется
• Необходима гибкая подписка и система
оповещения
• Привычность решения важнее
производительности и отказоустойчивости
![Page 28: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/28.jpg)
28
Когда решение имеет смысл
• Очень высокая нагрузка
• Децентрализованная распределённая
среда
• Сообщения сохраняются после обработки
• Необходима повторная обработка
сообщений
• Сложная зависимая обработка (например,
цепочки сообщений)
![Page 29: Делаем очередь поверх Кассандры](https://reader031.fdocument.pub/reader031/viewer/2022021321/58d11d771a28ab2a738b4e79/html5/thumbnails/29.jpg)
29
Спасибо за внимание
Максим Кирюшкин
telecan.ru