Spec-Zone.ru › CouchDB 3.5

Управление шардами

Введение

В этом документе рассказывается о работе шардинга в CouchDB, а также о том, как безопасно добавлять, перемещать и удалять шарды и создавать правила их размещения и размещения реплик.

Шард — это горизонтальный раздел базы данных. Разделение данных на шарды и распределение копий каждого шарда (называемых «репликами шардов» или просто «репликами») по разным узлам кластера повышает устойчивость данных к потере узлов. Кластеры CouchDB автоматически разбивают базы данных на шарды и распределяют подмножества документов, из которых состоит каждый шард, между узлами. Изменение состава кластера и поведения шардинга необходимо выполнять вручную.

Шарды и реплики

Количество шардов и реплик для каждой базы данных можно задать на глобальном уровне или отдельно для каждой базы данных. Соответствующие параметры: q и n.

q — количество шардов базы данных, которые необходимо поддерживать. n — количество копий каждого документа для распределения. Значение по умолчанию для n — 3, а для q — 2. При значении q=2 база данных разделяется на 2 шарда. При значении n=3 кластер распределяет по три реплики каждого шарда. В общей сложности для одной базы данных получается 6 реплик шардов.

В кластере из 3 узлов с q=8 каждый узел получит 8 шардов. В кластере из 4 узлов каждый узел получит 6 шардов. В общем случае мы рекомендуем, чтобы количество узлов в кластере было кратно n, чтобы шарды распределялись равномерно.

В узлах CouchDB есть файл etc/default.ini с разделом cluster, который выглядит так:

[cluster]
q=2
n=3

Эти настройки задают параметры шардинга по умолчанию для новых баз данных. Их можно переопределить в файле etc/local.ini, скопировав приведённый выше текст и заменив значения новыми значениями по умолчанию. Если задано [couch_peruser] q, это значение используется для пользовательских баз данных. (По умолчанию оно равно 1, поскольку предполагается, что пользовательские базы данных будут небольшими и их будет много.) Значения также можно задать отдельно для каждой базы данных, указав параметры запроса q и n при создании базы данных. Например:

$ curl -X PUT "$COUCH_URL:5984/database-name?q=4&n=2"

Эта команда создаёт базу данных, разделённую на 4 шарда и 2 реплики, то есть 8 реплик шардов, распределённых по кластеру.

Кворум

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

Каждый запрос, поступающий в кластер CouchDB, обрабатывается одним случайно выбранным координирующим узлом. Этот узел перенаправляет запрос другим узлам, у которых есть нужные данные; это может быть как сам координирующий узел, так и другие узлы. Координирующий узел отправляет ответ клиенту после получения ответов от кворума узлов базы данных; по умолчанию кворум равен 2. Размер кворума по умолчанию равен r=w=((n div 2) + 1), где r обозначает размер кворума чтения, w — размер кворума записи, n — количество реплик каждого шарда, а div означает целочисленное деление с округлением вниз. В кластере с настройками по умолчанию, где n равно 3, ((n div 2) + 1) будет равно 2.

Примечание

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

Размер требуемого кворума можно настроить во время выполнения запроса, задав параметр r для чтения документов и параметр w для записи документов. Эндпоинты _view, _find и _search читают только одну копию независимо от настроенного кворума, фактически устанавливая кворум 1 для этих запросов.

Например, этот запрос указывает координирующему узлу отправить ответ, когда ответят как минимум два узла:

$ curl "$COUCH_URL:5984/{db}/{doc}?r=2"

Похожий пример для записи документа:

$ curl -X PUT "$COUCH_URL:5984/{db}/{doc}?w=2" -d '{...}'

Если задать для r или w значение, равное n (количеству реплик), ответ будет получен только после того, как ответят все узлы с нужными шардами или истечёт время ожидания. Такой подход не гарантирует согласованность ACID. Если задать для r или w значение 1, ответ будет получен после ответа только одного подходящего узла.

Просмотр шардов базы данных

Есть несколько эндпоинтов API, которые помогают понять, как база данных разделена на шарды. Для начала создадим базу данных в кластере и добавим в неё несколько документов:

$ curl -X PUT $COUCH_URL:5984/mydb
{"ok":true}
$ curl -X PUT $COUCH_URL:5984/mydb/joan -d '{"loves":"cats"}'
{"ok":true,"id":"joan","rev":"1-cc240d66a894a7ee7ad3160e69f9051f"}
$ curl -X PUT $COUCH_URL:5984/mydb/robert -d '{"loves":"dogs"}'
{"ok":true,"id":"robert","rev":"1-4032b428c7574a85bc04f1f271be446e"}

