Это продолжение цикла, рассказывающего о практике развёртывания производственного кластера Cassandra. В первой части мы начали продвигаться вот по такому плану:

  1. Анализ рабочей нагрузки и требований

  2. Разработка схемы данных

  3. Настройка хостовых машин

    = ВЫ НАХОДИТЕСЬ ЗДЕСЬ =

  4. Настройка конфигурации Cassandra

  5. Настройка топологии кластера

  6. Подключение Prometheus Cassandra Exporter

  7. Подключение Prometheus Node Exporter

  8. Вывод всех метрик в Grafana

  9. Проведение нагрузочного тестирования

  10. Дополнительный тюнинг по результатам теста

Продолжим?

4. Настройка конфигурации Cassandra

Выбор Cassandra 4.0 (вместо новой Cassandra 5) был обусловлен нашими текущими архитектурными решениями и кодовой базой, включая использование Java 11. Несмотря на это, Cassandra 4.x — это вполне современная (вышедшая в 2021-2023 гг.) и поддерживаемая версия.

Прежде чем начнём, скажу, что Cassandra имеет несколько сотен тонких и толстых параметров настройки и мы, к сожалению, рассмотрим лишь небольшую часть из них. Хорошая же новость в том, что даже если вы настроите только те параметры, которые рассматриваются в этом материале, то ваш кластер будет уже вполне работоспособен и сможет держать нагрузку. Однако использовать этот гайд для развёртывания тяжёлого кластера масштаба Netflix (условно) было бы несколько опрометчиво :)

Что имеем на старте?

А на старте у нас есть дефолтный файл конфигурации cassandra.yaml (для Ansible это cassandra.j2), который для Cassandra 4.0 полностью выглядит так. Заберите этот конфиг из того образа, который вы используете для развёртывания. Пока что мы вписали сюда только seed-ноды — это две любые ноды Cassandra, находящиеся (очень желательно) в разных подсетях:

# deploy/templates/cassandra.j2
seed_provider:
	- class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          - seeds: "SEED_NODE1_IP,SEED_NODE2_IP"

Затем имеется следующий простой docker-compose.yaml (целиком):

# deploy/templates/docker-compose.j2
version: '3'

services:
  cassandra:
    image: cassandra:4.0
    container_name: cassandra
    restart: unless-stopped
    network_mode: "host"
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
    environment:
      # Адрес текущей ноды
      - CASSANDRA_BROADCAST_ADDRESS={{ ansible_host }}
      # Адреса seed-нод
      - CASSANDRA_SEEDS=SEED_NODE1_IP,SEED_NODE2_IP
      # Дефолтные значения на замену
      - MAX_HEAP_SIZE=512M
      - HEAP_NEWSIZE=100M
    volumes:
      # Папки с данными Cassandra
      - /cassandra:/var/lib/cassandra
      # Основной конфиг deploy/templates/cassandra.j2
      - ./cassandra.yaml:/etc/cassandra/cassandra.yaml

И, наконец, есть Ansible Inventory со списком хостов и их IP cassandra1..cassandra5, а также плейбук, содержащий следующую основную задачу:

# deploy/main.yml
- name: deploy
  hosts: all
  tasks:
	# ...
    - name: Copy all needed templates
      template:
        src: '{{ item.src }}'
        dest: '{{ item.dest }}'
      loop:
        - src: 'templates/docker-compose.j2' 
          dest: '{{ ansible_env.HOME }}/cassandra/docker-compose.yml'
        - src: 'templates/cassandra.j2'
          dest: '{{ ansible_env.HOME }}/cassandra/cassandra.yaml'
          mode: '664'
      become: true

    - name: Create and start services
      docker_compose:
        project_src: '{{ ansible_env.HOME }}/cassandra'

Для перезапуска нод и базовой проверки чаще всего пригодятся эти команды:

