Перейти к содержанию

Обслуживание

Руководство по периодическому обслуживанию кластера etcd

Обзор

Для сохранения надёжности кластер etcd нуждается в периодическом обслуживании. В зависимости от требований использующего etcd приложения такое обслуживание обычно можно автоматизировать и выполнять без простоя или существенного снижения производительности.

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

Хранение журнала Raft

Параметр etcd --snapshot-count задаёт количество применённых записей Raft, которые хранятся в памяти до компактизации. Когда достигается значение --snapshot-count, сервер сначала сохраняет данные снимка на диск, а затем усекает старые записи. Если медленный последователь запрашивает журналы до уже компактизированного индекса, лидер отправляет снимок, вынуждая последователь перезаписать своё состояние.

Большее значение --snapshot-count удерживает больше записей Raft в памяти до создания снимка, тем самым вызывая повторяющееся повышенное потребление памяти . Поскольку лидер дольше хранит последние записи Raft, у медленного последователя больше времени, чтобы догнать его до создания снимка лидером. Выбор --snapshot-count — компромисс между повышенным потреблением памяти и лучшей доступностью медленных последователей.

Начиная с v3.2 значение --snapshot-count по умолчанию изменено с 10,000 на 100,000 .

С точки зрения производительности значение --snapshot-count больше 100,000 может снизить пропускную способность записи. Большое количество объектов в памяти способно замедлить фазу маркировки Go GC runtime.scanobject , а редкое освобождение памяти замедляет её выделение. Производительность зависит от рабочей нагрузки и системного окружения. Однако в целом слишком частая компактизация ухудшает доступность кластера и пропускную способность записи. Слишком редкая компактизация также вредна, поскольку создаёт чрезмерную нагрузку на сборщик мусора Go. Дополнительные результаты исследований приведены в материале Understanding Performance Aspects of etcd and Raft .

Компактизация истории: база данных Key-Value API v3

Поскольку etcd хранит точную историю пространства ключей, её следует периодически компактизировать во избежание снижения производительности и окончательного исчерпания дискового пространства. Компактизация истории пространства ключей удаляет всю информацию о ключах, замещённых до заданной ревизии пространства ключей. Занимавшееся ими место становится доступным для последующих записей.

Пространство ключей можно компактизировать автоматически с помощью политики хранения истории etcd с временным окном либо вручную с помощью etcdctl. Метод etcdctl обеспечивает точное управление процессом компактизации, тогда как автоматическая компактизация подходит приложениям, которым история ключей нужна лишь в течение определённого времени.

Компактизация, инициированная etcdctl, выполняется следующим образом:

# compact up to revision 3
$ etcdctl compact 3

Ревизии, предшествующие ревизии компактизации, становятся недоступны:

$ etcdctl get --rev=2 somekey
Error:  rpc error: code = 11 desc = etcdserver: mvcc: required revision has been compacted

Автоматическая компактизация

Для автоматической компактизации пространства ключей в etcd можно задать параметры --auto-compaction-mode и --auto-compaction-retention. Существует два режима компактизации: periodic (по умолчанию) и revision.

Периодическая компактизация

Периодическая компактизация сохраняет ограниченное временным окном количество истории пространства ключей:

# keep one hour of history
$ etcd --auto-compaction-retention=1h

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

Если срок хранения превышает 1 час, etcd выполняет компактизацию каждый час, сохраняя полное окно хранения. Если срок хранения не превышает 1 часа, etcd выполняет компактизацию с интервалом, равным сроку хранения.

Например, с --auto-compaction-retention=10h etcd ждёт 10 часов до первой компактизации, а затем выполняет её каждый час:

0hr  (rev = 1)
1hr  (rev = 10)
...
8hr  (rev = 80)
9hr  (rev = 90)
10hr (rev = 100, Compact(1))
11hr (rev = 110, Compact(10))
...

Рекомендуемые значения зависят от сценария использования:

  • Частые обновления одних и тех же ключей: короткий период, например 1h или 30m
  • Редкие обновления: более длительный период, например 24h, 48h или 72h
  • Значение общего назначения по умолчанию: 10h

Компактизация по ревизиям

Компактизация по ревизиям сохраняет фиксированное количество ревизий:

# keep 1000 revisions
$ etcd --auto-compaction-mode=revision --auto-compaction-retention=1000

etcd выполняет проверку каждые 5 минут и компактизирует на ревизии "latest revision" - 1000. Например, если последняя ревизия равна 30000, компактизация выполняется на ревизии 29000.