Сначала эндпоинт верхнего уровня /{db} сообщит параметры шардинга базы данных:

$ curl -s $COUCH_URL:5984/db | jq .
{
  "db_name": "mydb",
...
  "cluster": {
    "q": 8,
    "n": 3,
    "w": 2,
    "r": 2
  },
...
}

Итак, мы знаем, что эта база данных была создана с 8 шардами (q=8), и у каждого шарда есть 3 реплики (n=3), то есть всего 24 реплики шардов на узлах кластера.

Теперь посмотрим, как эти реплики шардов размещены в кластере, с помощью эндпоинта /{db}/_shards:

$ curl -s $COUCH_URL:5984/mydb/_shards | jq .
{
  "shards": {
    "00000000-1fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node4@127.0.0.1"
    ],
    "20000000-3fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ],
    "40000000-5fffffff": [
      "node2@127.0.0.1",
      "node3@127.0.0.1",
      "node4@127.0.0.1"
    ],
    "60000000-7fffffff": [
      "node1@127.0.0.1",
      "node3@127.0.0.1",
      "node4@127.0.0.1"
    ],
    "80000000-9fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node4@127.0.0.1"
    ],
    "a0000000-bfffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ],
    "c0000000-dfffffff": [
      "node2@127.0.0.1",
      "node3@127.0.0.1",
      "node4@127.0.0.1"
    ],
    "e0000000-ffffffff": [
      "node1@127.0.0.1",
      "node3@127.0.0.1",
      "node4@127.0.0.1"
    ]
  }
}

Теперь мы видим, что в кластере на самом деле 4 узла и CouchDB равномерно распределила между ними все 24 реплики шардов.

С помощью эндпоинта /{db}/_shards/{docid} также можно точно определить, в каком шарде находится заданный документ:

$ curl -s $COUCH_URL:5984/mydb/_shards/joan | jq .
{
  "range": "e0000000-ffffffff",
  "nodes": [
    "node1@127.0.0.1",
    "node3@127.0.0.1",
    "node4@127.0.0.1"
  ]
}
$ curl -s $COUCH_URL:5984/mydb/_shards/robert | jq .
{
  "range": "60000000-7fffffff",
  "nodes": [
    "node1@127.0.0.1",
    "node3@127.0.0.1",
    "node4@127.0.0.1"
  ]
}

CouchDB показывает конкретный шард, которому сопоставлен каждый из двух примеров документов.

Перемещение шарда

При перемещении шардов и выполнении других операций с шардами в кластере рекомендуется остановить все задания перераспределения шардов. Подробнее см. в разделе Остановка заданий перераспределения шардов.

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

Рассмотрим кластер из трёх узлов с q=8 и n=3. В каждой базе данных 24 шарда, распределённых между тремя узлами. Если вы добавите в кластер четвёртый узел, CouchDB не перераспределит на него шарды существующих баз данных. Это приведёт к неравномерной нагрузке: новый узел будет хранить только шарды баз данных, созданных после его присоединения к кластеру. Чтобы сбалансировать распределение шардов существующих баз данных, их необходимо переместить вручную.

Перемещение шардов между узлами кластера состоит из следующих шагов:

  1. Убедитесь, что целевой узел присоединился к кластеру.

  2. Скопируйте шарды и все вторичные индексы шардов на целевой узел.

  3. Переведите целевой узел в режим обслуживания.

  4. Обновите метаданные кластера, указав новые целевые шарды.

  5. Следите за внутренней репликацией, чтобы убедиться, что шарды актуальны.

  6. Отключите режим обслуживания целевого узла.

  7. Снова обновите метаданные кластера, удалив исходные шарды

  8. Удалите файлы шардов и файлы вторичных индексов на исходном узле.

Копирование файлов шардов

Примечание

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

Файлы шардов находятся в каталоге data/shards установки CouchDB. В его подкаталогах расположены сами файлы шардов. Например, для базы данных q=8 с именем abc файлы шардов базы данных выглядят так:

data/shards/00000000-1fffffff/abc.1529362187.couch
data/shards/20000000-3fffffff/abc.1529362187.couch
data/shards/40000000-5fffffff/abc.1529362187.couch
data/shards/60000000-7fffffff/abc.1529362187.couch
data/shards/80000000-9fffffff/abc.1529362187.couch
data/shards/a0000000-bfffffff/abc.1529362187.couch
data/shards/c0000000-dfffffff/abc.1529362187.couch
data/shards/e0000000-ffffffff/abc.1529362187.couch