# Перезапуск одной командой
sudo docker-compose down && sudo docker-compose up -d
# Проверка логов запуска
sudo docker-compose logs cassandra -f
sudo docker-compose logs cassandra | grep ERROR
# Просмотр списка нод и их статуса
sudo docker exec cassandra nodetool status

Вы можете вдумчиво почитать комментарии к параметрам в оригинальном конфиге или сразу ринуться в бой — выбор за вами.

Настройка базовых параметров

Теперь нам предстоит привести ряд параметров Cassandra к более адекватным значениям, исходя из планируемого использования, возможностей железа и архитектуры Cassandra. Новые значения с первой попытки наверняка окажутся не очень оптимальными и потребуют дальнейшей тонкой настройки. Однако это будет уже намного, намного лучше, чем параметры по умолчанию.

Vnodes

Первым делом самолёты предстоит определиться с параметром num_tokens. Эта величина будет означать, что каждая физическая нода получит ровно столько же виртуальных нод или vnodes.

Cassandra 4.0 по умолчанию предлагает использовать 16 токенов. Поменять это значение на развернутом кластере невозможно, либо по сути это будет выглядеть как деплой нового чистого кластера “с нуля” с полным переносом данных из старого через внешний бэкап.

За подробным объяснением что такое vnodes отправлю вас в этот лонгрид: The Impacts of Changing the Number of VNodes in Apache Cassandra. А здесь ограничусь умеренной длины объяснением, чтобы быстро ввести в курс дела.

Этот параметр влияет сразу на несколько важных вещей:

  • Балансировку кластера

  • Метаданные и внутренний gossip-трафик

  • Производительность ремонта (Repair)

  • Размер сегмента при обмене данными (Streaming)

Vnodes: Балансировка кластера

Итак, num_tokens — это количество токенов, которые при инициализации кластера будут в случайном порядке распределены между всеми имеющимися нодами. То есть дефолтные 16 токенов будут раскиданы на 5 физических нод. Интуитивно понятно, что при таких численных вводных распределение может оказаться не очень равномерным. Ну, например, 2+3+1+7+3 = 16. В результате нода, получившая 7 токенов, будет обрабатывать в 7 раз большую нагрузку, чем нода, получившая 1 токен. То же пропорционально верно для остальных нод.

Конечно вы уже догадались, что для балансировки кластера следует увеличить либо количество токенов, либо число физических нод. Если нод достаточно много, то у вас появляется больше свободы в выборе подходящего числа токенов для кластера. И наоборот.

Для 5 нод увеличивать число токенов, например, вдвое с 16 до 32 особого смысла не имеет, поскольку “равномерность” случайного распределения вырастет лишь незначительно. А где 64 токена, там легко становится и 256, потому что распределение еще лучше выравнивается.

Vnodes: Метаданные и внутренний gossip-трафик

Gossip-протокол используется для обмена метаданными внутри кластера. Чем больше число токенов, тем больше метаданных будет храниться каждой ноде и тем выше внутренний трафик. Например, для кластера из 5-ти нод:

  • num_tokens = 16: 5 * 16 = 80 vnodes на весь кластер

  • num_tokens = 256: 5 * 256 = 1280 vnodes на весь кластер

Соответственно, увеличение num_tokens с 16 до 256 приведет к увеличению gossip-трафика в 16 раз (1280 / 80 = 16) и настолько уже увеличит необходимый объем памяти для метаданных. С другой стороны, для современных высокопроизводительных сетей и серверов этот оверхед незначителен по сравнению с преимуществами балансировки кластера.

Vnodes: Производительность ремонта (Repair)

Процесс ремонта проверяет и синхронизирует данные между нодами и работает с диапазонами токенов. Высокое значение num_tokens замедляет скорость ремонта, т.к. увеличивается количество диапазонов токенов, которые нужно передать.

Однако для современных версий Cassandra 4.0 и выше временные издержки незначительны, поскольку используется инкрементный repair, работающий намного эффективнее прежних версий, поэтому время ремонта уже не увеличивается линейно.

