Привет, Хабр! Меня зовут Евгений Абрамкин, я руководитель поддержки третьего уровня в направлении омниканальных решений Лиги Цифровой Экономики. Моя команда — последняя «инстанция» во флоу по решению инцидентов. Мы пишем доработки и фиксы, чтобы победить проблему клиента, а также можем предоставить оптимальную конфигурацию для системы, которая передана на эксплуатацию или требует масштабирования. Это может быть кластер Elasticsearch, балансировщики nginx или что поинтереснее — распределенная NoSQL СУБД Apache Cassandra.
В материале я расскажу именно об Apache Cassandra: какие ошибки можно совершить при ее использовании, на что стоит обратить внимание и чем лучше не пренебрегать.
Ошибка 1. Неправильное определение primary key
Одна из наиболее распространенных ошибок, которую можно совершить при работе с базой данных Cassandra, — неправильное определение primary key.
Primary key в Cassandra состоит из двух частей: partition key и clustering key. Первый определяет, как данные будут распределены по узлам кластера, а второй — как они будут упорядочены внутри partition.
Неправильное определение partition key может привести к тому, что данные будут неэффективно распределены по узлам кластера. Это может привести к «перегреву» последних и неравномерному распределению нагрузки.
Кроме того, ошибка в выборе partition key чревата дублированием данных и увеличением объема записываемых.
Если clustering key определить неправильно, данные внутри partition будут неэффективно упорядочены. Например, запросы на чтение данных могут занимать больше времени, чем нужно, из-за необходимости сортировки данных на уровне приложения.
Примеры partition key:
Для таблицы, хранящей данные о пользователях, partition key может быть идентификатором страны, в которой зарегистрирован пользователь. В этом случае данные будут распределены по узлам кластера в соответствии со страной.
Для таблицы, хранящей данные о заказах, partition key может быть идентификатором магазина, в котором был сделан заказ. Тогда данные будут распределены по магазинам.
Примеры clustering key:
Для таблицы, хранящей данные о фильмах, clustering key может быть годом выпуска фильма. Тогда данные внутри partition будут упорядочены соответственно по году выпуска.
Для таблицы, хранящей данные о транзакциях, clustering key может быть временем транзакции. В этом случае данные внутри partition рассортируются по времени транзакции.
При проектировании схемы данных в Cassandra необходимо тщательно выбирать primary key, учитывая особенности приложения, которое будет использовать базу данных, а также ожидаемый объем данных и нагрузку на кластер (последнюю можно выполнить штатным средствами через этот инструмент).
Ошибка 2. Использование слишком больших или слишком маленьких partition
Использование слишком больших или слишком маленьких partition — это еще одна распространенная ошибка при работе с базой данных Cassandra.
Partition — это единица распределения данных в Cassandra. Все данные в таблице Cassandra разбиваются на несколько partition, каждая из которых хранится на одном узле кластера. То есть это механизм, который позволяет обеспечить горизонтальное масштабирование базы данных.
Слишком большие partition могут привести к перегрузке узла, на котором они хранятся. Если partition слишком крупный, то запросы на чтение или запись данных могут занимать слишком много времени, потому что нужно обрабатывать большой объем данных. Кроме того, таковые могут вызывать проблемы с балансировкой нагрузки в кластере, поскольку она будет неравномерно распределена между узлами.
Слишком маленькие partition, напротив, могут привести к низкой эффективности использования ресурсов кластера. Когда partition небольшой, в нем может оказаться слишком мало данных. И это может привести к увеличению количества запросов на чтение или запись данных из-за необходимости поиска данных в разных partition.
Кроме того, слишком маленькие partition могут вызывать проблемы с производительностью в случае, если между ними не удается обеспечить правильное распределение нагрузки.
Для того чтобы избежать таких проблем с размером, необходимо тщательно выбирать partition key и учитывать ожидаемый объем данных и нагрузку на кластер. Помимо этого, следует следить за этим аспектом в процессе эксплуатации базы данных. В случае необходимости нужно реорганизовать данные, чтобы обеспечить более эффективное распределение нагрузки.
Ошибка 3. Некорректное определение числа узлов в кластере
Cassandra позволяет горизонтально масштабировать кластер через добавление новых узлов. При этом их оптимальное число зависит от многих факторов, включая объем данных и их доступность, требования к производительности и т. д.
Слишком маленький кластер может привести к низкой производительности и низкой доступности данных. Если в кластере недостаточно узлов, то при сбое одного или нескольких доступность данных может быть серьезно нарушена, что будет чревато потерей данных или недоступностью сервисов.
Слишком большой кластер также может привести к проблемам. Во-первых, он требует больше ресурсов для его поддержки, а значит, будет выше и стоимость эксплуатации. Во-вторых, крупный кластер может привести к проблемам с балансировкой нагрузки и синхронизацией данных между узлами.
Для определения оптимального числа узлов в кластере необходимо учитывать следующие факторы:
Объем данных. Чем больше данных необходимо хранить, тем больше узлов может потребоваться, чтобы обеспечить производительность и доступность данных.
Требования к производительности. Чем выше требования к производительности, тем больше узлов нужно для быстрого доступа к данным.
Требования к доступности данных. Чем выше требования к доступности данных, тем больше понадобится узлов для сохранения надежности и отказоустойчивости кластера.
При определении числа узлов в кластере необходимо учитывать все перечисленные факторы, а еще — проводить тестирование производительности и доступности данных на различных конфигурациях кластера. Только после этого можно определить оптимальное число узлов для конкретной задачи.
Общее правило состоит в том, что число реплик должно быть равно (или быть больше) числу узлов, которые могут одновременно выйти из строя без потери доступности данных.
Например, если в кластере 6 узлов, и мы хотим обеспечить доступность данных в случае отказа до 2 узлов, то необходимо настроить репликацию на 3 узла. Тогда операции можно будет продолжать при отказе 2-х узлов.
При настройке репликации также нужно учитывать количество центров данных (DC) в кластере. Если в нем их несколько, между ними следует настроить репликацию.
В Cassandra это делается при создании таблицы или через изменение существующих настроек с помощью команды ALTER TABLE. Например, чтобы создать таблицу с репликацией на 3 узла, можно использовать следующий синтаксис:
CREATE TABLE example_table (
id int PRIMARY KEY,
name text
) WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
Здесь мы используем стратегию SimpleStrategy и устанавливаем количество реплик, равное 3. Если мы хотим настроить репликацию между несколькими центрами данных, то можем использовать стратегию NetworkTopologyStrategy и указать количество реплик для каждого центра данных.
CREATE TABLE example_table (
id int PRIMARY KEY,
name text
) WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1': 2, 'DC2': 2};
Здесь мы используем стратегию NetworkTopologyStrategy и устанавливаем количество реплик, равное 2, для каждого центра данных (DC1 и DC2).
Ошибка 4. Неправильная настройка репликации данных
Неправильная настройка репликации данных в Cassandra может привести к потере данных или снижению производительности системы. Она определяет, как много копий данных следует создать в кластере и на каких узлах они должны располагаться.
Вот некоторые распространенные ошибки, которые можно допустить при настройке репликации данных в Cassandra:
Некорректный выбор стратегии репликации: Cassandra предоставляет две стратегии: SimpleStrategy и NetworkTopologyStrategy. SimpleStrategy используется для создания однородных кластеров, где все узлы имеют одинаковую роль. NetworkTopologyStrategy — для создания кластеров с несколькими центрами данных. Неправильный выбор стратегии может привести к неравномерному распределению данных и снижению производительности системы.
Неправильная настройка фактора репликации: replication factor — это количество копий данных, которые необходимо создать в кластере. Неправильная настройка может быть чревата слишком большим или слишком маленьким количеством копий данных, что повлияет на доступность последних и производительность системы.
Неверная настройка стратегии размещения данных: Cassandra позволяет настраивать расположение копии данных, используя стратегию размещения данных. Например, для стратегии NetworkTopologyStrategy можно настроить расположение копий данных в разных центрах данных. Такая ошибка может привести к неравномерному распределению данных и снижению производительности системы.
Неправильная настройка уровня согласованности: Cassandra позволяет регулировать consistency level для каждого запроса. Уровень согласованности определяет, сколько копий данных должно быть прочитано или записано для выполнения запроса. Некорректная настройка грозит неравномерным распределением данных и снижением производительности системы.
О последнем хочу рассказать подробнее — перечислю возможные ошибки при настройке уровня согласованности в Cassandra:
Неверное использование уровня согласованности ONE: запрос может быть выполнен, даже если доступна только одна копия данных. Это способно привести к тому, что некоторые запросы будут возвращать устаревшие данные, которые еще не были синхронизированы с другими копиями данных в кластере.
Некорректное использование уровня согласованности ALL: запрос будет выполнен только в том случае, если все копии данных доступны. Последствия — увеличенная задержка выполнения запроса и снижение производительности системы.
Неправильная настройка уровня согласованности для чтения и записи. Делать это можно отдельно в Cassandra. Ошибки чреваты неравномерным распределением данных, их устареванием или вовсе потерей.
Неверное использование уровня согласованности QUORUM: он применяется, чтобы обеспечить доступность данных и производительности системы. Этот уровень согласованности гарантирует, что большинство узлов в кластере участвуют в чтении или записи данных. Неправильная настройка грозит неравномерным распределением данных и снижением производительности системы.
Для правильной регулировки уровня согласованности в Cassandra необходимо учитывать требования к доступности данных и производительности системы. Хорошая практика — использовать QUORUM для чтения и записи, если это необходимо, а также настраивать уровень согласованности для каждого запроса в зависимости от его логики.
Например, для запросов, которые должны возвращать самые актуальные данные, можно использовать уровень согласованности ALL, а для запросов, которые могут возвращать редко изменяющиеся данные, — ONE.
Проиллюстрирую. Чтобы настроить уровень согласованности QUORUM для чтения и записи в кластере Cassandra с 3 узлами, можно использовать следующий код:
CREATE KEYSPACE my_keyspace WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1': 3};USE my_keyspace;
CREATE TABLE my_table (
id int PRIMARY KEY,
data text);
INSERT INTO my_table (id, data) VALUES (1, 'data1') USING CONSISTENCY QUORUM;SELECT * FROM my_table WHERE id = 1 USING CONSISTENCY QUORUM;
В этом примере уровень согласованности QUORUM устанавливается для запросов на запись и чтение, при этом используются операторы INSERT и SELECT с параметром CONSISTENCY. Репликация данных настроена на 3 узла, расположенных в одном дата-центре (DC1).
Важно учитывать, что настройка уровня согласованности должна быть сбалансирована между производительностью и доступностью данных. Слишком высокий уровень согласованности может снизить производительность системы, а слишком низкий — привести к потере данных.
Ошибка 5. Неверное применение сетевых настроек
Cassandra активно использует сеть для обмена данными между узлами кластера, поэтому правильная настройка сети критически важна для обеспечения высокой производительности и доступности данных. В зависимости от размера и конфигурации кластера может потребоваться разная скорость сети. Общее правило — обеспечить достаточную пропускную способность и низкую задержку для обработки операций чтения и записи данных.
Для кластеров Cassandra с небольшим количеством узлов (до 10) рекомендуется использовать сеть с пропускной способностью от 1 Гбит/с до 10 Гбит/с. Для кластеров с более чем 10 узлами необходимо применять сеть с более высокой пропускной способностью, например 25 Гбит/с или 100 Гбит/с.
При работе функционирует несколько портов для обмена данными между узлами кластера, в том числе — для взаимодействия с клиентам и порты для межузловой связи (gossip-протокол). При настройке кластера важно убедиться, что порты узлов настроены правильно и что все узлы могут связываться друг с другом через них. Если есть ошибки, производительность системы может снизиться, а связь между узлами кластера — потеряться.
Вот стандартные зарезервированные порты Cassandra:
7000: межузловой порт для связи между узлами кластера,
7001: межузловой SSL-порт для защищенной связи между узлами кластера,
7199: порт JMX для мониторинга и управления Cassandra через JMX-интерфейс,
9042: порт CQL для обмена данными между приложениями и Cassandra с помощью языка запросов CQL.
Кроме того, при использовании Cassandra необходимо учитывать особенности сетевых настроек на уровне операционной системы. Так, для обеспечения высокой производительности и доступности данных в Cassandra может потребоваться настройка определенных параметров TCP/IP на уровне операционной системы, таких как размер буферов TCP и количество открытых соединений. Неверная настройка снизит производительность и доступность данных.
Ошибка 6. Неправильное использование дисков
Это может быть чревато низкой производительностью и неэффективным использованием ресурсов.
Распространенные ошибки:
Использование медленных дисков (HDD). Cassandra лучше всего работает на быстрых дисках (SSD) с высокой скоростью чтения и записи. Медленные же создают узкое место в производительности и замедляют работу всего кластера. Кроме того, не рекомендуется использовать разные типы дисков (HDD и SSD) в одном кластере.
Применение RAID 5 в качестве хранилища данных для Cassandra. Это грозит низкой производительностью и проблемами с целостностью данных. Рекомендую прибегать к RAID 0 или RAID 10 для улучшения производительности и защиты от потери данных.
Выбор одного диска для размещения журнала фиксации (commitlog) и данных. Последствия — низкая производительность дискового массива. Чтобы хранить $CASSANDRA_HOME/data/data и $CASSANDRA_HOME/data/commitlog, лучше выбирать отдельные диски.
Использование дискового кэша (cache). Если он слишком маленький, при записи производительность будет низкой. С другой стороны, слишком большой кэш может привести к нехватке памяти, что тоже плохо скажется на производительности.
Обязательно озаботьтесь следующими параметрами в конфигурационном файле:
concurrent_reads — количество потоков, которые могут одновременно читать данные с диска. Этот параметр должен быть установлен в соответствии с количеством ядер процессора и скоростью дисковой подсистемы. Он также зависит от того, какие операции вы выполняете.
concurrent_writes — количество потоков, которые могут одновременно записывать данные на диск. Ориентироваться нужно на количество ядер процессора и скорость дисковой подсистемы.
concurrent_counter_writes — это параметр конфигурации Cassandra, который определяет количество потоков, способные выполнять операции записи счетчика одновременно. Счетчик (counter) — структура данных внутри Cassandra, представляет собой особый тип колонок, который позволяет увеличивать или уменьшать значение счетчика на определенную величину. В основном используются для операций инкремента и декремента.
memtable_flush_writers — число потоков, которые могут одновременно записывать данные из memtable в SSTable. Этот параметр также должен быть установлен в соответствии с количеством ядер процессора и скоростью дисковой подсистемы. SSTable - это отсортированный набор данных, который представляет собой неизменяемый файл на диске. SSTable состоит из двух файлов: файл данных и файл индекса, является основным механизмом хранения данных в Cassandra.
memtable_cieanup_threshold — процент заполнения memtable, при котором она автоматически сбрасывается на диск. Значение следует выбирать опытным путем на основе размера данных, которые вы записываете.
Еще один важный момент — параметр опережающего чтение (Read ahead).
Read ahead в Cassandra может улучшить производительность чтения данных, поскольку оно позволяет загрузить данные из файла в кэш до того, как они будут запрошены. Это уменьшает время ожидания чтения с диска.
Read ahead настраивается в Cassandra с помощью параметра disk_access_mode. Он может принимать одно из трех значений: auto, mmap или standard.
auto — использует наилучший доступный метод чтения данных в зависимости от операционной и файловой систем.
mmap — применяет метод memory-mapped I/O для чтения данных, что позволяет избежать копирования данных в буфере и повышает производительность чтения.
mmap_index_only — Cassandra загружает только индексы таблицы в память, оставляя данные на диске.
standard — использует стандартный метод чтения данных. Это может привести к повторному чтению данных и замедлению производительности.
Кроме того, значение read ahead нужно скорректировать и на операционной системе.
В Linux опережающие чтение можно настроить с помощью инструмента blockdev. Например, чтобы установить значение для read ahead раздела диска /dev/sda1 на 4 КБ, нужно выполнить:
$ blockdev --setra 8 /dev/sdal
Эту рекомендацию следует использовать в качестве отправной точки: настраивайте в соответствии с вашими требованиями к уровню обслуживания и пропускной способности.
Подытожу: чтобы избежать ошибок настройки и эксплуатации кластера Cassandra, делайте следующее:
Проводите тестирование перед запуском в продуктив;
Используйте рекомендации из документации по настройке кластера;
Адаптируйте их под ваш кластер;
Непрерывно оптимизируйте схемы данных и запросов.
one-eyed-j
Проектирование схемы, включая partitioning/clustering keys, нужно начинать с анализа всех возможных запросов. В некоторых случаях необходимо дуплицировать данные с различными ключами, для того чтобы отвечать на запросы, которые в принципе не пересекаются по ключам. Всё это описано в хороших учебниках, я понимаю, что в короткой статье рассказать об этом невозможно.