Вторичные индексы (в том числе представления JavaScript, представления Erlang и индексы Mango) также разбиты на шарды. Их следует переместить, чтобы новому узлу не пришлось перестраивать представление. Шарды представлений находятся в data/.shards. Например:

data/.shards
data/.shards/e0000000-ffffffff/_replicator.1518451591_design
data/.shards/e0000000-ffffffff/_replicator.1518451591_design/mrview
data/.shards/e0000000-ffffffff/_replicator.1518451591_design/mrview/3e823c2a4383ac0c18d4e574135a5b08.view
data/.shards/c0000000-dfffffff
data/.shards/c0000000-dfffffff/_replicator.1518451591_design
data/.shards/c0000000-dfffffff/_replicator.1518451591_design/mrview
data/.shards/c0000000-dfffffff/_replicator.1518451591_design/mrview/3e823c2a4383ac0c18d4e574135a5b08.view
...

Поскольку это файлы, для их копирования с одного узла на другой можно использовать cp, rsync, scp или другую команду копирования файлов. Например:

# one one machine
$ mkdir -p data/.shards/{range}
$ mkdir -p data/shards/{range}
# on the other
$ scp {couch-dir}/data/.shards/{range}/{database}.{datecode}* \
  {node}:{couch-dir}/data/.shards/{range}/
$ scp {couch-dir}/data/shards/{range}/{database}.{datecode}.couch \
  {node}:{couch-dir}/data/shards/{range}/

Примечание

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

Перевод целевого узла в режим обслуживания true

Прежде чем сообщать CouchDB о новых шардах на узле, его необходимо перевести в режим обслуживания. В этом режиме CouchDB возвращает ответ 404 Not Found для эндпоинта /_up и не позволяет узлу участвовать в обычных интерактивных кластерных запросах к его шардам. Правильно настроенный балансировщик нагрузки, который проверяет состояние узлов с помощью GET /_up, обнаружит ответ 404 и исключит узел из пула, не позволяя направлять на него запросы. Например, чтобы настроить HAProxy на использование эндпоинта /_up, укажите:

http-check disable-on-404
option httpchk GET /_up

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

Чтобы включить режим обслуживания:

$ curl -X PUT -H "Content-type: application/json" \
    $COUCH_URL:5984/_node/{node-name}/_config/couchdb/maintenance_mode \
    -d "\"true\""

Затем убедитесь, что узел находится в режиме обслуживания, выполнив запрос GET /_up к индивидуальному эндпоинту этого узла:

$ curl -v $COUCH_URL/_up
…
< HTTP/1.1 404 Object Not Found
…
{"status":"maintenance_mode"}

В завершение убедитесь, что балансировщик нагрузки исключил узел из пула доступных серверов.

Обновление метаданных кластера с учётом новых целевых шардов

Теперь нужно сообщить CouchDB, что целевой узел (который уже должен быть присоединён к кластеру) должен хранить реплики шардов указанной базы данных.

Чтобы обновить метаданные кластера, используйте специальную базу данных /_dbs — внутреннюю базу данных CouchDB, которая сопоставляет базы данных шардам и узлам. Эта база данных автоматически реплицируется между узлами. Доступ к ней возможен только через специальный эндпоинт /_node/_local/_dbs.

Сначала получите текущие метаданные базы данных:

$ curl http://adm:pass@localhost:5984/_node/_local/_dbs/{name}
{
  "_id": "{name}",
  "_rev": "1-e13fb7e79af3b3107ed62925058bfa3a",
  "shard_suffix": [46, 49, 53, 51, 48, 50, 51, 50, 53, 50, 54],
  "changelog": [
    ["add", "00000000-1fffffff", "node1@xxx.xxx.xxx.xxx"],
    ["add", "00000000-1fffffff", "node2@xxx.xxx.xxx.xxx"],
    ["add", "00000000-1fffffff", "node3@xxx.xxx.xxx.xxx"],
    …
  ],
  "by_node": {
    "node1@xxx.xxx.xxx.xxx": [
      "00000000-1fffffff",
      …
    ],
    …
  },
  "by_range": {
    "00000000-1fffffff": [
      "node1@xxx.xxx.xxx.xxx",
      "node2@xxx.xxx.xxx.xxx",
      "node3@xxx.xxx.xxx.xxx"
    ],
    …
  }
}