Наконец, процедура ремонта в норме требуется достаточно редко (добавление и удаление нод, восстановление после сбоев), а на стабильно работающем кластере — почти никогда. Другими словами, временными затратами на Repair при выборе числа num_tokens чаще всего можно пренебречь.

Vnodes: Размер сегмента при обмене данными (Streaming)

Streaming используется при добавлении, удалении, перемещении или замене ноды, а также при ремонте и восстановлении нод кластера.

Допустим, у нас есть 1 ТБ данных на 4 нодах, и мы добавляем 5-ю ноду.

  • num_tokens = 16: Каждая из 4 нод должна будет передать на новую примерно 16 / 4 = 4 сегмента данных по 250 Гб каждый “за раз” (всего 16 параллельных потоков)

  • num_tokens = 256: Каждая из 4 нод передаст на новую ноду примерно 256 / 4 = 64 сегмента данных по 16 Гб каждый “за раз” (всего 256 параллельных потоков)

Подсчет довольно грубый, потому что мы не учли фактор репликации для упрощения примера. Однако уже нетрудно сообразить, что для нашего небольшого кластера вариант с num_tokens = 256 и “легкими” небольшими сегментами в Streaming подходит как нельзя лучше.

Vnodes: Подытожим

Давайте просуммируем исправления и внесем их в конфиг:

# deploy/templates/cassandra.j2
cluster_name: 'Production Cluster'
num_tokens: 256

Производительность компакции

Краткая справка:
Компакция в Cassandra — это процесс объединения нескольких SSTable (Sorted String Table) файлов в один или несколько новых файлов для оптимизации производительности и высвобождения дискового пространства.

▼ Я уменьшил дефолтное значение compaction_throughput_mb_per_sec до 32 Мб/сек. Сам параметр напрямую связан с производительностью дисковой подсистемы. Забегая вперед скажу, что для нашего железа (Core i5 / 64 GB RAM / 2 x 512 GB NVMe SSD / 16 TB SATA) по итогу и после всех тестов подходящим значением стало 24 Мб/сек (для дисков SATA).

Находим в конфиге соответствующий параметр и меняем значение:

# deploy/templates/cassandra.j2
compaction_throughput_mb_per_sec: 32

Таймауты записи и чтения

Здесь сталкиваются потребности вашего приложения к скорости ответа при операциях записи/чтения с одной стороны, и производительность дисков — с другой. Если требования приложения высокие, то следует подумать о выборе серверов с высокопроизводительной дисковой подсистемой.

Я установил параметры read_request_timeout_in_ms и write_request_timeout_in_ms равными 10 секундам, чтобы “перестраховаться“, хотя это значение избыточно даже для HDD дисков. Отмечу, что в самом неудачном нагрузочном тесте задержки достигали 1000 мс. Сейчас же на работающем production кластере задержки иногда достигают 40 мс для записи и 8-10 мс для чтения (думаю, они еще вырастут по мере увеличения нагрузки).

Возможно, даже очень требовательному к скорости приложению иногда бывает лучше подождать, чем получить отказ в обслуживании и потерю данных. Так что запас по таймауту в некоторых случаях не помешает. Но, с другой стороны, избыточные значения задержки могут скрывать проблемы конфигурации и плохую настройку кластера.

Словом, установите некие стартовые значения, которые впоследствии можно будет поправить по результатам нагрузочного тестирования:

# deploy/templates/cassandra.j2
read_request_timeout_in_ms: 10000
write_request_timeout_in_ms: 10000

Бесполезная оптимизация репликации

Параметр allocate_tokens_for_local_replication_factor служит для автоматической оптимизации распределения токенов (vnodes) по кластеру. Он пытается сгруппировать реплики для одного и того же набора данных на меньшем числе нод, чтобы уменьшить внутренний трафик.

Несмотря на кажущуюся полезность, параметр потенциально конфликтует с принципом vnodes, использует не всегда очевидный алгоритм и может нарушить равномерное распределение данных по кольцу кластера. В свою очередь, это может привести к разбалансировке нагрузки и перевешивает возможные выгоды от этой опции.

