apache cassandra. Ещё одно nosql хранилище (Владимир Климонтович)
DESCRIPTION
TRANSCRIPT
Apache Cassandra
Еще одно NoSQL хранилище
О чем будет идти речь?
• Пару слов про NoSQL• Amazon Dynamo• Google Big Table• Cassandra снаружи• Cassandra кассандра изнутри• Наш опыт использования
NoSQL - WTF?
• Казалось бы, причем тут ЛужковSQL?• Абсолютно не причем! SQL – просто язык
запросов• Под “SQL” понимают MySQL/InnoDB, MSSQL и
аналоги (row oriented, b-tree индексы).• NoSQL == No MySQL• Некоторые из NoSQL хранилищ
предоставляют SQL-синтаксис. Например, Apache Hive
CAP-теорема
• Consistency: в один момент времени, все клиенты видят один и тот же набор данных
• Availability: на каждый запрос будет дан ответ (включая сообщение об ошибке)
• Partition tolerance: система продолжает работать при нарушении связи между любыми двумя узлами
• Можно выбрать только два!
NoSQL хранилища – тысячи их!
• MongoDB тот же MySQL, только в профиль. • Apache Hadoop: offline, MapReduce• Google BigTable family: Hbase• Amazon Dynamo: Riak• Google BigTable + Amazon Dynamo = Apache
Cassandra
Dynamo
Amazon Dynamo
• Описана в статье 2007-ого года• Две операции: get(key), put(key, value)• Область использования в Amazon: session
management, shopping cart, etc• Полная распределенность• Отсутствует master node: клиент общается
сразу со всеми серверами в кластере• Ближайший родственник – DHT в BitTorrent
Token Ring
T1
T2
T3
T4
[T4,∞) [T1, T2)
[T2,T3)[T3,T4)
Replication
T1
T2
T3
T4
[T4,∞) [T1, T2)
[T2,T3)[T3,T4)
Запись• Клиент не знает ничего о топологии кластера• Команда на запись отправляется на
произвольный сервер, который становится координатором данной операции
• Координатор записывает данные на нужные сервера
• Клиент выбирает критерий успешности записи
• Если одна из реплик недоступна, запись будет завершена позже
Чтение
• Команда на чтение оправляется произвольному серверу в кластере
• Сервер знает опрашивает нужные реплики• Критерий успешности чтений (количество
живых реплик) настраивается клиентом
BigTable
BigTableKey Column1 column2 column3 column442 1666 29000 312 4
• У каждой строки может быть индивидуальный набор колонок
• Схема данных отсутствует
Пример схемы данных
• Будем хранить список друзей в социальной сети• Ключ – имя пользователя• Колонка – тоже имя пользователя!• Значение: 1/2/3 в зависимости от взаимности дружбы• f(key, column_name) → column_value – более удобное
представление модели данных• SELECT WHERE key >= start AND key <= end AND name<=maxColumn
AND name<minColumn
Вова Дима Лёня
Вова 3 2Дима 3Лёня 1
Хранение данных
Master
Коорд
инация
Координация
Координация
Чтен
ие/З
апис
ь да
нны
х
Откуда читать? Куда писать?
Tablet servers
Данные внутри tablet server’а
• Memtable – данные, которые были добавлены недавно
• Memtable дублируется commit log’ом на диске
• SSTable – неизменяемая структура данных на диске с O(1) временем доступа к ключу
• Bloomfilter для каждой SSTable• SSTable compaction – переодический merge
маленьких SSTable
Тандем BigTable и Dynamo
Что взяли из Dynamo• Token ring• Алгоритм записи/чтения
T1
T2
T3
T4
[T4,∞) [T1, T2)
[T2,T3)[T3,T4)
Что взяли из BigTable?
• Модель данных: key/column• Локальную структуру данных на серверах• Memtable/commit log – временное хранилище• SSTable/Bloomfilter – постоянное хранилище• SSTable compaction• Вместо put/get доступны сложные запросы: SELECT
WHERE key>=start AND key <= end AND columnName >= c1 AND columnName <= c2
• Индексы!
Терминология Cassandra
• Cluster. Глобальные настройки: тип ключей, partitioning (ordered, md5), размер кэша, топология кластера
• Keyspace. Аналог в MySQL: база данных. Настройки уровня keyspace: replication factor
• Column family. Аналог в MySQL: таблица. размер кэша, индексы
• Super columns.
Super column
• Еще один уровень вложенностиSuper columns Friends Subscribers
Columns Вова Дима Вова Дима
Вова *
Дима *
Операции
• mutation(key, column, value)• get(key, column)• multi_get([k1, k2,…], column)• get_slice(key, column_predicate).
column_predicate: набор колонок или интервал• get_range_slices(start_key, end_key,
column_predicate)• multi_get_slice • Counters: add/remove(key, column)
Запись
• Команда идет на произвольный сервер в кластере. Сервер находит нужные реплики (ReplicationStrategy)
• Сервер сохраняет данные локально (Hinted handoff)• Критерий успешности записи определяет клиент
согласно настройки ConsistencyLevel
Уровень Что значит
ANY Начальный сервер (Hinted Handoff)
ONE Хотя бы одна реплика
QUORUM (ReplicationFactor/2) + 1
ALL Все реплики
Репликация: один датацентр
0
25
50
75
[75,∞) [0, 25)
[25,50)[50,75)
Репликация: два датацентра
1
26
51
76 0
25
50
75
42
Запись: внутренности
• Memtable: хранилище новых записей. Настраиваемый flush-критерий (по таймауту, по размеру)
• Commit-log: дублирует memtable на случай падения сервера
• Memtable flush -> SSTable• SSTable: data + index + bloomfilter• SSTable compaction – борьба с
фрагметнацией
Чтение• Команду на чтение обрабатывает произвольный сервер• Сервер определяет ближайшую реплику на основе
настройки snitch: Simple, Topology, Dynamic• Клиент определяет критерий успешности чтения• Read repair (optional): убедится, что все реплики
содержат свежие данные
Уровень Что значит
ONE Хотя бы одна реплика
QUORUM (ReplicationFactor/2) + 1
ALL Все реплики
Конфликты
• Каждое значение в колонке имеет timstamp• Timestamp проставляется клиентом как
текущее время• Можно переопределить timestamp на
любое 64-х битное число• Клиент получает всегда последний
timestamp
Кеширование запросов
• Key cache: кеширование позиции ключей внутри SSTable
• Row cache: кеширование ключей и их значений в памяти
• Принцип кеширования: LIFO. Настраивается для каждой column family отдельно
• Но! Кассандра использует mmap для чтения файлов• Настройки кеширования использовать не
рекомендуется. Лучше полагаться на кеширование файловой системы
Индексы
• Secondary Indexes: на columns, но не на super columns!• При полностью распределенной архитектуре сложно
реализовать индексы• Чтобы найти значение по индексу, нужно опросить
все сервера• Ограничение реализации: можно делать запросы
только по строгому сравнению (SELECT … WHERE column>value – не поддерживается)
• Индексы сильно замедляют вставку данных• Итого: индексы довольно бесполезная фича
Масштабирование: как добавить сервера в кластер?
• У каждого сервера есть операция move token. Можно переназначит token у любого сервера
• Топология кластера измениться, миграция данных будет происходить в фоне
• Пока миграция не закончена, сервер будет отвечать за старый кусок данных
• Аналогично будет отработана ситуация добавления нового сервера в token ring
Проще всего масштабироваться в 2 раза
0
25
50
75
0
37
50
75
87 12
6225
Преимущества
• Быстрый write, особенно когда не нужна consistency
• Легкость в администрировании. Один daemon с одним конфигурационным файлом
• В HBase: четыре daemon’а на каждый сервер
Недостатки
• Плохо реализован range scan: кассандра не умеет передавать данные поточно.
• Слишком много настроек вынесено на cluster-level: вид и стратегия хранения ключей, и т.д.
• Compaction существенно замедляет запросы
• Протокол общения между нодами: Thrift
Наш опыт
• Храним события в online рекламы: показы/клики/конверсии• Типичный клиент: 1 миллиард событий в месяц, 100
миллионов уникальных пользователей (ключей)• Ключ: ID пользователя. Имя колонки: ID события• Вопрос N1: сколько уникальных пользователей было в каждом
городе• Вопрос N2: сколько уникальных пользователей видели баннер
X, но не видели баннер Y; какое распределение таких пользователей по городам
• Вопрос N3: на какие объявления нажимал конкретный пользователь
User id 2321312 36465930 123213232 9879879
78969813467 ……
21312312378 ….. …. ….
Плюсы и минусы
+ Быстрая запись, группировка по пользователям во время записи+ Нет проблемы дубликации данных- Плохо реализованный range scan- Нельзя выполнять логику прямо на серверах
Решение проблем
• Аггрегация данных на сервере. Опции: Hadoop/MapReduce, кастомное решение
• Минусы Hadoop: операционные расходы, возможность использовать лишь один column family как источник данных
• Свое решение: кастомный демон на каждом сервере (аналог map), финальная аггрегация на клиенте.
Наши цифры на тестовых данных
• Кластер: 3 x (m1.large EC2: 7.5Gb RAM, 2CPU)• Скорость записи: 12 тысяч событий в
секунду• Скорость чтения: 9 тысяч событий в секунду• Объем данных: 600Gb за 1.5 месяца, 1.5
миллиарда событий (значений колонок), 100 миллионов ключей