Краткое описание структуры этого документа:

  • _id: имя базы данных.

  • _rev: текущая ревизия метаданных.

  • shard_suffix: отметка времени создания базы данных в секундах с начала эпохи Unix, представленная кодовыми точками ASCII-цифр.

  • changelog: история шардов базы данных.

  • by_node: список шардов на каждом узле.

  • by_range: узлы, на которых находится каждый шард.

Чтобы отразить перемещение шарда в метаданных, выполните три шага:

  1. Добавьте соответствующие записи в журнал изменений.

  2. Обновите записи by_node.

  3. Обновите записи by_range.

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

Будьте предельно осторожны! Ошибки в этом процессе могут привести к необратимому повреждению кластера!

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

Чтобы добавить шард на узел, добавьте в атрибут changelog метаданных базы данных записи следующего вида:

["add", "{range}", "{node-name}"]

{range} — это конкретный диапазон шарда. Значение {node-name} должно соответствовать имени и адресу узла, отображаемым в GET /_membership кластера.

Примечание

При удалении шарда с узла укажите remove вместо add.

Определив новые записи журнала изменений, обновите by_node и by_range, чтобы указать, кто хранит какие шарды. Данные в записях журнала изменений и этих атрибутах должны совпадать. В противном случае база данных может быть повреждена.

Продолжая наш пример, ниже приведена обновлённая версия метаданных выше, в которой шарды добавлены на дополнительный узел с именем node4:

{
  "_id": "{name}",
  "_rev": "1-e13fb7e79af3b3107ed62925058bfa3a",
  "shard_suffix": [46, 49, 53, 51, 48, 50, 51, 50, 53, 50, 54],
  "changelog": [
    ["add", "00000000-1fffffff", "node1@xxx.xxx.xxx.xxx"],
    ["add", "00000000-1fffffff", "node2@xxx.xxx.xxx.xxx"],
    ["add", "00000000-1fffffff", "node3@xxx.xxx.xxx.xxx"],
    ...
    ["add", "00000000-1fffffff", "node4@xxx.xxx.xxx.xxx"]
  ],
  "by_node": {
    "node1@xxx.xxx.xxx.xxx": [
      "00000000-1fffffff",
      ...
    ],
    ...
    "node4@xxx.xxx.xxx.xxx": [
      "00000000-1fffffff"
    ]
  },
  "by_range": {
    "00000000-1fffffff": [
      "node1@xxx.xxx.xxx.xxx",
      "node2@xxx.xxx.xxx.xxx",
      "node3@xxx.xxx.xxx.xxx",
      "node4@xxx.xxx.xxx.xxx"
    ],
    ...
  }
}

Теперь можно PUT эти новые метаданные:

$ curl -X PUT http://adm:pass@localhost:5984/_node/_local/_dbs/{name} -d '{...}'

Принудительная синхронизация шардов

Добавлено в версии 2.4.0.

Скопировали ли вы шарды на новый узел заранее или нет, можно принудительно синхронизировать все реплики всех шардов базы данных с помощью эндпоинта /{db}/_sync_shards:

$ curl -X POST $COUCH_URL:5984/{db}/_sync_shards
{"ok":true}

Это запустит процесс синхронизации. Обратите внимание, что он увеличит нагрузку на кластер, что может повлиять на производительность.

Также можно принудительно синхронизировать отдельный шард, записав документ, который хранится в этом шарде.

Примечание

На время синхронизации шардов администраторам может потребоваться увеличить значение [mem3] sync_concurrency.

Контроль внутренней репликации для проверки актуальности шардов

После выполнения предыдущего шага CouchDB начнёт синхронизацию шардов. За этим процессом можно наблюдать, отслеживая эндпоинт /_node/{node-name}/_system, который включает метрику internal_replication_jobs.

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

Отключение режима обслуживания целевого узла

Теперь можно разрешить узлу обрабатывать запросы данных, установив для "false" режим обслуживания через эндпоинт конфигурации, как на шаге 2.

Убедитесь, что узел не находится в режиме обслуживания, выполнив запрос GET /_up к индивидуальному эндпоинту этого узла.

В завершение убедитесь, что балансировщик нагрузки вернул узел в пул доступных серверов.

Повторное обновление метаданных кластера для удаления исходного шарда

Теперь удалите исходный шард из карты шардов тем же способом, которым на шаге 2 добавили в неё новый целевой шард. Не забудьте добавить запись ["remove", {range}, {source-shard}] в конец журнала изменений и изменить разделы by_node и by_range документа метаданных базы данных.