Большинство рекомендаций в интернетах сводятся к тому, чтобы отключить этот параметр, что мы и сделаем:

# deploy/templates/cassandra.j2
# allocate_tokens_for_local_replication_factor: 3

Суммируем всё в конфиг

Как вы помните, ранее в разделе “Настройка хостовых машин” мы переносили CommitLog на SSD для ускорения работы. Пора это тоже зафиксировать, в дополнение ко всему остальному. ВАЖНО: Местоположение папки с CommitLog нельзя поменять после развёртывания кластера!

# deploy/templates/cassandra.j2
cluster_name: 'Production Cluster'

num_tokens: 256

# allocate_tokens_for_local_replication_factor: 3

compaction_throughput_mb_per_sec: 32

read_request_timeout_in_ms: 10000
write_request_timeout_in_ms: 10000

commitlog_directory: /var/lib/cassandra/commitlog_nvme

seed_provider:
	- class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          - seeds: "SEED_NODE1_IP,SEED_NODE2_IP"

Параметр endpoint_snitch рассмотрим отдельно в разделе “Настройка топологии кластера”.

Сборщик мусора

Разные сборки Cassandra могут использовать устаревший сборщик мусора CMS или более современный G1 Garbage Collector (G1GC).

CMS определенно будет неудачным выбором, поскольку первый же нагрузочный тест уронил две ноды. Допускаю, что CMS тоже можно правильно настроить, однако зачем? Просто замена на G1GC позволила кластеру отлично выдержать часовой highload тест. При этом никакие другие параметры не тюнились, так что эксперимент с зависимостью именно от сборщика мусора можно считать вполне показательным.

Вначале проверьте, какой именно сборщик мусора сейчас используется:

sudo docker-compose logs cassandra | grep "JVM Arguments"

В выводе будет одна длинная строка с параметрами. Найдите там -XX:CMS... или -XX:G1.... Если вам повезло и менять сборщик мусора не требуется, то все же есть смысл настроить параметры сборщика G1GC более точно.

Нужный нам файл конфигурации называется jvm11-server.options и полностью выглядит
вот так. Забрать его, конечно, нужно не из репозитория, а из контейнера с запущенной Cassandra или из образа вашей конкретной сборки. Например, скопируйте файл из контейнера:

sudo docker cp cassandra:/etc/cassandra/jvm11-server.options /path-to/jvm11-server.options

Теперь можно отредактировать конфиг. Нам нужно:

  • Закомментировать все строки, относящиеся к CMS

  • Включить G1GC -XX:+UseG1GC

  • Настроить значение -XX:MaxGCPauseMillis

  • Настроить значение -XX:InitiatingHeapOccupancyPercent

Краткая справка:
Heap (Куча) — это область оперативной памяти, которую JVM выделяет для хранения всех объектов, создаваемых Cassandra во время работы. Память Heap делится на два "поколения": 1) Young Generation, где создаются все новые объекты. Эта область очищается сборщиком мусора часто и быстро. 2) Old Generation предназначена для долгоживущих объектов. Сборка мусора здесь происходит реже и более ресурсозатратная.

G1GC: MaxGCPauseMillis

-XX:MaxGCPauseMillis указывает желательное значение паузы, которую G1GC будет стараться не превышать. Иначе говоря это примерное максимальное время “заморозки” приложения, пока сборщик мусора выполняет свою работу. В этот момент приложение простаивает и время обработки данных увеличивается.

▼ При малых значениях параметра, например, до 100-200 мс, паузы будут очень короткими, чтобы улучшить время ответа (latency) приложения. G1GC будет собирать мусор чаще, но маленькими порциями. При этом общая пропускная способность (throughput) снижается, т.к. CPU тратит больше времени на частые и короткие циклы GC. И увеличивается риск, что Heap заполнится мусором быстрее, чем G1GC успеет его очистить — это может привести к длинной и нежелательной паузе для “накопившейся“ сборки мусора, т.н. “Full GC”.

