Как правильно развернуть и запустить смотрим деплой.
Как правильно "перехать" на другой хост смотрим миграция
В этом документе описанно как работает репликация, как правильно ее настроить, что делать если репликация "развалилась"
Любые запросы на изменения RocksDB предварительно записывает в так называемый WAL (Write Ahead Log или лог перед записью), прежде чем записать их в основную базу (sst-файлы). Сама RocksDB предоставляет бинарный интерфейс для чтения WAL, а демон PrefixDB соотвествующий JSON-RPC метод get_updates_since
для чтения этого WAL. Слейв, процесс PrefixDB который хочет получать все измения данных мастера, подключаеться к мастеру по TCP и, с помощью этого метода, получает все измения для поддержания базы в актуальном состоянни. Иными словами, архитектура репликации реализована так, что слейвы запрашивают изменения на мастере, а не наоборот (когда мастер рассылает измения на слейвы).
На момент реализации проекта PrefixDB бинарный формат WAL для RocksDB был закрыт, и он был определен через реверс-инженериг. Позже он был открыт, и на первый взгляд, формат был определен правильно, но для избежания сюрпризов, репозитарий RocksDB был форкнут в репозитарий мамбы. Если необходимо будет обновить RocksDB, то в первую очередь необходимо убедиться, что репликация для новой версии будет работать.
В JSON-конфигурации для PrefixDB указываеться путь к ini-конфигурации RocksDB, используя которую демон открывет RocksDB бызы для всех префиксов в общем окружении. Сам демон никак не анализирует конфигурацию RocksDB, а просто передает ее в RocksDB. Любые изменения настроек RocksDB влияют только на производительность самой RocksDB, за исключением двух опций, которые определяют время жизни WAL, и, соответсвенно на возможность репликации:
WAL_ttl_seconds=7200
WAL_size_limit_MB=0
Опция WAL_size_limit_MB
определяет минимальный размер WAL после которого он может быть сброшен. Про нее сразу забываем и всегда устанавливаем в ноль или не указываем (оптимальный размер определяеться самой RocksDB). Если репликация не предполагаеться, то параметр WAL_ttl_seconds
также устанавливаем в ноль. Это не отключает WAL, но позволяет RocksDB управлять им максимально эффективным образом, но при этом ломает репликацию PrefixDB.
Если на уже работающих PrefixDB задано WAL_ttl_seconds=0
то это основной признак того, что у этого процесса нет слейва (он просто не будет работать). Скорее всего для него нет сейва не просто так, а потому что профиль нагрузки на сервер такой, что либо сам механизм репликации не справляется, либо дает недопустимую избыточную нагрузку на местер, увеличивая общее время ответа. Поэтому если возникнет необходимость сделать для него слейв, то делать это нужно аккуратно, убедившись, что репликация влияет на время ответа сервера в допустимых пределах.
Опция WAL_ttl_seconds
должна быть ненулевой только на мастере, на слеве ее устанавливать не нужно, за исключением ситуации когда к слейву нужно подключить еще слейв "паровозом" (как правило это используеться на время "переезда" связки мастер-слейв без даунтайма, об этом расскажу в следующих разделах)
В продакшене для мастеров WAL_ttl_seconds=7200
- это два часа. Для нормально работающей связки мастер-слейв это даже избыточно. Его время можно интерпретировать как максимально время отставания слейва от мастера, при котором слейв остается работоспособным. Если отставание превысит это значение, то весьма вероятно (но не гарантированно), что репликация развалится. В штатном режме слейв отстает от мастера на несколько секунд. Если произошел разовый всплеск нагрузки на мастер, в результате работы каких-то скриптов (например очитстка от мусора, или наоборот какая-то массовая запись), то у слейва есть два часа, чтобы нагнать мастер. Но если изменился общий внешний профиль нагрузки на мастер, и слейв начал отставать, то весьма вероятно, что слейв мастер уже не догонит и репликация развалиться (демон слейва завершит работу). В этом случае (возрасла общая нагрука мастер) перезаливка базы и запуск слейва заного, поможет только до суточной пиковой нагрузки на мастер, потом она развалится. Но тем не менее возможна ситуация, когда какой-то скрипт, разово, внесет столько изменений, что слейв не уложится в два часа и демон завершит работу - в этом случае перезаливка поможет. Чтобы определить, почему это произошло, нужно смотреть графики btp.
В этот же интервал, два часа, можно спокойно останавливать слейв для каких-то работ (перезапуск сервера и пр.). После запуска он попытается нагнать мастер и выйти в штатный режим. Если время остановки слейва превышает два часа, то не факт, что потребуется перезаливка. Два часа -это минимально гарантированное время, может повезти и WAL на мастере проживет дольше. Пэтому если остановили слейв на любое время, то сначала можно попытаться запустить его без перезаливки базы. Под любым подразумеваем "абсолютли!" - все зависит от профиля нагрузки, я реально наблюдал ситуации, когда WAL "живет" месяцами (например одна запись в день, отстальное только чтение).
Репликация для каждого префикса производится независимо, но по одному или нескольким общим TCP соединениям, но поток запросов каждый префикс формирует свой. И у каждого префикса на мастере свой WAL. Как правило, если демон останавливает работу с сообщением в логе, что сломалась репликация, то он указывает в логе имя префикса, для которого она развалилась. В последних версиях PrefixDB скрипт перезаливки позволяет загрузить данные конкретного префикса (ну или сделать это вручную) и, после этого, нужно перезапустить после слейв. Только надо иметь ввиду, что за это время критически может отстать другой префикс и т.д. Иногда проще перезалить все приефиксы разом, чем разбираться в деталях.
Разница настроек мастера и конфигурации без поддержки репликации, может заключаться только в одной записи в ini-конфигурации RocksDB, а именно в уже описанной выше WAL_ttl_seconds
.
В теущем релизе для основных серверов PrefixDB предоставляеться три не слейв конфигурации по умолчанию:
prefixdb.conf
- без поддержки репликацииmaster.conf
- с поддержкой репликацииmaster-slave.conf
- это слейв котрый может быть мастером для другог слейва (можно выстраивать бесконечную цепочку репликации)
По большому счету разница у них только в пути к конфигурации ini-файлу RocksDB, а именно prefixdb.ini
и master.ini
. Для каждого сервера конфигурация может быть адаптирована под конкретный профиль нагрузки, но для репликации важнна только опция WAL_ttl_seconds
- для мастера она не нулевая.
Общая информация о конфигурации предоставлена здесь, но в краце опишу следующий момент, чтобы он не сбивал с толку. Для всех серверов PrefixDB в продакшене у нас открыты четыре порта:
23000
- основной порт23001
- порт для фоновых скриптов23002
- порт для подключения слейвов23003
- порт для текстовых запросов через telnet Первые три порта равнозначны по API, просто у них по разному сконфигурирована очередь обработки запросов. Порт23002
для конфигурации которая не поддерживает репликацию может быть открыт, т.е. по его наличию нему нельзя определить поддерживает эта конфигурация репликацию или нет. Основной ориентир это название конфигурационных файлов и опцияWAL_ttl_seconds
. АХТУНГ! на момент написания этой документации не все PrefixDB переведены на единый набор портов! Определить можно по имени хоста. Если в имени присутствует суффиксn
(напримерmastern0
) или окончание-deb
(напримерmaster0-deb
), то там набор портов соответствует регламенту. Если хост (виртуалка) называется простоmaster0
то скорее всего там другой набор портов, но он организован по схожему принципу. Но самое главное эти серверы работают на старой, несовместимой, RocksDB. К ним можно подключаться слейвом, но перезаливать базу нужно только через API (см. следующие разделы).
Конфигурация RocksDB (ini) на слейве может ничем не отличатся от настройки на мастере, но нам нет нужды держать два часа WAL, поэтому на сейве WAL_ttl_seconds=0
. Однако кофигурационный файл PrefixDB (slave.conf, а также master-slave.conf) имеет некторые отличия:
- Добавлен модуль
client-tcp
для подключения к мастеру - Добавлен модуль
prefixdb-gateway
для сериализации запросов в JSON-RPC к мастеру - В основном модуле
prefixdb
добавлена секцияslave
в которой настраиваются режимы работы с мастером.
Если вы задеплоили файл конфигурации для слейва по умолчаню slave.conf
, то в секции client-tcp
в поле addr
вам нужно будет указать имя хоста или ip мастера:
/*...*/
"client-tcp": [
{
"name": "client-tcp1",
"startup_priority":-500,
"addr": "", /* <- здесь нужно указать имя хоста (или ip) мастера */
"port": "23002",
"connect_count":5,
"threads":1
}
]
Пока еще есть бардак со старыми инстансами в регламенте открытых портов. На данный момент инстансы работающие на виртуалках с суффиксом 'n' в имени (например mastern5) соответсвует регламенту и для слейва открывает порт 23002. Для более древних виртуалок (например master1) порт для слейва нужно смотреть в конфиге и указать его в client-tcp
конфига слейва.
По умолчанию это поле пустое и в такой конфигурации демон не запустится. Однако если вы ошибетесь, то демон запуститься и будет вечно пытаться долбиться по этому адресу, что в прочем, легко обнаружить посмотрев логи. Настраивать другие поля, если вы точно не знаете, чего хотите добиться, не нужно. Модуль prefixdb-gateway
также не требует каких либо изменений в конфигурации.
В общем и секция slave
модуля prefixdb
не требует дополнительных настроек, но иногда может быть полезно их подкрутить:
{
/*...*/
"prefixdb": [
{
/*...*/
"path": "/monamour/prefixdb",
/*...*/
"slave": {
/* Можно установить в false чтобы временно отключить репликацию, не удаляя всю секцию */
"enabled": true,
/* Цель, шлюз через который происходят запросы к мастеру */
"target": "prefixdb-gateway1",
/* Можно установить время запуска репликации, а не сразу после запуска демона в формате "12:34:56" просто пусть будет */
"start_time": "",
/* Путь хранения файла счетчика (не базы), если пуст или не указан то /monamour/prefixdb_slave */
"path": "",
/* Запрашивать с мастера только разрешенные для записи префиксы */
"writable_only": false,
/* Спискок разрешенных для репликации префиксов например ["префикс1"]*/
"allowed_prefixes": [],
/* Спискок запрещенных для репликации префиксов например ["префикс1"]*/
"denied_prefixes": [],
/* Интервал вычитывания WAL*/
"pull_timeout_ms": 1000,
/* Интервал вычитывания списка префиксов */
"query_prefixes_timeout_ms": 2000,
/* Количестово записей за один запрос */
"log_limit_per_req": 100,
/* Только для отладки. Допустимое количество пропусков */
"acceptable_loss_seq": 0,
/* При каком количестве пропусков ( если acceptable_loss_seq > 0 ) нужно писать в лог предупреждение */
"wrn_log_diff_seq": 10000,
/* Как часто писать в лог записи об отставании об отставании от мастера, если это проиходит */
"wrn_log_timeout_ms": 1000,
/* Таймаут запросов к мастеру для получения изменений */
"seq_log_timeout_ms": 1000,
/* Выдерживать интервал после каждого запроса. В противном случае, если не достигнут конец WAL, следующий запрос */
"expires_for_req": false,
/* Отключить запись в WAL. Испльзовать только при полной выгрузке данных с мастера [при аварийном завершении чать данных */
/* может быть утеряна] */
"disableWAL": false
}
}
]
/*...*/
}
При настройке слейва важно следить не только за тем, что отстает ли репликация или нет, но и как она влияет на производительность мастера. Если при запуске слейва, время ответа мастера на боевые запросы недопустимо увеличивается, то во первых нужно убедиться, что слейв подключаеться не к общему порту мастера, а к специально выделеному (обычно 23002) и на этот порт навешано не слишком большое число потоков обработки (workflow, на самом деле должен быть один). Здесь двоякая ситуация. Чем больше потоков на мастере обслуживают слейв, тем быстрее происходит репликация. Однако, чем выше нагрузка записи в мастер, тем интенсивнее вычитываються WAL, что дает еще большую нагрузку на мастер и может увеличиваться время ответа на "боевые" запросы от клиентов, превышая критические значения. Поэтому на мастере, обычно, настроен один поток обработки слейва. Этого достатчно в большинстве случаев, но если слейв начинает отставать, то скорее всего на мастер и без того идет избыточная нагрука и, увеличение потоков обработки слейва может и решит проблему с отставанием, но навярняка приведет увеличению времени ответов на боевые запросы. Здесь нужно определить на какой префикс идет избыточная нагрузка и, оптимальным решением, будет перенести это префикс на другой сервер. Но опять же, нужно смотреть по ситуации и на профиль нагрузки мастера.
Настройки слейва также влияют на скорость репликации, нагрузку на сам слейв и на мастер. Рассмотрим более подробно эти опции:
"query_prefixes_timeout_ms": 2000
- получать список актуальных префиксов раз в две секунды (значение в миллисекндах). При значениях больше секунды этот параметр особо не влияет на производительность как мастера, так и слейва. С такой переодичностю слейв будет получать информацию о создании и удалении префиксов на мастере. Если из списка пропадет существующий на слейве префик то он закроет для него базу и пренесет файлы в/monamour/prefixdb_detach
. При появлении нового префикса, он создаст локальную базу для него и будет пытаться догнать отставание от этого префикса, пока не выйдет в штатный режим. На самом деле эти ситуации настолько редки, что не стоит особо заморачиватся по этому поводу. Может показаться зачем так часто получать список префиксов, если его изменение черезвычайно редкое событие? Ну это просто удобно при отладке или раскладке, но если это не дает нагрузки, то почему бы не сделать реакцию слейва на такое событие быстрой. Главное не устанавливать это значение большиим чемWAL_ttl_seconds
(два часа). Да и в районе часа не лучшее решение, при попытке слейвом догнать часовое отстование, он может дать существенную нагрузку на мастер."log_limit_per_req": 100
- кличество изменений в мастере которые получит слейв за один запрос к нему. Это основной параметр слейва с которым имеет смысл поиграться при отставании слейва или избыточной нагрузке на мастере (даже если на мастере настроен один поток обработки слейва, слейв может влиять на общую производительность мастера). Может показаться контринтуитивным, но чем меньше это значение, тем меньше нагрузка на мастер, несмотря на то, что количество запросов от слейва на мастер в возрастает. Значение в 100 записей на запрос это компромисное решение, которое не дает сильную нагруку на местер и, в тоже время, позволяет слейву не отставать от него, в большинстве случаев. Если слейв начал отставать, то имеет смысл увеличить это значение, например до 1000, но при этом обязательно отслеживать как изменилось время ответа на мастере на боевые запросы, например по графикам btp. Но при этом нужно учитывать, что несмотря на возможное снижение нагрузки на CPU на мастере, связанное с тем что нужно обрабоать в десять раз меньшне запросов, которое, впрочем производиться в отдельном потоке, мастеру нужно в десять раз больше считать данных с диска. И хотя это будет происходить реже (по разным причинам не в десять раз, а меньше), но эта операция может начать выбивать по таймауту пачками боевые запросы, поэтому нужно остлеживать по btp количество отвалившихся запросов по таймауту и решать с тех. подержкой допустимо это или нет."seq_log_timeout_ms": 1000
- интервал между запросами на мастер на получение изменений (одна секунда). Эта опция может показатся важной, так как вроде напрямую связана с предыдущей, но на самом деле нет, она не так критична. Логика тут такая: слейв делает запрос на вычитываниеlog_limit_per_req
записей из WAL местера и, если в ответе получает флаг, что еще не все данные прочитаны, тут же, без таймаута, посылает запрос на вычитывания следующей порции данных. Это позволяет слейву быстро нагнать мастер, при всплеске нагрузки на запись. И вот только когда слейв получает флаг, что все изменения прочитаны, срабатывает этот таймаут и следующий запрос будет произведен через секунду или через заданное значение. Смысла увеличивать этот параметр нет, потому что при слабой загрузке мастера эти запросы никак не влияют на его производительность. Уменьшать тоже смысла нет, при большой нагрузке он и так будет "долбить" мастер непрерывно. Увеличивать особо тоже нет смысла. Если вы зададите, например 10 минут, то раз в десять минут он будет задрюкивать мастер серией запросов на вычитывание WAL, пока весь его не вычитает. Единственный гепотетический кейс когда он может пригодиться, если какой-то скрипт делает большие пачки записей раз в секунду и нужно вывести слейв из этого "резонанса". Но если вы ключите опциюexpires_for_req
, то совместно они будут давать более значимый эффект. Но лучше этого не делать, если вы точно не знаете какого эффекта вы хотите добиться."expires_for_req": false
- эта опция запрещает вычитывание лога без таймаутаseq_log_timeout_ms
. Она меняет логику вычитывания WAL так, что каждый запрос на вычитывание WAL идет с интерваломseq_log_timeout_ms
вне зависимости от значения флага, что остались еще данные для вычитывания из WAL. Если вы точно не знаете чего хотите добиться, то лучше ее не устанавливать. В лучшем случае она не даст ефекта, но скорее приведет к отставанию слейва и в конечном итоге развалу репликации. Для этой опции можно придумать более реалистичные гипотетические кейсы, где она может пригодиться (например, на мастер заливаеться раз в сутки большой объем данных, а продакшн работает со слейвам, быстрая обновление не особо критично, но важно чтобы слейв не тормозил, тогда слейв потихонку вычитает данные). Короче, эта опция не даст нагруку на мастер, в ряде случаев даст иллюзию ее снижения, но при этом репликация отстанет и развалиться."disableWAL": false
отключает запись в WAL в смысле совсем (не путать ее сWAL_ttl_seconds=0
, когда изменения пишуться в WAL но время жизни управляються RocksDB). При отключении записи в WAL входящие данные не записываються на диск, а храняться в оперативной памяти. Это ускоряет репликацию, но при аварийном завершении работы демона или сервера, часть данных может быть утеряна. Эта опция важна для единственного случая, когда делаем полный перезалив бызы через API PrefixDB (более подробную информацию см. в разделе Перезаливка). Вне этого контекста эта опция мало в каких случаях поможет, за исключением разве что если на слейве люто медленный hdd и, в случае аварии, ненапряжно базу перезалить (и она не особо велика). Отключени WAL можно реализовать и на мастере, это может даст серёзный профит при ряде экстремальных профилей нагрузки, но сделает невозможным репликацию. Эта информация для того, что есть такая возможность, реализвать ее не сложно, если это действительно необходимо будет.
Перезаливка бызы с мастера на слейв нужна в двух случаях:
- Развертывние нового слейва
- При развале репликации, которая может произойти в следующих случаях:
- Отставание репликации на недопустимое время (WAL был на мастере перезаписан RocksDB, до вычитывания всех данных).
- Конфигурация мастера была изменена на уменьшение времени жизни WAL или он был запущен с конфигурацией без поддержки репликации.
- Демон слейва был отстановлен на время большием чем указано в опции
WAL_ttl_seconds
на мастере
- На слейве развернут демон с несовместимым форматом RocksDB. В этом случае поможет только перезалика через API демона.
Перезалить базу можно тремя способами:
- Простое копирование базы после остановки мастера и слейва.
- Копирование базы без остановки мастера
- Слейв загружает базу через API мастера. Работает сильно дольше, на позволяет перезалить базу даже если формат не совместим.
Для того чтобы можно было безопасно скопировать файлы базы с мастера на слейв, нужно, перед копированием, дать команду на мастер, чтобы он временно прекратил любые манипуляции с файлами базы. После завершения копирования, нужно дать команду на отмену запрета и можно запускать слейв. Для упрощения этой процедуры можно использовать скрипт:
./rsync-db.sh master5-deb 600
Первым параметром передаем имя хоста мастера или ip, а вторым время в секундах на запрет манипуляции с файлами на мастере. Скрипт посылает через telnet
команду на запрет нв манипуляцию с файлами на 600 секунд, потом копирует, с помощью rsync
, файлы с мастера в локальную папку /monamour/prefixdb/*
каталоги всех префиксов с мастера и, после этого, снимает запрет на изменения файлов. За указанное время скрипт должен успеть все скопировать, в противном случае возможно нарушение консистентности базы. Ограничение времени нужно на случай прерывания работы скрипта, чтобы мастер не остался в режиме запрета навсегда. Это время должно быть достаточным (возможно с запасом), но не слишком большим, желательно не более двух часов.
Этот скрипт работает только со стандартными портами (23003
) и путями (/monamour/prefixdb/*
), что легко можно изменить соответствующими изменениями в скрипте.
Порт 23003
предоставляет доступ к API в простом тектовом формате (не JSONRPC), например через telnet
. Его нельзя использовать в продакшене, он урезан по функционалу, неоптимизирован по производительности и полноценно не тестировался. Но для админских нужд вполне сойдет. Подключаетесь по telnet
к этому порту, набираете help
и получаете список доступных комманд. Скрипт ./rsync-db.sh
работает примерно следующим образом:
(echo "db 600"; sleep 1) | telnet master5-deb 23003
rsync ... #копируем файлы
(echo "cb"; sleep 1) | telnet master5-deb 23003
Здесь db
и cb
сокращенные варианты названия команд delay_background
и continue_background
соответсвенно. Они также доступны и через JSONRPC API.
Для этого достаточно указать список префиксов:
./rsync-db.sh master5-deb 600 префикс1 префикс2
или
(echo "db 600 префикс1 префикс2"; sleep 1) | telnet master5-deb 23003
rsync ... #копируем файлы
(echo "cb"; sleep 1) | telnet master5-deb 23003
В двух словах, слейв вычитывает все данные мастера по JSONRPC, используя метод range
. Т.е. сначала он долбит мастер вызовами range
пока не вкачает все данные, а потом запускает механизм репликации используя вычитывание WAL. Подобные запросы люто не "любит" сама RocksDB, да и сам механизм JSONRPC не особо предназначен для передачи большого объема данных. Однако это единственный способ перезалить данные в базу не совместимую с мастером.
Несмотря на то, что есть возможность резвернуть слейв базой другого формата (сильно другая версия или с без/с подержкой TTL), делать это вне контекста процесса миграции, по меньшей мере, не разумно. Этот процесс описан в разделе миграция
После запуска слейва внимательно смотрим лог:
2021-03-16 22:58:01.176 IOW END Client FAIL connected to addr:23002. 111 Connection refused
То это неверно указан адрес или порт мастера (демон продолжает работать! Предполагаем, что мастер просто упал или перезапускается. Как только порт будет открыт будет установленно соединнение).
Если адрес не указан (значение по умолчанию),то демон завершит работу с сообщением:
2021-03-06 01:22:04.347 SYSTEM WARNING !!! WFC ABORTED! Смотрите выше.
2021-03-06 01:22:04.347 FINAL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
...
2021-03-16 23:13:16.732 FINAL Message: In the configuration of the 'client-tcp1', you must set the 'addr' field or enable suspend mode
2021-03-06 01:22:04.347 FINAL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
В этом случае необходимо в конфигурации указать хост мастера.
Если переносим базу с помощью slave-reload.sh
(через API) то наблюдаем сообщения типа на время вычитывания базы:
2021-03-16 23:17:08.048 PrefixDB MESSAGE Initial load...
Для каждого префикса сообщения в лог пишутся примерно раз в секунду, и если подобные сообщения прекратились, то можно делать вывод что загрузка базы из мастера завершена. Каждый префикс загружеаеться независимо и после переходит в нормальный режим.
Чтобы убедиться, что репликация работает в штатном режиме проверям:
2021-03-16 23:17:08.048 PrefixDB MESSAGE 1 (201) updates for 'mlm' in the last 1 seconds. Next seq №3315197030
2021-03-16 23:17:09.048 PrefixDB MESSAGE No updates for 'mlm' in the last 1 seconds. Next seq №3315197030
Для каждого префикса подобные собщения пишутся в лог примерно раз в секунду. Сообщения типа No updates
это нормально и означает, что за прошедшую секунду на мастере небыло обновлений для данного префикса. Однако если ни для одного префикса в течении нескольких десятков секунд не прилетает ни одного обновления, то это может означать, что на мастере нет нагрузки или нагрузка только на чтение. Если на мастере есть нагрузка, то скорее всего что-то пошло не так. Для начала просто перезапустите слейв и если ничего не изменилось, обновления не идут, то обращаейтесь к разработчику.
Сразу после заливки бызы с мастера (второй и третий способ), слейв будет отставать от мастера на время этой перезаливки и будет пытаться сократить это отставание. Если отставание велико, то в лог (раз в секунду) будут писаться сообщения типа:
2021-03-17 22:39:21.560 PrefixDB WARNING Slave replication too big difference 'cshlp': 1208861(wrn:10000)
Важно убедиться, что отставание сокращаеться, а не нарастает. Для наглядности можно грепнуть по big
:
tail -f /logs/slave.log | grep big
В какие-то моменты отставание может увеличиваться (несколько секунд) - это нормально, главное чтобы в общем оно сокращалось. Иначе, в конце концов, репликация у вас развалится. Что делать в этом случае, смотри следующий раздел.
Обычно, демоны PrefixDB запущены с параметром автоматического перезапуска, с помощью моняторящего процесса, на случай падения. Но также там, обычно, установлен параметр для предотвращения "кувырканя", которая запрещает перезапуск демона если он проработал менее 10 минут (-a 600). Когда реплиикация разваливаеться, оснновной процесс демона завершает работу с ошибкой. Мониторящий процесс его перезапускает, но так как это не может восстановить репликацию, основной процесс повторно завершает работу, потому что он "понимает" невозможность продолжения репликация без потерь даных. А т.к. это происходит в пределах заданных 10 минут, моняторящий процесс повторно его не перезапускает. Это наиболее вероятный сценарий завершения работы слейва, но не единственный (как минимум, нужно убедиться, что места на диске не закончилось).
Для однозначного определения того, что демон завершил работу в результате развала репликации нужно посмотреть последние записи логов /logs/slave.log
или /logs/master-slave.log
в зависимости от текущей конфигурации (ну или просто самый свежий лог, если не уверены с какой конфигурацией был запущен демон). Если демон не грохнулся по segfaults, а в результате контролируемой ошибки после которой он не может продолжить корректную работу, то финальными записями лога будет вот такое красивое сообщение:
...
2021-03-06 01:22:04.347 SYSTEM WARNING !!! WFC ABORTED! Смотрите выше.
2021-03-06 01:22:04.347 FINAL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2021-03-06 01:22:04.347 FINAL ---------- Abnormal Shutdown! ----------
2021-03-06 01:22:04.347 FINAL Date: 2021-03-06
2021-03-06 01:22:04.347 FINAL Time: 01:22:03.348
2021-03-06 01:22:04.347 FINAL Name: PrefixDB
2021-03-06 01:22:04.347 FINAL Message: Slave replication error. Invalid master responce for 'adcfg' need sequence == 1, but last acceptable == 2 status=InvalidSeqNumber
2021-03-06 01:22:04.347 FINAL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
В данном примере части сообщения Slave replication error
и status=InvalidSeqNumber
однозначно сообщают о том, что репликация развалилась. Запись Invalid master responce for 'adcfg'
говорит о том, что именно на префиксе 'adcfg'
сломалась репликация. Это не значит, что на других префиксах все в порядке (демон завершает работу при ошибке репликации любого из префиксов). Разница между значениями need sequence
и last acceptable
показывает масштаб "трагедии". В данном примере пропущена всего одна запись, но этого достаточно чтобы зафиксировать ошибку репликации. На самом деле, с помощью опций PrefixDB можно задать допустимый предел пропусков (по умолчанию недопустимо), но делать этого в продакшене категорически не рекомендуеться (исключительно для отладки настроек).
Единственным вариантом решения этой проблемы являеться полная перезаливка всей базы, либо базы конкретного префикса. Перезаливка базы конкретных префиксов доступна для PrefixDB версии 0.9.2 (на мастере) и выше. Прежде чем принимать решение о презаливке конкретного префикса, нужно учесть следующие моменты (для примера возьмём тот же 'adcfg'):
- Если база префикса 'adcfg', допустим, занимает 500Гб, а остальные префиксы, суммарно до 100Гб (условно), то проще перезалить всю базу, на время копирования базы это существенно не повлияет.
- Если все префиксы укладываються в несколько десятков Гб (условно), то проще перезалить всю базу.
- Если база префикса 'adcfg' небольшая, но есть огромные префиксы на 500Гб, то имеет смысл перезалить имеено 'adcfg'.
- Если демон слейва не работал более двух часов, то вероятно за это время ошибка репликации возникнет и у остальных префиксов, поэтому делаем полный перезалив. Но это не точно. Если база 'adcfg' небольшая, то все равно можно попытаться перезалить только его и посмотреть, что будет. Если будет ошибка репликации на другом префиксе, и его база небольшая, то перезаливаем его Но если вы вышли в режим "и т.д.", то проще сделать полный перезалив.
- Слейв был остановлен на продолжительное время
- Разовая большие операции на мастере (заливка большого объема данных)
- Общее увеличение нагрузки (например, выкатили новый сервис в бой)
- Мастер был запущен с не тем конфигом, или были внесены изменения в конфигурацию без учета работы слейва
В двух словах RocksDB (это библиотека от facebook на базе которой построен демон PrefixDB) все измения первоночально пишет в WAL (лог перед записью) переодически его сбрасывая, после записи в хранилище (sst-файлы). Слейв, через API мастера, переодически (раз в секунду, настраивается) вычитывает эти данные, для обновления. По умолчаню время "жизни" WAL неопределено и RocksDB может его сбрасывать по своему усмотрению. Но для мастера конфигурация RocksDB (смотри master.ini
или master-slave.ini
) настроена так, чтобы гарантировано держать записи в WAL не мнее двух часов. За это отвечает поле:
WAL_ttl_seconds=7200
Если значение этого поля на мастере нулевое (смотри prefixdb.ini
или slave.ini
), то RocksDB работает с WAL по своему усмотрению, и слейв даже какое-то непродолжительное время может с ним работать, но потом все равно отвалиться, как только WAL обнулиться. Когда угодно это может произойти, но если на мастер идет хорошая нагрузка, то в течении нескольких минут или секунд. Если на мастер идут изменения (по всем префиксам) очень редко, то и сутки до развала могут пройти.
При переносе слейва на новый хост для работающей связки мастер-слейв этот параметр на мастере установлен в нужное значение. Если необходимо развернуть слейв для давно работающего PrefixDB без слейва, то скорее всего у него этот параметр нулевой. Его нужно перезапустить в режиме мастер master.sh start
, или, если этого скрипта нет, что означает там работает устаревшая версия, и внести изменения вручную. Но скорее всего вам это нужно будет делать только при миграции мастера на обновленную версию (см. далее), а слейв подцеплять уже в штатном режиме (см. выше)
Итак, если репликация равалилась, нам нужно перезалить базу, неважно каким способом. Здесь расмотрим ситуации, что делать если репликация разваливаеться сразу (или почти сразу) после перезаливки.
В первую очередь убеждаемся, что мастер сконфигурирован как мастер. Виртуалка может называться как masterN, демон может быть запущен с конфигом master.conf, но не факт, что этот конфиг настроен на репликацию, поэтому:
- заходим на хост мастера и в top или еще как смотрим имя конфиг-файла с которым запущен демон
- в конфиге находим путь к ini-файлу для RocksDB (можно грепнуть по ini)
- в ini-файле убеждаемся что
WAL_ttl_seconds=7200
имеет ненулевое значение
Если на мастере свежая версия ./prefixdbd -v
от 0.9.2 и выше то в текущем каталоге есть конфигурации и скрипты запуска в режиме мастера. Если нет, то вносим вручную изменения в INI файл и перезапускаем демон.
Далее расмотрим ситуации, если мастер сконфигурирован правильно, но при запуске слейва, репликация все равно разваливаеться через какое-то время:
- Если репликация работает некоторое время, но потом отваливаеться, проверте по логам, отставание слейва от мастера со временем сокращаеться, а не увеличивается
- Убедитесь что на диске есть место
- Попробуйте вручную очистить директории /monamour/prefixdb и /monamour/prefixdb_slave и запустить перезалив удобным для вас способом
- Убедитесь, что время копирования с помощью, например
time rsync-db.sh master5-deb 600
укладывется в 10 мин, если нет, то задайте нужное время - Убедитесь, что интервал запуска
./slave.sh start
послеrsync-db.sh
не привышет двух часов (или времени указаного вWAL_ttl_seconds
на мастере). - Если перезаливаете третим способом с помощью
./slave-reload.sh
убедитесь, что заливка укладываеться в два часа (или время указаного вWAL_ttl_seconds
на мастере). Это можно проверить по времени последней записи в логе '...Initial load..' и первой записи в логе.
Небольшая ремарка. Если перезаливаете третим способом с помощью ./slave-reload.sh
и время перезаливки превысило два часа, но при этом все работает корректно, демон продолжает работать и загружать данные, то не надо паниковать, останавливать демон и начинать все заного. Опция WAL_ttl_seconds=7200
задает нижнию границу, т.е. не менее двух часов, но может пройти неопределенно больше этого времени, чем WAL обнулится и репликация развалится, все очень сильно зависит от профиля нагрузки на мастер. Кроче, ждем пока демон сам отвалится, а не форсируем события.