Удаление файлов шарда и вторичных индексов с исходного узла

Наконец, можно удалить исходную реплику шарда, удалив её файл из командной строки на исходном узле, а также любые реплики шардов представлений:

$ rm {couch-dir}/data/shards/{range}/{db}.{datecode}.couch
$ rm -r {couch-dir}/data/.shards/{range}/{db}.{datecode}*

Поздравляем! Вы переместили реплику шарда базы данных. Добавляя и удаляя таким образом реплики шардов базы данных, можно менять структуру шардов кластера, также называемую картой шардов.

Настройка размещения базы данных

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

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

Параметр placement переопределяет параметр n как в файле .ini, так и при указании в URL.

Сначала каждому узлу необходимо присвоить атрибут зоны. Он определяет, к какой зоне относится узел. Для этого отредактируйте документ узла в специальной базе данных /_nodes, доступной через специальный локальный для узла эндпоинт API /_node/_local/_nodes/{node-name}. Добавьте пару «ключ-значение» следующего вида:

"zone": "{zone-name}"

Повторите эти действия для всех узлов кластера. Например:

$ curl -X PUT http://adm:pass@localhost:5984/_node/_local/_nodes/{node-name} \
    -d '{ \
        "_id": "{node-name}",
        "_rev": "{rev}",
        "zone": "{zone-name}"
        }'

В качестве альтернативы можно задать на каждом узле переменную среды COUCHDB_ZONE, и CouchDB настроит этот документ при запуске.

В локальном файле конфигурации (local.ini) каждого узла задайте согласованную настройку для всего кластера, например:

[cluster]
placement = {zone-name-1}:2,{zone-name-2}:1

В этом примере CouchDB разместит две реплики шарда на узлах с атрибутом зоны {zone-name-1}, а одну реплику — на новом узле с атрибутом зоны {zone-name-2}.

Этот подход гибок: можно также задавать зоны отдельно для каждой базы данных, указывая настройку размещения в качестве параметра запроса при создании базы данных и используя тот же синтаксис, что и в ini-файле:

curl -X PUT $COUCH_URL:5984/{db}?placement={zone}

Также можно указать аргумент placement. Обратите внимание: это переопределит логику, определяющую количество создаваемых реплик!

Эту систему также можно использовать, чтобы запретить размещение реплик новых баз данных на определённых узлах кластера: для этого задайте им атрибут зоны, отсутствующий в строке размещения [cluster].

Разделение шардов

Эндпоинт /_reshard — это HTTP API для работы с шардами. В настоящее время он поддерживает только разделение шардов. Инструкции по объединению шардов см. в описании ручного процесса в разделе Объединение шардов.

Основной способ работы с /_reshard — создание заданий перераспределения шардов, наблюдение за ними, ожидание их завершения, удаление, создание новых заданий и так далее. Ниже приведены несколько шагов, которые можно выполнить для разделения шардов с помощью этого API.

Для начала полезно вызвать GET /_reshard, чтобы получить сводку о перераспределении шардов в кластере.

$ curl -s $COUCH_URL:5984/_reshard | jq .
{
  "state": "running",
  "state_reason": null,
  "completed": 3,
  "failed": 0,
  "running": 0,
  "stopped": 0,
  "total": 3
}

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

Поле state показывает состояние перераспределения шардов в кластере. Обычно оно равно running, однако другой пользователь мог временно отключить перераспределение. В этом случае состояние будет stopped, и, будем надеяться, в значении поля state_reason будет указана причина или комментарий. Подробнее см. в разделе Остановка заданий перераспределения шардов.

Важно следить за количеством заданий total, поскольку для каждого узла установлено максимальное количество заданий перераспределения шардов. Создание новых заданий после достижения этого ограничения приведёт к ошибке. Перед запуском новых заданий рекомендуется удалить уже завершённые. Значение параметра max_jobs по умолчанию и инструкции по его изменению при необходимости см. в разделе конфигурации reshard.

Например, чтобы удалить все завершённые задания, выполните:

$ for jobid in $(curl -s $COUCH_URL:5984/_reshard/jobs | jq -r '.jobs[] | select (.job_state=="completed") | .id'); do \
      curl -s -XDELETE $COUCH_URL:5984/_reshard/jobs/$jobid \
  done

Затем рекомендуется посмотреть на карту шардов базы данных.