В целом небольшие значения параметра рекомендуются для приложений, где низкая и предсказуемая задержка важнее общей пропускной способности.

▲ При больших значениях параметра, например, до 500-1000 мс, паузы будут более длинными, а сборка мусора будет происходить реже и большими порциями. Пропускная способность приложения (throughput) увеличится. Одновременно увеличивается продолжительность пауз, что может негативно сказаться на времени ответа (latency) приложения.

Увеличенное значение параметра рекомендуется, когда важна высокая пропускная способность, и допускаются более длинные, но редкие паузы. Например, для пакетной обработки данных или работы с высокими таймаутами.

Несложно сделать вывод, что тюнинг этого параметра соотносится с потребностями бизнес-задачи, которую вы решаете при помощи Cassandra, и возможностями серверного железа.

В очередной раз забегая вперёд скажу, что в нашем конкретном случае я начал с консервативного значения в 500 мс, но после первой же пары нагрузочных тестов уменьшил его до 200 мс. Что хорошо сказалось на общей отзывчивости кластера и стало вполне подходящим балансом между latency и throughput.

G1GC: InitiatingHeapOccupancyPercent

-XX:InitiatingHeapOccupancyPercent (IHOP) определяет порог заполненности всего Heap в процентах, при достижении которого G1GC начинает “concurrent marking cycle”. Это фаза, когда G1GC в фоновом режиме (без остановки приложения) ищет мусор в Old Generation, чтобы определить, какие регионы там содержат больше всего мусора, и включить их в следующие циклы сборки мусора (вместе с регионами New Generation).

Всё это погружение в тёмные и неизведанные глубины JVM очень интересно, скажете вы, но можно попроще? Конечно. Давайте посмотрим на что именно и как это влияет:

▼ При уменьшении IHOP, например, до 40-50%, G1GC будет чаще запускать “concurrent marking cycle”, чтобы избежать ситуаций, когда Heap внезапно заполняется и случаются “неожиданные” и нежелательные "Full GC". Это создает больше фоновой нагрузки на CPU и может снизить общую пропускную способность.

Пониженные значения параметра рекомендуются на больших Heap или при очень высокой скорости создания объектов в JVM, чтобы дать G1GC больше времени на подготовку к сборке мусора.

▲ При увеличении IHOP, например, до 70-80%, G1GC будет реже запускать “concurrent marking cycle”, что снизит фоновую нагрузку на CPU. Однако увеличивается риск, что при резком всплеске создания объектов Heap заполнится быстрее, чем G1GC успеет завершить цикл маркировки и начать очистку мусора, что опять же приведет к "Full GC".

Увеличение параметра рекомендуется когда нагрузка на создание объектов относительно предсказуема и не слишком высока, и хочется минимизировать фоновую работу GC.

Короче говоря, значение в 70% — это вполне хорошая и безопасная настройка для Heap размера 16 Gb, который мы настроим буквально в следующем разделе. Это даёт G1GC достаточно времени на реакцию, не создавая при этом излишней фоновой нагрузки.

Суммируем настройки G1GC в серверный конфиг

# deploy/templates/jvm11-server.options.j2

### CMS Settings
#-XX:+UseConcMarkSweepGC
#-XX:+CMSParallelRemarkEnabled
#-XX:SurvivorRatio=8
#-XX:MaxTenuringThreshold=1
#-XX:CMSInitiatingOccupancyFraction=75
#-XX:+UseCMSInitiatingOccupancyOnly
#-XX:CMSWaitDuration=10000
#-XX:+CMSParallelInitialMarkEnabled
#-XX:+CMSEdenChunksRecordAlways
#-XX:+CMSClassUnloadingEnabled

### G1 Settings
## Use the Hotspot garbage-first collector.
-XX:+UseG1GC
#-XX:+ParallelRefProcEnabled

