Алексей Чумаков
achumakov@exadel.com
Skype: alexey.chumakov
Вкратце
• Немного о NoSQL вцелом
• Что такое Apache Cassandra и для чего она может
понадобиться
• Как она устроена изнутри
• Несколько примеров
• Нюансы...
• Администрирование
НЕМНОГО О NOSQL…
NoSQL. Зачем?

Join, group by, count начинают работать медленно
на больших объемах данных

BigData – данных много (не помещаются на один
сервер) и они все нужны

Необходима репликация данных между
датацентрами и их постоянная доступность
(availability)

Partitioning/sharding вручную не всегда удобен

А еще хотим гибкую схему данных...
NoSQL. Зачем?
Pull on Demand vs Push on Change
CAP-теорема
http://blog.nahurst.com/visual-guide-to-nosql-systems
ЧТО ТАКОЕ
APACHE CASSANDRA?
История
Организация
кластера
(consistent hashing),
hinted handoff, read
repair
Структура
данных
(SSTables),
timestamps
?
Распределенная и горизонтально масштабируемая
http://techblog.netflix.com/2011/11/benchmarking-cassandra-scalability-on.html
Добавление новых нодов
• Скачать и распаковать дистрибутив
• Настроить IP
• Указать seed nodes
• Запустить 
Что-то еще?
• Децентрализованная (кольцо, нет master node, нет
single point of failure)
• Репликация между нодами и дата-центрами
• Настраиваемая Consistency (Tunable Consistency)
• Низкий уровень вхождения в NoSQL благодаря
CQL (Cassandra Query Language)
• Поддержка Hadoop
И в чем подвох?
• Нет ACID транзакций
• Сложно гарантировать 100% consistency данных
• Нет сложных запросов (никаких like, join, group by)
• Схему данных приходится продумывать исходя из
будущих запросов, а не наоборот
Когда имеет смысл использовать Apache Cassandra?
• Количество операций записи больше, чем чтения
• Данные должны быть постоянно доступны для
чтения и записи, несмотря на потерю N нодов
• Анализ поведения пользователя
• Агрегаторы
• Мониторинг
Когда не нужна C*?
• Данные помещаются в память
• Данные помещаются на одном сервере
• Не предвидится серьезного роста объема данных
• Данные редко модифицируется и возможно
реализовать шардинг
КАК APACHE CASSANDRA
УСТРОЕНА ИЗНУТРИ?
Организация кластера
Запись в любой доступный нод кластера
Hinted Handoff
Read repair
Anti-entropy repair
• Что будет, если Coordinator Node умрет?
• Лучше запускать по расписанию
• bin/nodetool repair
Физическая организация данных
• Нет B-Trees
• Используются отсортированные в памяти таблицы
фиксированного размера (SSTables)
• SSTable последовательно записываются на диск, а
потом объеденяются в отдельном потоке
(compaction)
• При удалении физически ничего не меняется, а
ставится маркер (tombstone)
Физическая организация данных
ЛОГИЧЕСКАЯ СТРУКТУРА
ДАННЫХ
= Map<Key, Map<Column, Value>>
Map<Key, Map<Column, Value>>
При использовании CQL все очень похоже на RDBMS
CREATE TABLE order_events (
order_id ascii,
operation_time timestamp,
operation_type ascii,
waiter ascii,
changed_menu_items list<ascii>,
PRIMARY KEY (order_id, operation_time)
);
Но в действительности все немного не так...
Идемпотентность
• Повторная запись по тому же ключу c теми же
значениями ничего не меняет
• Insert == Update
INSERT INTO NerdMovies (movie, director, main_actor, year)
VALUES ('Serenity', 'Joss Whedon', 'Nathan Fillion', 2005);
UPDATE NerdMovies
SET director = 'Joss Whedon',
main_actor = 'Nathan Fillion',
year = 2005
WHERE movie = 'Serenity';
Распределенные счетчики
• Работают с той же скоростью, что и обычный
update
• Не идемпотентны
UPDATE UserActions
SET total = total + 2
WHERE user = B70DE1D0-9908-4AE3-BE34-5573E5B09F14 AND action = 'click';
НЕСКОЛЬКО ПРИМЕРОВ...
Нагрузочное тестирование Black Box
Данные для каждой транзакции
CREATE TABLE transactions (
transaction_id ascii,
transaction_data map<text, text>,
PRIMARY KEY (transaction_id)
);
Данные для каждой транзакции
CREATE TABLE transaction_metrics (
transaction_id ascii,
tr_type ascii,
time timestamp,
PRIMARY KEY (transaction_id, tr_type)
);
Статистика
CREATE TABLE transaction_count (
stat_id ascii,
time_string ascii,
ops_count counter,
PRIMARY KEY (detail_key, time_string)
)
А теперь получаем нужный нам промежуток
SELECT time_string, ops_count FROM transaction_count
WHERE stat_id = ‘B_REQ|20140510'
AND time > '2014051003' AND time <= '2014051015'
Что не стоит делать с C*?
• Пытаться создать очередь на ее основе
• Читать перед записью – в большинстве случаев
можно воспользоваться счетчиками или
идемпотентностью
• Писать все в один Wide Row или часто удалять
данные из него
НЮАНСЫ
Очень высокая загрузка CPU
• Слишком большой HEAP
• concurrent_reads/concurrent_writes
• native_transport_max_threads
• rpc_max_threads
Anti Entropy Repair
• nodetool repair
• Осбенно нужен в тех случаях, когда кластер
оказался перегружен
Amazon EBS volumes
Слишком Wide Rows
• Запись в Wide Row оказалась в 5 раз медленне,
чем в row с разными ключами
• Удаления из Wide Row требуют много памяти во
время compaction
(TombstoneOverwhelmingException)
• Все записи из Wide Row физически находятся на
одном ноде (и его репликах)
Синхронизация времени между нодами
• Время на нодах (даже в AWS) может быть
рассинхронизированно
• Timestamps оказываются неверными
• Данные в итоге тоже
Bugs
Баги есть!
...но правят их быстро
Администрирование
• Nodetool – command-line утилита, в которой есть
все (или почти все) для администрирования
кластера
• DataStax OpsCenter – красивый веб-интерфейс для
администрирования, есть Community Edition
Правильный выбор технологий
VS
Q & A

Алексей Чумаков. Apache Cassandra на реальном проекте