$ curl -s $COUCH_URL:5984/db1/_shards | jq '.'
{
  "shards": {
    "00000000-7fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ],
    "80000000-ffffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ]
  }
}

В этом примере мы разделим все копии диапазона 00000000-7fffffff. API позволяет комбинировать параметры: например, разделить все диапазоны на всех узлах, все диапазоны только на одном узле или один конкретный диапазон на одном конкретном узле. Для этого используются параметры задания db, node и range.

Чтобы разделить все копии 00000000-7fffffff, отправьте запрос следующего вида:

$ curl -s -H "Content-type: application/json" -XPOST $COUCH_URL:5984/_reshard/jobs \
  -d '{"type": "split", "db":"db1", "range":"00000000-7fffffff"}' | jq '.'
[
  {
    "ok": true,
    "id": "001-ef512cfb502a1c6079fe17e9dfd5d6a2befcc694a146de468b1ba5339ba1d134",
    "node": "node1@127.0.0.1",
    "shard": "shards/00000000-7fffffff/db1.1554242778"
  },
  {
    "ok": true,
    "id": "001-cec63704a7b33c6da8263211db9a5c74a1cb585d1b1a24eb946483e2075739ca",
    "node": "node2@127.0.0.1",
    "shard": "shards/00000000-7fffffff/db1.1554242778"
  },
  {
    "ok": true,
    "id": "001-fc72090c006d9b059d4acd99e3be9bb73e986d60ca3edede3cb74cc01ccd1456",
    "node": "node3@127.0.0.1",
    "shard": "shards/00000000-7fffffff/db1.1554242778"
  }
]

В ответе на запрос возвращены три задания — по одному для каждой из трёх копий.

Чтобы проверить ход выполнения заданий, используйте GET /_reshard/jobs или GET /_reshard/jobs/{jobid}.

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

$ curl -s $COUCH_URL:5984/db1/_shards | jq '.'
{
  "shards": {
    "00000000-3fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ],
    "40000000-7fffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ],
    "80000000-ffffffff": [
      "node1@127.0.0.1",
      "node2@127.0.0.1",
      "node3@127.0.0.1"
    ]
  }
}

Остановка заданий перераспределения шардов

Перераспределение шардов на уровне кластера можно остановить, а затем возобновить. Это полезно, чтобы внешние инструменты, изменяющие карту шардов, не мешали заданиям перераспределения. Чтобы остановить все задания перераспределения шардов в кластере, отправьте запрос PUT к эндпоинту /_reshard/state с ключом и значением "state": "stopped". При остановке также можно указать необязательное примечание или причину.

Например:

$ curl -s -H "Content-type: application/json" \
  -XPUT $COUCH_URL:5984/_reshard/state \
  -d '{"state": "stopped", "reason":"Moving some shards"}'
{"ok": true}

Это состояние отобразится в глобальной сводке:

$ curl -s $COUCH_URL:5984/_reshard | jq .
{
  "state": "stopped",
  "state_reason": "Moving some shards",
  "completed": 74,
  "failed": 0,
  "running": 0,
  "stopped": 0,
  "total": 74
}

Чтобы возобновить работу, отправьте запрос PUT, как в примере выше, указав состояние running. Все задания разделения шардов должны продолжиться с последней контрольной точки.

Подробнее см. в справочнике API: /_reshard.

Объединение шардов

Значение q для базы данных можно задать при её создании или увеличить позднее, разделив некоторые шарды, как описано в разделе Разделение шардов. Чтобы уменьшить q и объединить несколько шардов, необходимо создать базу данных заново. Выполните следующие шаги:

  1. Если в кластере выполняются задания разделения шардов, остановите их через HTTP API, как описано в разделе Остановка заданий перераспределения шардов.

  2. Создайте временную базу данных с нужными настройками шардов, указав значение q в качестве параметра запроса при выполнении операции PUT.

  3. Запретите клиентам доступ к базе данных.

  4. Реплицируйте основную базу данных во временную. Если основная база данных активно используется, может потребоваться выполнить репликацию несколько раз.

  5. Удалите основную базу данных. Убедитесь, что никто её не использует!

  6. Создайте основную базу данных заново с нужными настройками шардов.

  7. Теперь клиенты снова могут обращаться к базе данных.

  8. Реплицируйте данные из временной базы обратно в основную.

  9. Удалите временную базу данных.

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

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

Copyright © 2025 The Apache Software Foundation — Licensed under the Apache License 2.0
https://docs.couchdb.org/en/3.5.1/cluster/sharding.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API