## Main G1GC tunable: lowering the pause target will lower throughput and vise versa.
## 200ms is the JVM default and lowest viable setting
## 1000ms increases throughput. Keep it smaller than the timeouts in cassandra.yaml.
-XX:MaxGCPauseMillis=500

## Optional G1 Settings
# Save CPU time on large (>= 16GB) heaps by delaying region scanning
# until the heap is 70% full. The default in Hotspot 8u40 is 40%.
-XX:InitiatingHeapOccupancyPercent=70

И конечно нужно смонтировать новый конфиг в docker-compose таким образом, чтобы исправленная версия заменила оригинальную в контейнере:

# deploy/templates/docker-compose.j2
services:
  cassandra:
    volumes:
      - ./jvm11-server.options:/etc/cassandra/jvm11-server.options

Убедитесь, что замена сборщика мусора прошла успешно. На любой ноде перезапустите docker-compose и проверьте, во-первых, что ничего не сломалось и нода запустилась, а, во-вторых, повторите:

sudo docker-compose logs cassandra | grep "JVM Arguments"

Параметров, начинающиеся с -XX:CMS... в выводе быть не должно, а должен присутствовать -XX:+UseG1GC и его настройки, которые вы только что сделали.

Настройка docker-compose

Память и куча

Параметры MAX_HEAP_SIZE и HEAP_NEWSIZE — одни из самых важных для настройки производительности любого Java-приложения, и Cassandra не исключение.

MAX_HEAP_SIZE — максимальный размер Heap, который JVM может выделить для Cassandra. Параметр определяет, сколько данных Cassandra может держать в памяти одновременно. Недостаточное значение приведет к частым и агрессивным сборкам мусора, ошибкам OutOfMemoryError и общей медленной работе. Избыточное значение может привести к слишком длинным паузам сборки мусора (GC pauses), в течение которых Cassandra не сможет отвечать на запросы.

Общая рекомендация заключается в том, чтобы устанавливать MAX_HEAP_SIZE от 1/4 до 1/2 объема оперативной памяти. В нашем случае при 64 Gb RAM я выбрал значение 16 Gb.

HEAP_NEWSIZE определяет размер Young Generation внутри Heap. При маленьком значении область Young Generation будет заполняться слишком быстро, а сборки мусора станут чаще. При большом значении сборки мусора будут происходить реже, но более станут более продолжительными.

Обычно рекомендуется устанавливать параметр в размере 1/4 от MAX_HEAP_SIZE.

Зафиксируем изменения в docker-compose:

# deploy/templates/docker-compose.j2
services:
  cassandra:
    environment:
      - MAX_HEAP_SIZE=16G
      - HEAP_NEWSIZE=4G

Лимиты на файлы и процессы

Лимиты на открытые файлы и процессы для пользователя Cassandra должны быть установлены с достаточным запасом. Заметьте, что, во-первых, есть ulimits для пользователя, запускающего Docker (или для демона Docker), а во-вторых, есть ulimits для самой Cassandra внутри контейнера. При этом лимиты Docker’а могут влиять на дефолтные ulimits внутри контейнеров.

# Проверка на хостовой машине:
# Лимиты для пользователя, запускающего docker-compose
ulimit -n
ulimit -u