Дефрагментация

После компактизации пространства ключей в базе данных бэкенда может возникнуть внутренняя фрагментация. Внутренне фрагментированное пространство доступно бэкенду, но по-прежнему занимает место в хранилище. Компактизация старых ревизий внутренне фрагментирует etcd, оставляя пустоты в базе данных бэкенда. Это место доступно для использования etcd, но недоступно файловой системе узла. Иными словами, удаление данных приложения не освобождает место на диске.

Дефрагментация возвращает это дисковое пространство файловой системе. Она запускается отдельно для каждого участника, что позволяет избежать всплесков задержки во всём кластере.

Для дефрагментации участника etcd используйте команду etcdctl defrag:

$ etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
Предупреждение

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

Предупреждение

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

Выполните дефрагментацию всех конечных точек кластера, связанных с конечной точкой по умолчанию:

$ etcdctl defrag --cluster
Finished defragmenting etcd member[http://127.0.0.1:2379]
Finished defragmenting etcd member[http://127.0.0.1:22379]
Finished defragmenting etcd member[http://127.0.0.1:32379]

Чтобы напрямую дефрагментировать каталог данных etcd при остановленном etcd, используйте команду:

etcdutl defrag --data-dir <path-to-etcd-data-dir>

Квота дискового пространства

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

По умолчанию etcd задаёт консервативную квоту дискового пространства, подходящую большинству приложений, однако в командной строке её можно указать в байтах:

# set a very small 16 MiB quota
$ etcd --quota-backend-bytes=$((16*1024*1024))

Квоту дискового пространства можно активировать с помощью цикла:

# fill keyspace
$ while [ 1 ]; do dd if=/dev/urandom bs=1024 count=1024  | ETCDCTL_API=3 etcdctl put key  || break; done
...
Error:  rpc error: code = 8 desc = etcdserver: mvcc: database space exceeded
# confirm quota space is exceeded
$ ETCDCTL_API=3 etcdctl --write-out=table endpoint status
+----------------+------------------+-----------+---------+-----------+-----------+------------+
|    ENDPOINT    |        ID        |  VERSION  | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
| 127.0.0.1:2379 | bf9071f4639c75cc | 2.3.0+git | 18 MB   | true      |         2 |       3332 |
+----------------+------------------+-----------+---------+-----------+-----------+------------+
# confirm alarm is raised
$ ETCDCTL_API=3 etcdctl alarm list
memberID:13803658152347727308 alarm:NOSPACE

Удаление избыточных данных пространства ключей и дефрагментация базы данных бэкенда вернут кластер в пределы квоты:

# get current revision
$ rev=$(ETCDCTL_API=3 etcdctl --endpoints=:2379 endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')
# compact away all old revisions
$ ETCDCTL_API=3 etcdctl compact $rev
compacted revision 1516
# defragment away excessive space
$ ETCDCTL_API=3 etcdctl defrag
Finished defragmenting etcd member[127.0.0.1:2379]
# disarm alarm
$ ETCDCTL_API=3 etcdctl alarm disarm
memberID:13803658152347727308 alarm:NOSPACE
# test puts are allowed again
$ ETCDCTL_API=3 etcdctl put newkey 123
OK

Метрика etcd_mvcc_db_total_size_in_use_in_bytes показывает фактическое использование базы данных после компактизации истории, а etcd_debugging_mvcc_db_total_size_in_bytes — размер базы данных с учётом свободного места, ожидающего дефрагментации. Вторая метрика увеличивается только тогда, когда первая приближается к ней; следовательно, когда обе метрики близки к квоте, необходимо компактизировать историю, чтобы избежать активации квоты дискового пространства.

Начиная с v3.4, etcd_debugging_mvcc_db_total_size_in_bytes переименована в etcd_mvcc_db_total_size_in_bytes.

Предупреждение

Для запроса Put/Txn/LeaseGrant можно получить ошибку ErrGRPCNoSpace, хотя запись в бэкенде окажется успешной. Это возможно потому, что etcd проверяет квоту дискового пространства на уровне API и на внутреннем уровне Apply, причём уровень Apply только активирует аварийный сигнал NOSPACE, не блокируя выполнение транзакции.

Резервное копирование снимка

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

Снимок создаётся с помощью etcdctl:

$ etcdctl snapshot save backup.db
$ etcdutl --write-out=table snapshot status backup.db
+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| fe01cf57 |       10 |          7 | 2.1 MB     |
+----------+----------+------------+------------+