# Лимиты демона Docker, если он запущен через systemd
sudo systemctl cat docker | grep -E "LimitNOFILE|LimitNPROC"`

Лимиты внутри контейнера:

docker exec -it cassandra bash

# И далее внутри контейнера
ulimit -n
ulimit -u 

Добавьте в docker-compose для гарантии:

# deploy/templates/docker-compose.j2
services:
  cassandra:
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
      nproc:
        soft: 32768
        hard: 32768

Монтирование логов на локальный хост

Это вполне хорошая практика хранить логи на хостовой машине, чтобы они не терялись после перезапуска нод (контейнеров). Для этого сделайте на каждой ноде (хосте) локальную папку для логов. ВАЖНО: НЕ создавайте директорию логов внутри основной папки Cassandra с данными!

# Здесь 999:999 - Cassandra user/group
sudo mkdir -p /var/log/cassandra_host_logs
sudo chown -R 999:999 /var/log/cassandra_host_logs
sudo chmod 755 /var/log/cassandra_host_logs

ls -la /var/log/cassandra_host_logs

Добавляем монтирование в docker-compose:

# deploy/templates/docker-compose.j2
services:
    volumes:
      - /var/log/cassandra_host_logs:/var/log/cassandra

Суммируем всё в docker-compose

# deploy/templates/docker-compose.j2
version: '3'

services:
  cassandra:
    image: cassandra:4.0
    container_name: cassandra
    restart: unless-stopped
    network_mode: "host"
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
    environment:
      - CASSANDRA_BROADCAST_ADDRESS={{ ansible_host }}
      - CASSANDRA_SEEDS="SEED_NODE1_IP,SEED_NODE2_IP"
      - MAX_HEAP_SIZE=16G
      - HEAP_NEWSIZE=4G
    volumes:
      - /cassandra:/var/lib/cassandra
      - ./cassandra.yaml:/etc/cassandra/cassandra.yaml
      - /cassandra/commitlog_nvme:/var/lib/cassandra/commitlog_nvme
      - ./jvm11-server.options:/etc/cassandra/jvm11-server.options
      - /var/log/cassandra_host_logs:/var/log/cassandra
	ulimits:
      nofile:
        soft: 65536
        hard: 65536
      nproc:
        soft: 32768
        hard: 32768

Если вы уже успели развернуть кластер, то попытка изменить расположение CommitLog вызовет неустранимую ошибку. На пустом кластере самым быстрым решением будет очистка папок с данными, в которые Cassandra успела записать внутренние таблицы с конфигурацией.

ВАЖНО: Эти операции эквивалентны hard reset и уничтожают все данные Cassandra! Заметьте, что мы не удаляем сами папки, а только очищаем содержимое.

# Остановите ноды
sudo docker-compose down

# Удалите все данные, hints и кэш
sudo rm -rf /cassandra/data/*
sudo rm -rf /cassandra/hints/*
sudo rm -rf /cassandra/saved_caches/*

# Эта папка будет существовать, если вы запускали кластер ДО переноса CommitLog
sudo rm -rf /cassandra/commitlog/*

sudo rm -rf /cassandra/commitlog_nvme/*

Резюмируем

Пожалуй, можно уже подбить итоги всех изменений. Рутинно напоминаю, что зависимые от хоста правки нужно сделать на каждом из них. За исключением автоматического деплоя, который раскатывается сразу на все ноды.

Давайте именно последнее и сделаем при помощи обновлённого Ansible плейбука:

# deploy/main.yml
- name: deploy
  hosts: all
  tasks:
	# ...
    - name: Copy all needed templates
      template:
        src: '{{ item.src }}'
        dest: '{{ item.dest }}'
        owner: '{{ item.owner | default("root") }}'
        group: '{{ item.group | default("root") }}'
        mode: '{{ item.mode | default("0644") }}'
      loop:
        - src: 'templates/docker-compose.j2'
          dest: '{{ ansible_env.HOME }}/cassandra/docker-compose.yml'
          owner: 'root'
          group: 'root'
          mode: '0644'
        - src: 'templates/cassandra.j2'
          dest: '{{ ansible_env.HOME }}/cassandra/cassandra.yaml'
          owner: 'cassandra'
          group: 'cassandra'
          mode: '0644'
        - src: 'templates/jvm11-server.options.j2'
          dest: '{{ ansible_env.HOME }}/cassandra/jvm11-server.options'
          owner: 'cassandra'
          group: 'cassandra'
          mode: '0644'
      become: true

    - name: Create and start services
      docker_compose:
        project_src: '{{ ansible_env.HOME }}/cassandra'

Похоже, ваш кластер уже заработал? :)
Продолжение следует.

Комментарии (0)