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

S3R

В данном разделе приведены сведения о S3R, плагине объектного хранилища для СУБД Picodata. Это же руководство поставляется вместе со сборкой плагина.

Picodata Enterprise

Функциональность плагина доступна только в коммерческой версии Picodata.

О документе

Документ описывает установку, настройку и эксплуатацию плагина S3R. Плагин реализует объектное хранилище с интерфейсом, совместимым с Amazon S3, и работает внутри СУБД Picodata.

Документ описывает текущее состояние плагина. Полный перечень неподдерживаемых возможностей приведён в главе «Ограничения».

Команды ALTER PLUGIN в документе приведены для версии плагина 2.0.0. Установленную версию показывает запрос SELECT name, version FROM _pico_plugin.

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

Назначение и устройство

Что представляет собой S3R

Плагин S3R хранит метаданные объектного хранилища (бакеты, объекты, каталоги и карту размещения) в таблицах Picodata двух видов. Глобальные таблицы реплицируются через Raft-консенсус, а шардированные таблицы распределяются по репликасетам средствами vshard. Содержимое объектов размещается на локальных дисках узлов в журнально-структурированном хранилище блоков и защищается репликацией либо избыточным кодированием Рида-Соломона.

Архитектура плагина обеспечивает три свойства.

Согласованность. Отдельный слой метаданных с отложенной согласованностью и внешние хранилища, например etcd или RocksDB, не используются. Бакеты и карта размещения хранятся в глобальных таблицах и согласуются через Raft-консенсус, а метаданные каждого объекта размещаются в одном шарде vshard. При значении read_consistency = strong, которое действует по умолчанию, операции с одним ключом линеаризуемы, и успешно записанные данные сразу доступны для чтения. Значение eventual разрешает чтение с реплики, и результат такого чтения может быть устаревшим.

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

Скорость обработки малых объектов. Объект размером до inline_max хранится в строке своих метаданных. При движке memtx, который действует по умолчанию, чтение такого объекта не обращается к диску и выполняется в оперативной памяти.

Состав плагина

Плагин состоит из трёх сервисов, которые назначаются на один и тот же тир Picodata.

Сервис Назначение
s3r_api Приём запросов S3: разбор HTTP, проверка подписи SigV4, авторизация, разбиение объекта на блоки, кодирование и сборка блоков
s3r_meta Операции над таблицами пространства имён и передача обращений от среды выполнения Tokio транзакционному потоку TX
s3r_storage Хранилище блоков на локальных дисках, регистрация дисков в кластере, обмен фрагментами блоков между узлами, ведение карты размещения

Размещение сервисов и данных в кластере показано на схеме:

Устройство кластера S3R

Сервисы запускаются независимо друг от друга и в произвольном порядке. Пока сервис s3r_meta на инстансе не запущен, конечная точка S3 этого инстанса отвечает на запросы ошибкой ServiceUnavailable.

Примечание

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

Путь запроса на запись

Объект размером больше inline_max записывается в следующем порядке.

  1. Сервис s3r_api принимает тело запроса и проверяет подпись.
  2. Объект разбивается на блоки размером block_bytes, заданным для выбранной группы размещения.
  3. В зависимости от класса хранения каждый блок кодируется в k фрагментов данных и m фрагментов чётности либо копируется R раз.
  4. Фрагменты передаются на диски группы размещения по протоколу HTTP/2. Единица передачи совпадает с единицей записи на диск.
  5. Блок считается записанным, когда его фрагменты приняли и сохранили не менее k + m − write_tolerance дисков и не менее k дисков. Непринятые фрагменты заносятся в очередь дозаписи.
  6. После записи всех блоков в пространстве имён создаётся строка объекта.

Путь запроса на запись

Метаданные фиксируются только после записи данных.

Кворум записи

Параметр write_tolerance сервиса s3r_storage задаёт число фрагментов блока, которые запись вправе оставить недописанными. Значение по умолчанию равно 1.

Значение 1 допускает недоступность одного участника группы: отказ диска либо, если группа распределена по дискам разных инстансов, отказ одного инстанса. Группа, собранная из дисков одного инстанса, при отказе этого инстанса недоступна целиком (см. «Схема избыточности»). При значении 0 для записи требуются все фрагменты, и недоступность одного участника приводит к отказу каждой записи в группу.

Кворум записи не опускается ниже k. Блок из k фрагментов доступен для чтения, но потеря ещё одного фрагмента сделает чтение невозможным. Блок, у которого сохранилось от k + 1 до k + m фрагментов, остаётся доступным для чтения при ещё одном отказе, пока недостающие фрагменты восстанавливаются. Значение write_tolerance больше m не отклоняется, и кворум в этом случае равен k.

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

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

Состояние очереди дозаписи показывает запрос:

SELECT object_id, slot, pg_id FROM s3r_shortfall;

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

Чтение выполняется в обратном порядке. Строка объекта содержит идентификатор группы размещения и размер объекта. По ним вычисляется геометрия блоков, после чего запрашиваются блоки, попадающие в запрошенный диапазон.

Требования

Компонент Требование
СУБД Picodata той версии, под которую выпущена версия плагина; см. «Соответствие версий S3R и Picodata». При несовпадении версий плагин не загружается и выводит обе версии
Ядро Linux 5.10 или новее
Подсистема ввода-вывода io_uring и открытие файлов с флагом O_DIRECT. Резервная реализация отсутствует: при недоступности этих механизмов диск не монтируется, и событие фиксируется в журнале
Файловая система Локальная, с поддержкой O_DIRECT и posix_fallocate

Окружение контейнера проверяется отдельно. Профиль seccomp может запрещать системные вызовы io_uring, а оверлейная файловая система может запрещать открытие файлов с флагом O_DIRECT. Эти причины независимы, и отказ одного механизма не означает отказа другого.

Сборки плагина поставляются для следующих операционных систем:

  • Альт 10 (ALT p10) и Альт p11;
  • Astra Linux Special Edition 1.8;
  • РЕД ОС 8;
  • CentOS 8 и CentOS Stream 9;
  • Debian 11 и Debian 13;
  • Fedora 43 и Fedora 44;
  • Ubuntu 22.04, Ubuntu 24.04 и Ubuntu 26.04.

Требование к ядру действует для любой операционной системы из перечня.

Установка

Соответствие версий S3R и Picodata

Под каждую выпущенную версию Picodata собирается соответствующая выпущенная версия плагина.

S3R Picodata
2.0.0 26.2.1

Состав поставки

Репозиторий Picodata содержит архив плагина s3r_2.0.0-<ОС>.tar.gz для каждой операционной системы из перечня в главе «Требования». Доступ к репозиторию предоставляется по запросу.

Структура архива соответствует стандартной структуре плагина Picodata: каталог s3r/2.0.0/ содержит библиотеку libs3r.so, файл манифеста manifest.yaml и каталог миграций migrations/.

Расчёт ресурсов

Число инстансов

Инстанс Picodata с плагином S3R размещается в пределах одного узла NUMA, и на каждом узле NUMA сервера запускается не менее одного инстанса. Один инстанс обслуживает в секунду до 10 000 операций с метаданными: записей, чтений, запросов атрибутов и листингов. Необходимое число инстансов определяется делением ожидаемой нагрузки на это значение.

Процессорные ядра

Каждому инстансу выделяется 10 логических ядер процессора. Логическим ядром считается аппаратный поток, а не физическое ядро. Одно ядро занимает транзакционный поток TX, восемь ядер занимает пул рабочих потоков Tokio, в котором выполняются разбор запросов, кодирование, сжатие и обмен фрагментами блоков, и одно ядро остаётся для фоновых операций, например для создания снимков. Размер пула задаётся переменной окружения S3R_WORKER_THREADS=8. Без неё пул рассчитывается по числу ядер всего сервера, и при нескольких инстансах на сервере потоков запускается больше, чем ядер.

Оперативная память

Метаданные хранятся в памяти memtx. Объект, содержимое которого размещено на дисках, занимает в памяти около 320 байт вместе с индексами и, кроме того, столько байт, сколько занимает его ключ. Объект размером до inline_max дополнительно занимает объём своего содержимого. Например, 100 миллионов объектов с ключами длиной 80 байт требуют около 40 ГБ памяти. Этот объём необходим каждому инстансу репликасета, потому что каждая реплика хранит полную копию его данных.

Объём памяти под метаданные увеличивается двумя способами: добавлением узлов, между которыми распределяются шарды метаданных, либо увеличением параметра instance.memtx.memory.

Плагин устанавливается двумя способами: вручную, как описано в разделе «Пошаговая установка», либо ролью Ansible для Picodata, как описано в разделе «Установка ролью Ansible». В обоих случаях выполняются одни и те же действия.

Схема избыточности

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

Внимание

Если схема не выбрана, S3R хранит одну копию данных. Picodata по умолчанию создаёт тир с коэффициентом репликации 1, а без объявленных форм кодирования группа размещения состоит из одного диска. Отказ диска делает недоступными объекты крупнее inline_max, фрагменты которых хранились на этом диске. Отказ инстанса делает недоступными также метаданные его репликасета.

Уровни избыточности

Каждый уровень избыточности задаётся своими параметрами и защищает свою часть данных.

Уровень Параметры Защищаемые данные Отказ, который переживают данные
Инстанс failure_domain инстанса и replication_factor тира Picodata строки объектов и содержимое объектов размером до inline_max (по умолчанию 4 КиБ) отказ инстанса или узла
Диск поддомен диска hba= и формы s3r_storage.erasure содержимое объектов крупнее inline_max отказ дисков, число которых не больше m
Площадка компонент dc домена отказа инстанса копия каждого объекта на каждой площадке отказ площадки

Распределение данных по уровням для кластера из раздела «Пример: одна площадка» показано на схеме:

Уровни избыточности на одной площадке

Домены отказа Picodata и поддомены дисков описывают разные вещи. Домен отказа инстанса определяет, какие инстансы Picodata объединяет в репликасет. Поддомен диска определяет, какие диски одного инстанса могут хранить фрагменты одного блока.

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

Если домены отказа заданы, Picodata объединяет в репликасет только инстансы, домены отказа которых не совпадают ни в одном компоненте, а набор компонентов должен быть одинаковым у всех инстансов кластера. Компонент с одинаковым значением у всех инстансов, например dc: msk в кластере с одной площадкой, не позволяет собрать репликасет больше чем из одного инстанса. Поэтому на одной площадке домен отказа инстанса задаётся без компонента dc, например компонентом host, и все инстансы относятся к площадке default. На нескольких площадках репликасет содержит не более одного инстанса с каждой площадки, и коэффициент репликации не может превышать число площадок.

Группа размещения собирается из дисков одного инстанса, если у этого инстанса достаточно дисков для формы кодирования. По дискам разных инстансов группа распределяется, только когда ни у одного инстанса дисков недостаточно. Группа на дисках одного инстанса переживает отказ m дисков, но не отказ самого инстанса. Пока инстанс недоступен, не читается содержимое тех объектов крупнее inline_max, фрагменты которых находятся в его группах, хотя строки этих объектов доступны на других репликах. Копия объекта на другой площадке в этом случае для чтения не используется.

Пример: одна площадка

Кластер состоит из трёх узлов, на каждом из которых работает один инстанс с четырьмя дисками. Метаданные и объекты до inline_max хранятся в трёх копиях. Содержимое крупных объектов кодируется формой 2+2 и занимает на дисках вдвое больше своего объёма.

Конфигурация инстанса на node1:

cluster:
  tier:
    default:
      replication_factor: 3
      can_vote: true
instance:
  failure_domain:
    host: node1

Диски инстанса:

S3R_DISKS=/data/s3r/d0:hba=a,/data/s3r/d1:hba=b,/data/s3r/d2:hba=c,/data/s3r/d3:hba=d

Форма кодирования:

ALTER PLUGIN s3r 2.0.0 SET s3r_storage.erasure = '[{"k":2,"m":2}]';

Picodata собирает из трёх инстансов один репликасет, а плагин создаёт по одной группе 2+2 на дисках каждого инстанса.

Отказ Метаданные и объекты до inline_max Объекты крупнее inline_max
один диск доступны доступны: недостающие фрагменты вычисляются при чтении, а слот перестраивается на другом диске
два диска одного узла доступны доступны
узел доступны на двух других репликах объекты, фрагменты которых хранятся на этом узле, недоступны до его возвращения; остальные доступны

Пример: группы на дисках разных узлов

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

S3R_DISKS=/data/s3r/d0:hba=a

Ни один инстанс не может собрать группу 2+2 из своих дисков, поэтому каждая группа собирается из дисков четырёх инстансов на разных узлах. Picodata собирает из двенадцати инстансов четыре репликасета по три инстанса.

Группы размещения на дисках разных узлов

Отказ Метаданные и объекты до inline_max Объекты крупнее inline_max
один диск или один узел доступны на двух других репликах доступны: группа теряет одного участника из четырёх
два узла одной группы доступны на других репликах, если узлы входят в разные репликасеты доступны

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

Пример: несколько площадок

Кластер размещён на трёх площадках msk, spb и ekb. На каждой площадке находятся два узла, и на каждом узле работает один инстанс с четырьмя дисками. Компонент dc домена отказа задаёт площадку, а компонент host различает узлы.

Конфигурация инстанса на первом узле площадки msk:

cluster:
  tier:
    default:
      replication_factor: 3
      can_vote: true
instance:
  failure_domain:
    dc: msk
    host: msk1

Диски и форма кодирования задаются так же, как в примере с одной площадкой.

Picodata собирает два репликасета, в каждом из которых по одному инстансу с каждой площадки, и строки объектов хранятся на всех трёх площадках. Плагин создаёт группы 2+2 внутри каждой площадки, а каждая площадка хранит собственную закодированную копию содержимого. Кодирование не выходит за границу площадки, а копии между площадками передаются асинхронно фоновым процессом siterepl. Содержимое крупных объектов занимает на дисках в шесть раз больше своего объёма: вдвое на каждой из трёх площадок.

Отказ Метаданные и объекты до inline_max Объекты крупнее inline_max
один или два диска узла доступны доступны
узел доступны на репликах других площадок объекты, фрагменты которых хранятся на этом узле, недоступны клиентам его площадки до возвращения узла
площадка доступны на двух других площадках доступны на других площадках, если их копия успела перейти в состояние live

При двух площадках кворум Raft не переживает отказ площадки, на которой находится большинство голосующих инстансов. Для этого случая предусмотрен инстанс арбитра на третьей площадке, как описано в разделе «Установка ролью Ansible».

Пошаговая установка

В примерах кластер состоит из трёх узлов node1.example.netnode3.example.net, на каждом из которых работает один инстанс Picodata с четырьмя дисками. Схема избыточности соответствует разделу «Пример: одна площадка». Версия плагина в примерах 2.0.0, тир default.

Шаг 1. Проверка узлов

На каждом узле проверьте версию ядра:

uname -r

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

mkdir -p /data/s3r/d0
dd if=/dev/zero of=/data/s3r/d0/probe bs=4096 count=1 oflag=direct
rm /data/s3r/d0/probe

Если команда dd завершается ошибкой Invalid argument, файловая система не поддерживает O_DIRECT, и этот каталог диском хранилища служить не может.

Доступность io_uring проверяется при запуске плагина: диск, для которого механизм недоступен, не монтируется, и событие фиксируется в журнале. Результат виден на шаге 7.

Шаг 2. Размещение архива

На каждом узле распакуйте архив в каталог плагинов Picodata, заданный параметром instance.share_dir:

tar -xzf s3r_2.0.0-astra_1.8_x86-64.tar.gz -C /usr/share/picodata

В каталоге /usr/share/picodata/s3r/2.0.0/ должны появиться libs3r.so, manifest.yaml и migrations/. Имя каталога версии должно совпадать с версией, указанной в командах SQL на шаге 5.

Шаг 3. Конфигурация инстансов

В файл конфигурации каждого инстанса Picodata добавьте коэффициент репликации тира, домен отказа, каталог плагинов и слушатели двух сервисов плагина. Пример для node1:

cluster:
  tier:
    default:
      replication_factor: 3
      can_vote: true
instance:
  share_dir: /usr/share/picodata
  failure_domain:
    host: node1
  plugin:
    s3r:
      service:
        s3r_api:
          listener:
            enabled: true
            listen: "0.0.0.0:8443"
            tls:
              enabled: true
              cert_file: /etc/s3r/server.pem
              key_file:  /etc/s3r/server.key
        s3r_storage:
          listener:
            enabled: true
            listen: "0.0.0.0:8700"
            advertise: "node1.example.net:8700"
            tls:
              enabled: true
              cert_file: /etc/s3r/node1.pem
              key_file:  /etc/s3r/node1.key
              ca_file:   /etc/s3r/cluster-ca.pem

Параметры различаются от узла к узлу в трёх местах: компонент host домена отказа, адрес advertise и сертификат узла для внутрикластерного контура.

Коэффициент репликации тира применяется при первом запуске кластера и в дальнейшем не изменяется. Домен отказа не содержит компонента dc, потому что площадка одна: инстансы с одинаковым значением компонента не объединяются в репликасет (см. «Схема избыточности»).

Слушатель s3r_api принимает запросы S3 от клиентов. Слушатель s3r_storage служит для обмена фрагментами блоков между узлами; его порт должен быть недоступен клиентам. Для внутрикластерного контура параметр ca_file обязателен. Выпуск сертификатов и назначение каждого параметра описаны в главе «Шифрование трафика».

Диски хранилища задаются одним из двух способов. Если пути дисков совпадают на всех узлах, они задаются параметром плагина s3r_storage.disks на шаге 5. Если пути различаются, например при нескольких инстансах на одном узле, каждому инстансу задаётся переменная окружения S3R_DISKS:

S3R_DISKS=/data/s3r/d0:hba=a,/data/s3r/d1:hba=b,/data/s3r/d2:hba=c,/data/s3r/d3:hba=d

Свойство hba= задаёт поддомен отказа диска. Без него несколько дисков одного инстанса считаются одним доменом отказа, и группа размещения для кодирования на них не собирается. Формат переменной описан в разделе «Переменные окружения».

Объём памяти memtx задаётся параметром instance.memtx.memory, а размер пула рабочих потоков переменной окружения S3R_WORKER_THREADS. Значения обоих параметров рассчитываются по разделу «Расчёт ресурсов».

Шаг 4. Запуск кластера

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

picodata admin /var/run/picodata/node1.sock

Команды шагов 5 и 7 выполняются в этой консоли.

Шаг 5. Регистрация и включение плагина

Выполните команды SQL в указанном порядке:

CREATE PLUGIN s3r 2.0.0;

ALTER PLUGIN s3r 2.0.0 ADD SERVICE s3r_storage TO TIER default;
ALTER PLUGIN s3r 2.0.0 ADD SERVICE s3r_meta TO TIER default;
ALTER PLUGIN s3r 2.0.0 ADD SERVICE s3r_api TO TIER default;

ALTER PLUGIN s3r 2.0.0 SET migration_context.storage_tier = 'default';
ALTER PLUGIN s3r 2.0.0 SET migration_context.engine = 'memtx';
ALTER PLUGIN s3r 2.0.0 SET migration_context.unlogged = '';

ALTER PLUGIN s3r MIGRATE TO 2.0.0;

ALTER PLUGIN s3r 2.0.0 SET
  s3r_storage.disks = '[{"path":"/data/s3r/d0","failure_domain":"hba=a"},
                        {"path":"/data/s3r/d1","failure_domain":"hba=b"},
                        {"path":"/data/s3r/d2","failure_domain":"hba=c"},
                        {"path":"/data/s3r/d3","failure_domain":"hba=d"}]';
ALTER PLUGIN s3r 2.0.0 SET
  s3r_storage.erasure = '[{"k":2,"m":2}]';

ALTER PLUGIN s3r 2.0.0 ENABLE;

Порядок команд существенен. Сервисы назначаются на тир и контекст миграции задаётся до применения миграций, потому что имя тира и движок хранения подставляются в текст миграций. Диски задаются до включения плагина, потому что изменение списка дисков на работающем сервисе вступает в силу только при следующем запуске инстанса. Команду с s3r_storage.disks пропустите, если диски заданы переменной S3R_DISKS.

Все три сервиса назначаются на один тир. Разделение сервисов по разным тирам не поддерживается: сервис s3r_meta предоставляет конечной точке S3 на том же узле доступ к метаданным, фоновые процессы читают строки своего инстанса, а вызовы между сервисами рассчитаны на соседний сервис того же узла. Плагин проверяет совпадение списков тиров при запуске и не включается, если списки различаются. Имя тира выбирает оператор, и то же имя указывается в migration_context.storage_tier.

Форма кодирования k=2, m=2 собирается из четырёх дисков каждого инстанса с различными поддоменами hba=. Если формы кодирования не объявлены, объекты крупнее inline_max хранятся копиями, число которых равно коэффициенту репликации тира, и при коэффициенте 1 копия одна. Схема избыточности выбирается по разделу «Схема избыточности», а форма по разделу «Выбор формы кодирования».

Шаг 6. Проверка конечной точки

На любом узле проверьте, что конечная точка S3 отвечает:

curl --cacert /etc/s3r/ca.pem https://node1.example.net:8443/-/health

Примечание

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

Шаг 7. Проверка дисков и групп размещения

В административной консоли выполните запросы:

SELECT name, replication_factor FROM _pico_tier;

SELECT instance_name, path, failure_domain, tier, state FROM s3r_disk
 ORDER BY instance_name;

SELECT pg_id, site, tier, k, m, state FROM s3r_pg ORDER BY pg_id;

Коэффициент репликации тира должен совпадать с выбранной схемой избыточности. Каждый диск должен находиться в состоянии active, а каждая группа размещения в состоянии clean. Группа со значением m = 0 избыточности не имеет: отказ любого её диска делает недоступным содержимое хранящихся в ней объектов. Диск, отсутствующий в s3r_disk, не смонтирован; причина записана в журнале его инстанса. Если групп размещения нет, дисков или независимых доменов отказа недостаточно для объявленной формы кодирования.

Шаг 8. Учётные данные

Создайте пользователя Picodata и выдайте ему ключ доступа S3 начального арендатора:

CREATE USER "alice" WITH PASSWORD 'Str0ngPassw0rd' USING scram-sha256;

ALTER PLUGIN s3r 2.0.0 SET s3r_api.credentials =
  '[{"access_key":"AKIAEXAMPLE000000001","secret_key":"...","pico_user":"alice"}]';

Ключ доступа действителен, пока существует названный им пользователь. Выдача ключей другим арендаторам и смена ключей описаны в разделе «Учётные данные».

Шаг 9. Проверка работы

С рабочего места клиента выполните запись и чтение объекта через AWS CLI:

aws configure set aws_access_key_id AKIAEXAMPLE000000001
aws configure set aws_secret_access_key ...
aws configure set default.s3.addressing_style path

export AWS_CA_BUNDLE=/etc/s3r/ca.pem
aws --endpoint-url https://node1.example.net:8443 s3 mb s3://smoke-test
aws --endpoint-url https://node1.example.net:8443 s3 cp /etc/hostname s3://smoke-test/
aws --endpoint-url https://node1.example.net:8443 s3 ls s3://smoke-test/
aws --endpoint-url https://node1.example.net:8443 s3 rb --force s3://smoke-test

Установка завершена. Дальнейшая настройка описана в главах «Изоляция арендаторов», «Квоты и ограничение скорости» и «Первый вход в консоль управления».

Установка ролью Ansible

Роль Ansible для Picodata распаковывает архив плагина на узлы, выполняет команды SQL шага 5, применяет файл настроек плагина и включает плагин. В инвентарный файл добавляется блок plugins:

plugins:
  s3r:
    path: '../files/s3r_2.0.0-astra_1.8_x86-64.tar.gz'
    config: '../files/s3r-config.yml'
    services:
      s3r_storage:
        tiers:
          - default:
              listener:
                enabled: true
                listen: "0.0.0.0:87<INSTANCE_NUM>"
                advertise: "<INSTANCE_ADDR>:87<INSTANCE_NUM>"
      s3r_meta:
        tiers:
          - default
      s3r_api:
        tiers:
          - default:
              listener:
                enabled: true
                listen: "0.0.0.0:84<INSTANCE_NUM>"
    migration_context:
      storage_tier: 'default'
      engine: 'memtx'
      unlogged: ''

Литералы <INSTANCE_ADDR> и <INSTANCE_NUM> роль заменяет адресом узла и двузначным номером инстанса на узле. Разделы tls слушателей задаются так же, как на шаге 3; файлы сертификатов должны находиться на узлах до установки плагина.

Диски и размер пула рабочих потоков задаются переменными окружения в параметре extra_vars тира:

tiers:
  default:
    extra_vars:
      S3R_DISKS: '/data/s3r/i<INSTANCE_NUM>d0:hba=a,/data/s3r/i<INSTANCE_NUM>d1:hba=b'
      S3R_WORKER_THREADS: '8'

Файл настроек плагина s3r-config.yml содержит параметры сервисов:

s3r_api:
  credentials:
    - access_key: AKIAEXAMPLE000000001
      secret_key: "..."
      pico_user: alice
s3r_storage:
  erasure:
    - k: 2
      m: 2

Пользователь, указанный в pico_user, должен существовать до применения настроек. Его создание выполняется скриптом, заданным параметром роли sql_file_pre_plugins.

Для тира, на котором работает плагин, рекомендуются два параметра.

  • Синхронная репликация. Параметр replication_mode: sync делает репликацию внутри репликасета синхронной: запись подтверждается только после того, как её принял кворум реплик.
  • Запись журнала с синхронизацией. Вместе с синхронной репликацией задаётся wal_mode: fsync. Записи журнала Raft Picodata синхронизирует на диске независимо от этого параметра, а параметр защищает данные репликасета. При асинхронной репликации он пользы не даёт, потому что запись на реплику всё равно выполняется асинхронно.

Примечание

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

Инвентарный файл кластера из трёх серверов с плагином S3R
all:
  vars:
    ansible_user: root

    repo: 'https://download.picodata.io'  # репозиторий пакетов Picodata
    cluster_name: 'demo'
    admin_password: '<пароль администратора>'

    audit: false
    log_level: 'info'
    log_to: 'file'

    conf_dir: '/etc/picodata'
    data_dir: '/var/lib/picodata'
    run_dir: '/var/run/picodata'
    log_dir: '/var/log/picodata'
    share_dir: '/usr/share/picodata'  # каталог плагинов

    listen_address: '{{ ansible_fqdn }}'
    first_bin_port: 13301
    first_http_port: 18001
    first_pg_port: 15001

    sql_file_pre_plugins: files/sql_start.sql   # создание пользователей до установки плагина
    sql_file_post_plugins: files/sql_finish.sql # действия после установки плагина

    tiers:
      default:                  # тир хранилища S3R
        replicaset_count: 2
        replication_factor: 3
        can_vote: true
        replication_mode: sync
        wal_mode: fsync
        extra_vars:
          S3R_API_LISTEN: '0.0.0.0:80<INSTANCE_NUM>'
          S3R_DISKS: '/data/s3r/i<INSTANCE_NUM>'
          S3R_WORKER_THREADS: '8'
        config:
          memtx:
            memory: 16G         # по разделу «Расчёт ресурсов»

    plugins:
      s3r:
        path: '../plugins/s3r_2.0.0-ubuntu_24.04.tar.gz'
        services:
          s3r_storage:
            tiers:
              - default:
                  listener:
                    enabled: true
                    listen: "0.0.0.0:17<INSTANCE_NUM>"
                    advertise: "<INSTANCE_ADDR>:17<INSTANCE_NUM>"
          s3r_meta:
            tiers:
              - default
          s3r_api:
            tiers:
              - default
        migration_context:
          storage_tier: default
          engine: memtx
          unlogged: ""

GROUP1:                       # группа серверов задаёт домен отказа
  hosts:
    server-1-1:
      ansible_host: 'node1.example.net'
      host_group: 'STORAGES'

GROUP2:
  hosts:
    server-2-1:
      ansible_host: 'node2.example.net'
      host_group: 'STORAGES'

GROUP3:
  hosts:
    server-3-1:
      ansible_host: 'node3.example.net'
      host_group: 'STORAGES'

В примере адрес конечной точки S3 задаётся переменной S3R_API_LISTEN. Раздел listener сервиса s3r_api задаёт тот же адрес и, кроме того, позволяет включить TLS; без TLS оба способа дают одинаковый результат. Каталог диска включает номер инстанса, потому что на одном сервере работает несколько инстансов, а каталог диска не может принадлежать двум инстансам.

После работы роли выполните проверки шагов 6, 7 и 9.

Тестовый кластер

Локальный кластер для разработки разворачивается средством Pike:

cargo install picodata-pike
cargo pike run

Pike собирает плагин, поднимает кластер по описанию из topology.toml, устанавливает плагин, применяет миграции и включает сервисы. Кластер останавливается командой cargo pike stop.

Удаление

ALTER PLUGIN s3r 2.0.0 DISABLE;
DROP PLUGIN s3r 2.0.0 WITH DATA;

Внимание

Параметр WITH DATA применяет миграции в обратном направлении и удаляет таблицы плагина вместе с метаданными объектов. Без метаданных содержимое объектов на дисках прочитать нельзя; сами файлы сохраняются, и каталоги дисков очищаются отдельной операцией.

Конфигурация

Конфигурация плагина едина для всего кластера. Значения по умолчанию заданы в манифесте плагина и изменяются командой ALTER PLUGIN ... SET.

Параметры, которые различаются от узла к узлу, задаются в конфигурации самой Picodata, в разделе instance.plugin, и переменными окружения.

Сводный перечень параметров со значениями по умолчанию приведён в приложении В.

Контекст миграции

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

Параметр По умолчанию Описание
storage_tier default тир Picodata, в котором создаются шардированные таблицы и работает хранилище блоков
engine memtx движок таблиц пространства имён: memtx или vinyl
unlogged пусто значение UNLOGGED отключает журнал упреждающей записи для таблиц пространства имён; допустимо только для memtx и только там, где допустима потеря метаданных при перезапуске ведущего узла репликасета

Сервис s3r_api

Параметр По умолчанию Описание
listen 127.0.0.1:8000 адрес и порт конечной точки S3; применяется, только если в конфигурации Picodata нет раздела слушателя
inline_max 4096 верхняя граница размера объекта класса inline
max_body_bytes 268435456 устаревший параметр, сохранённый для совместимости с существующими конфигурациями; текущая версия его не использует
credentials [] начальный список ключей доступа, только для арендатора 0; пустой список не отключает аутентификацию
backend picodata источник данных; значение fs включает отладочный режим поверх файловой системы
fs_root null каталог для режима backend = fs
region default значение в ответе GetBucketLocation и допустимое значение LocationConstraint при создании бакета
service_timeout_s 30 предельное время ожидания внутренних ресурсов: памяти, очередей, дисков и узлов; время ожидания данных от клиента не учитывается
api_memory 0 общий предел памяти для содержимого объектов в обрабатываемых запросах; значение 0 выбирает предел автоматически, в размере четверти памяти, доступной процессу
diagnostics health доступная часть пространства /-/: health, debug или bench
control_api false включает консоль и API управления на HTTP-порту Picodata (instance.http_listen)
iam null аутентификация в консоли и API управления: внешний поставщик OpenID Connect либо проверка паролей самим кластером
s3_public_url null адрес конечной точки S3 в том виде, в каком к нему обращается браузер; используется для предподписанных ссылок, если у арендатора нет собственного домена
grafana_url null адрес Grafana для ссылки из консоли; без значения ссылка не показывается

Ограничения на полный размер тела запроса нет. Запись выполняется потоком: данные кодируются и передаются на диски по мере поступления, и записываемый объект целиком в памяти не накапливается. Параметр api_memory учитывает буфер приёма и созданные из него фрагменты. Для формы кодирования k+m это приблизительно объём буфера, умноженный на 1 + (k + m) / k.

При чтении в памяти собирается весь запрошенный диапазон, и его размер также резервируется из api_memory. Если память не освобождается за время service_timeout_s, запрос завершается ответом SlowDown.

Параметров TLS в конфигурации плагина нет. Сертификат задаётся в конфигурации Picodata, в разделе слушателя, так же как для остальных слушателей Picodata.

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

Сервис s3r_meta

Параметр По умолчанию Описание
bridge_fibers 16 число служебных волокон, которые обрабатывают обращения к метаданным со стороны среды выполнения Tokio; ограничивает число одновременных операций
bridge_queue 256 предельное число заданий в очереди к служебным волокнам; при заполнении очереди приём новых запросов приостанавливается
read_consistency strong strong: чтение с ведущего узла репликасета, успешно записанные данные сразу доступны для чтения; eventual: чтение с реплики с меньшими затратами ресурсов, результат может быть устаревшим

Сервис s3r_storage

Параметр По умолчанию Описание
disks [] список каталогов хранилища блоков с необязательными поддоменом отказа, ярусом, ёмкостью и размером экстента
erasure [] формы групп размещения для избыточного кодирования: k, m, block_bytes (по умолчанию 2 МиБ) и tier (ярус, по умолчанию standard)
tiers [] карта классов хранения S3: пары {name, class} в порядке от наиболее частого к наиболее редкому доступу; пустая карта означает ярус standard с классом STANDARD
write_tolerance 1 число фрагментов блока, которые запись вправе оставить недописанными; см. «Кворум записи»
gc_reclaim_after_s 60 задержка перед освобождением фрагментов удалённого объекта
dirgc_grace_s 0 выдержка перед проверкой опустевшего каталога; значение 0 означает max(2, 2 × service_timeout_s), то есть 60 секунд при значениях по умолчанию
orphan_grace_s 86400 возраст запечатанного экстента, начиная с которого проверяются контрольные суммы и удаляются фрагменты без строки объекта
mpu_abandon_after_s 604800 срок, после которого заброшенная составная загрузка отменяется
scrub_staleness_s 604800 наибольший допустимый возраст полной проверки данных и чётности группы размещения
compact_live_percent 50 доля живых данных в экстенте, ниже которой экстент уплотняется

Пример объявления формы кодирования:

ALTER PLUGIN s3r 2.0.0 SET
  s3r_storage.erasure = '[{"k":8,"m":4,"block_bytes":1048576}]';

Формы для репликации не объявляются. Число копий определяется параметром replication_factor тира Picodata, на котором работает хранилище.

Адрес обмена фрагментами блоков различается на каждом узле, поэтому он задаётся в конфигурации Picodata.

Конфигурация Picodata

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

instance:
  failure_domain:
    dc: msk
    rack: r3
  plugin:
    s3r:
      service:
        s3r_api:
          listener:
            enabled: true
            listen: "0.0.0.0:8000"
            tls:
              enabled: true
              cert_file: /etc/s3r/server.pem
              key_file:  /etc/s3r/server.key
              ca_file:   /etc/s3r/clients-ca.pem
        s3r_storage:
          listener:
            enabled: true
            listen: "0.0.0.0:8700"
            advertise: "node3.example.net:8700"

Домен отказа инстанса

Домен отказа инстанса (failure_domain) задаётся в конфигурации Picodata. Компонент dc задаёт площадку, и группа размещения не выходит за границу площадки. Инстансы, домены отказа которых совпадают хотя бы в одном компоненте, Picodata не объединяет в один репликасет (см. «Схема избыточности»).

Слушатель s3r_api

Слушатель s3r_api задаёт адрес конечной точки S3 и её сертификат. Параметр ca_file включает двустороннюю аутентификацию TLS (mTLS): клиент без сертификата отклоняется на этапе рукопожатия. Если раздела listener нет, применяется переменная S3R_API_LISTEN, а при её отсутствии параметр s3r_api.listen. Явное значение listener.enabled: false отключает конечную точку S3, и запасной адрес в этом случае не применяется.

Слушатель s3r_storage

Слушатель s3r_storage задаёт адрес обмена фрагментами блоков. Объявленный адрес (advertise) Picodata публикует в таблице _pico_peer_address, и по этой таблице узлы находят друг друга. Собственного реестра узлов плагин не ведёт.

Инстанс, на котором заданы диски и не задан слушатель s3r_storage, не запускается. Иначе инстанс опубликовал бы диски, недоступные остальным узлам кластера, и при этом выглядел бы исправным.

Переменные окружения

Переменная Назначение
S3R_DISKS список дисков инстанса; перекрывает параметр s3r_storage.disks
S3R_API_LISTEN адрес конечной точки S3; применяется, только если в конфигурации Picodata нет раздела слушателя
S3R_WORKER_THREADS верхняя граница пула рабочих потоков Tokio

Переменная S3R_DISKS задаётся как список дисков через запятую. Диск описывается полями через двоеточие: путь[:КЛЮЧ=ЗНАЧЕНИЕ]*[:ёмкость[:размер_экстента]], например /mnt/d0:hba=a,/mnt/d1:hba=b:tier=hdd. Поле со знаком = задаёт свойство диска. Свойство tier= назначает ярус (метку оператора из символов [a-z0-9_-], по умолчанию standard), а остальные свойства образуют поддомен отказа. Поля без знака = позиционные: сначала ёмкость, затем размер экстента.

Параметр disks в конфигурации плагина описывает установку, в которой на всех узлах одинаковые устройства смонтированы по одинаковым путям. Если пути различаются, например из-за нескольких инстансов на одном узле, диски задаются переменной окружения. На каждой площадке должно хватать дисков и независимых доменов отказа для каждого используемого яруса; результат проверяется по полю unsatisfied в ответе /-/debug/topology.

Переменная S3R_WORKER_THREADS нужна на узлах с несколькими инстансами. Без неё каждый инстанс определяет размер пула по всей машине, и на узле с четырьмя инстансами рабочих потоков запускается вчетверо больше, чем процессорных ядер. Если ресурсы инстансов ограничены средствами cgroup, переменная не требуется, потому что функция available_parallelism() учитывает квоту.

Шифрование трафика

Плагин обслуживает два независимых сетевых контура. По клиентскому контуру приходят запросы S3, по внутрикластерному узлы обмениваются фрагментами блоков. Контуры настраиваются отдельно.

Контур Транспорт Шифрование
Клиентский (S3) HTTP/1.1 TLS; при заданном ca_file mTLS
Внутрикластерный (обмен фрагментами блоков) HTTP/2 взаимный TLS, ca_file обязателен

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

Сетевые контуры S3R

Клиентский контур

TLS для конечной точки S3 задаётся разделом listener сервиса s3r_api в конфигурации Picodata. Собственных параметров TLS у плагина нет: сертификат описывается там же, где и для остальных слушателей Picodata.

instance:
  plugin:
    s3r:
      service:
        s3r_api:
          listener:
            enabled: true
            listen: "0.0.0.0:8443"
            tls:
              enabled: true
              cert_file: /etc/s3r/server.pem
              key_file:  /etc/s3r/server.key
              ca_file:   /etc/s3r/clients-ca.pem

Параметр ca_file включает двустороннюю аутентификацию (mTLS). Клиент без сертификата, подписанного указанным удостоверяющим центром, отклоняется на этапе рукопожатия TLS, до разбора запроса S3.

Рукопожатие выполняется в среде выполнения Tokio средствами OpenSSL. Набор шифров соответствует профилю Mozilla Intermediate v5.

Версии протокола и наборы шифров

Плагин использует библиотеку OpenSSL, с которой собрана Picodata, и собственной криптографии не вводит. Поэтому доступные версии протокола и наборы шифров совпадают с доступными остальным слушателям Picodata, а TLS 1.3 поддерживается в обоих контурах. Поддержка отечественных алгоритмов определяется сборкой OpenSSL: в сертифицированной конфигурации с поддержкой ГОСТ они доступны без отдельной настройки в плагине.

Сертификат арендатора и выбор по SNI

Слушатель s3r_api использует сертификат кластера, заданный в конфигурации Picodata. Арендатор может отвечать по собственному доменному имени (s3r_tenant.domain, см. главу «Изоляция арендаторов») с собственным сертификатом.

Сертификат арендатора хранится в строке таблицы s3r_tenant, в столбцах cert_chain, cert_key и, для взаимного TLS, mtls_ca. Строка реплицируется на все узлы одной транзакцией. Если бы сертификаты хранились в файлах, их пришлось бы распространять по узлам, а расхождение файлов привело бы к ошибкам TLS на части узлов.

Сертификат и ключ задаются как текст PEM в кодировке Base64. Закрытый ключ в формате PEM занимает несколько строк, а не все способы передачи значения сохраняют переносы строк. Значение в кодировке Base64 занимает одну строку и от способа передачи не зависит.

Во время рукопожатия сервер выбирает сертификат арендатора по имени из SNI. Если у арендатора задан mtls_ca, сервер также требует клиентский сертификат. Выбор выполняется до чтения заголовка Host, потому что к этому моменту рукопожатие TLS уже завершено.

Соединение без SNI обслуживается только как соединение с арендатором по умолчанию. Оно получает сертификат этого арендатора и его режим проверки клиентского сертификата, а если собственного сертификата у арендатора по умолчанию нет, получает сертификат кластера. Запрос, адресованный заголовком Host любому другому арендатору, по такому соединению отклоняется. Имя из SNI должно соответствовать арендатору запроса, поэтому клиент не может предъявить сертификат одного арендатора и обратиться к данным другого, а требование клиентского сертификата нельзя обойти, опустив SNI.

Сертификат арендатора заменяется командой UPDATE его строки. Изменение реплицируется на все узлы и не прерывает обслуживание других арендаторов.

Внимание

Закрытый ключ арендатора сохраняется в журнале упреждающей записи и в снимках до их уплотнения. При компрометации ключа недостаточно заменить его: старый ключ остаётся восстановимым из резервных копий за этот период.

Таблица s3r_tenant выдаётся только роли s3r_superuser и не входит в наборы табличных разрешений для остальных ролей. Плагин читает столбец ключа только для того, чтобы собрать контекст TLS, и не выводит ключ ни в журнал, ни в диагностику.

Внутрикластерный контур

Обмен фрагментами блоков между узлами шифруется, если в конфигурации слушателя s3r_storage задан раздел tls. Без него порт обмена фрагментами принимает и передаёт содержимое объектов в открытом виде.

Внимание

Шифрование обмена фрагментами блоков по умолчанию выключено. Без раздела tls порт s3r_storage размещается только в изолированной сети; для кластера разработки на одном узле это допустимо.

Каждый узел выступает одновременно сервером и клиентом обмена фрагментами, поэтому применяется взаимная аутентификация через общий удостоверяющий центр кластера. Узел предъявляет собственный сертификат и проверяет сертификат узла на другой стороне соединения.

instance:
  plugin:
    s3r:
      service:
        s3r_storage:
          listener:
            enabled: true
            listen: "0.0.0.0:8700"
            advertise: "node3.example.net:8700"
            tls:
              enabled: true
              cert_file: /etc/s3r/node3.pem
              key_file:  /etc/s3r/node3.key
              ca_file:   /etc/s3r/cluster-ca.pem
Параметр Роль в схеме
cert_file, key_file сертификат и ключ узла; предъявляются при приёме и при установлении соединения
ca_file удостоверяющий центр кластера; по нему проверяется сертификат другого узла

Для внутрикластерного контура параметр ca_file обязателен, а для клиентского нет: в клиентском контуре сертификат подтверждает подлинность сервера для клиента. Запрос фрагмента блока не несёт подписи S3, и право на запрос определяется принадлежностью узла к кластеру, которую подтверждает его сертификат. Без ca_file проверить, что соединение установлено с доверенным узлом, невозможно, поэтому раздел tls без ca_file останавливает загрузку плагина с сообщением об ошибке.

При запуске узел записывает в журнал выбранный режим:

shard endpoint serving on Some(127.0.0.1:9801) over mutual TLS, repair and
shortfall workers started

Фрагмент over mutual TLS означает, что включены шифрование и взаимная аутентификация. Без раздела tls сообщение содержит фрагмент over plaintext; carry it over a trusted network: данные передаются без шифрования, и порт следует размещать в изолированной сети. Режим передачи в таблицы s3r_pg и s3r_disk не записывается.

Имя узла не проверяется

Адреса узлов берутся из таблицы _pico_peer_address в виде IP:порт, то есть из консенсуса самого кластера, а не из службы имён. Проверка имени потребовала бы указывать IP-адрес в расширении subjectAltName каждого сертификата и перевыпускать сертификат при переносе узла, но ничего не добавила бы к адресу, полученному через Raft. Проверяется цепочка сертификатов: сертификат узла должен быть подписан удостоверяющим центром кластера, иначе рукопожатие не состоится.

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

Выпуск сертификатов узлов средствами openssl:

# Удостоверяющий центр кластера, один на установку.
openssl req -x509 -newkey rsa:4096 -days 3650 -nodes \
  -keyout cluster-ca.key -out cluster-ca.pem \
  -subj "/CN=s3r cluster CA"

# Сертификат узла.
openssl req -newkey rsa:2048 -nodes \
  -keyout node3.key -out node3.csr \
  -subj "/CN=node3.example.net"

openssl x509 -req -in node3.csr -days 825 \
  -CA cluster-ca.pem -CAkey cluster-ca.key -CAcreateserial \
  -extfile <(printf "subjectAltName=DNS:node3.example.net\nextendedKeyUsage=serverAuth,clientAuth") \
  -out node3.pem

Расширение extendedKeyUsage содержит оба назначения, потому что узел использует один сертификат и как сервер, и как клиент.

Если шифрование не включено, внутрикластерный трафик изолируется сетевыми средствами: отдельным сегментом сети или VLAN для межузлового обмена, фильтрацией порта обмена фрагментами блоков на границе сегмента, туннелированием через IPsec или WireGuard при передаче между площадками.

Диски и домены отказа

Идентификация диска

Диском S3R служит каталог локальной файловой системы. При первом запуске в нём создаётся суперблок с постоянным идентификатором диска и идентификатором кластера. Записи о размещении ссылаются на идентификатор диска, а не на путь или имя инстанса.

Такая идентификация обеспечивает два свойства:

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

Параметр диска capacity_bytes ограничивает используемую ёмкость значением меньше размера файловой системы. Параметр extent_bytes задаёт размер файла экстента: по умолчанию 1 ГиБ, допустимы кратные 4096 значения от 16 МиБ до 2 ГиБ. Оба параметра задаются в YAML либо позиционными полями S3R_DISKS. Размер экстента и вычисленное из ёмкости число экстентов записываются при форматировании и для диска с данными не меняются; чтобы задать другую ёмкость или другой размер экстента, нужен новый пустой каталог.

Домен отказа диска

Домен отказа диска состоит из домена отказа его инстанса и поддомена диска.

инстанс dc=msk,rack=r3   диск (не задан)  ->  dc=msk,rack=r3
инстанс dc=msk,rack=r3   диск hba=a       ->  dc=msk,rack=r3,hba=a

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

Правило размещения одно для обоих классов хранения: участники группы размещаются в различных доменах отказа, насколько позволяют диски. Для класса replica участниками служат R копий, для класса ec участниками служат k+m фрагментов. Группа собирается из дисков одного инстанса, если их достаточно, как описано в разделе «Схема избыточности».

Диск без объявленного поддомена считается настолько же независимым, насколько независим его инстанс. Несколько таких дисков одного инстанса образуют один домен отказа, группа из k+m фрагментов на них не собирается, и применяется репликация. Без сведений о независимости дисков кодирование не выполняется.

Классы хранения и группы размещения

Размещение объекта определяется двумя независимыми решениями.

Ось Что определяет Чем задаётся
Внутри площадки как данные разложены по дискам: inline, ec или, при отсутствии групп кодирования, replica параметром inline_max и формами в s3r_storage.erasure
Между площадками на скольких площадках хранится копия объекта составом доменов отказа: компонентом dc в failure_domain

Кодирование не выходит за границу площадки. Внутри площадки объект кодируется по k+m дискам, а между площадками объект реплицируется целиком, и каждая площадка хранит собственную, независимо закодированную копию. Столбец placements строки объекта содержит отображение площадки в группу размещения и служит единицей межплощадочной избыточности.

Репликация между площадками дополняет кодирование, а не заменяет его. При одной площадке применяется кодирование, при нескольких площадках применяется кодирование внутри каждой площадки и репликация между площадками.

Причина ограничения состоит в пропускной способности канала между площадками. При кодировании через границу площадки каждое чтение с потерей фрагментов передавало бы по каналу k фрагментов, каждое восстановление передавало бы объём в k раз больше утраченного, а каждая запись ожидала бы самое медленное из k+m соединений.

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

Внимание

Пока в placements есть только одна запись live, безвозвратная потеря этой площадки делает содержимое объекта недоступным, даже если строка объекта сохранилась. Перед плановым выводом площадки дождитесь пустой очереди s3r_t<N>_siterepl каждого арендатора и проверьте наличие записей live на других площадках.

Размещение голосующих реплик Picodata и сохранение кворума Raft настраиваются отдельно от размещения содержимого объектов.

Классы хранения внутри площадки

Размер объекта Класс Размещение
до inline_max включительно inline строка метаданных; избыточность обеспечивает Picodata
больше inline_max ec k фрагментов данных и m фрагментов чётности на блок
больше inline_max, если групп кодирования нет replica R полных копий на R различных дисках

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

Класс replica служит запасным вариантом. Он выбирается там, где группу кодирования собрать не из чего, например когда ни один диск не объявил поддомен отказа. Без этого варианта установка без поддоменов не смогла бы хранить объекты крупнее inline_max.

Внутри хранилища блоков второй границы по размеру объекта, между репликацией и кодированием, нет. Объект, для которого репликация выгодна по размеру, помещается в строку метаданных, а строки реплицирует сама Picodata. Кроме того, каждая запись в хранилище блоков выравнивается до 4 КиБ, что существенно для малых объектов. Сравнение формы k=8, m=4 с тремя копиями:

Объект ec 8+4 3 копии Меньший объём
5 КиБ 48 КиБ 24 КиБ копии
8 КиБ 48 КиБ 36 КиБ копии
16 КиБ 48 КиБ 60 КиБ ec
64 КиБ 144 КиБ 204 КиБ ec
1 МиБ 1584 КиБ 3084 КиБ ec

Для объектов размером примерно от 4 до 10 КиБ, то есть немного больше inline_max, репликация занимает меньше места, а чтение закодированного объекта требует k обращений к дискам против одного. Для этого диапазона предназначен параметр inline_max, который задаёт границу хранения содержимого в оперативной памяти узла.

Классы хранения S3 и ярусы

Класс хранения S3 (x-amz-storage-class) выбирает клиент, а ярус хранения (tier= на диске) назначает администратор. Соответствие между ними задаётся параметром s3r_storage.tiers: каждому ярусу соответствует один класс, а каждому классу один ярус. Список упорядочен от наиболее частого к наиболее редкому доступу.

s3r_storage:
  tiers:
    - { name: standard, class: STANDARD }
    - { name: cold, class: STANDARD_IA }
  erasure:
    - { k: 4, m: 2, block_bytes: 2097152 }
    - { k: 8, m: 2, block_bytes: 4194304, tier: cold }

Объект создаётся в ярусе, который соответствует его классу. Операции PutObject, CopyObject и CreateMultipartUpload принимают заголовок x-amz-storage-class. Без заголовка назначается класс STANDARD, а CopyObject не наследует класс источника. Части составной загрузки наследуют класс загрузки. Класс возвращается в ответах HeadObject, GetObject, GetObjectAttributes и операций перечисления.

Класс, которого нет в карте, отклоняется с ответом 400 InvalidStorageClass. Кластер с единственным ярусом принимает любое имя класса AWS и хранит его как метку. Если карта не называет ни ярус standard, ни класс STANDARD, ярус standard с классом STANDARD подразумевается.

Привязка класса к ярусу постоянна: строки объектов хранят класс, размещения ссылаются на группы одного яруса, и изменение конфигурации данные не переносит.

Внимание

Команда ALTER PLUGIN, которая связывает уже известный класс с другим ярусом или ярус с другим классом, может завершиться успешно: Picodata не даёт плагину проверить конфигурацию до её сохранения. Сервис записывает в журнал ошибку с обеими привязками, игнорирует несовместимую карту и продолжает использовать прежнюю. После изменения проверьте журнал и действующую карту в таблице s3r_tier.

Объекты размером до inline_max хранятся в строке метаданных при любом классе, и класс для них служит только меткой. Если на площадке нет группы нужного яруса, запись объекта этого класса отклоняется с ответом 503, в котором названы класс, ярус и площадка; объект не размещается на дисках яруса с более частым доступом. Такие отказы считает метрика s3r_class_refused_total{class}. Задание перехода в недоступный ярус остаётся в очереди и выполняется, когда администратор добавит диски и появится подходящая группа.

Кластер с ярусами строится по двум правилам. Ярусу нужны диски не менее чем в k+m доменах отказа на каждой площадке, иначе его формы не образуют групп, а диски другого яруса не заимствуются. Если ярус представлен на меньшинстве узлов, весь его трафик и восстановление проходят через сетевые интерфейсы этих узлов. Подробности приведены в главе «Администрирование».

Группы размещения

Группа размещения представляет собой упорядоченный набор дисков в пределах одной площадки и геометрию записи на них. Фрагмент с номером i каждого блока, размещённого в группе, хранится на i-м диске набора.

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

Группы формируются автоматически. Менеджер топологии пересматривает группы при изменении состава кластера и дисков и создаёт на каждой площадке столько групп каждой формы, сколько позволяют свободные диски. Группа размещения постоянна: объекты записываются в её конкретный состав.

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

Диски, уже распределённые по группам, новой форме не достаются. Поэтому форма кодирования объявляется до ввода кластера в эксплуатацию.

Выбор формы кодирования

Число фрагментов ограничено сверху значением k + m не больше 32768, до которого на практике не доходят. Существенное ограничение другое: форма k+m требует k + m различных доменов отказа, потому что фрагменты одного блока не размещаются в одном домене.

Испытаниями охвачены формы от 2+2 до 12+4. Более широкие схемы, например 17+3 и 61+3, кодировщик принимает, но на стенде они не проверялись.

Избыточность формы k+m равна (k + m) / k, а полезная ёмкость пула равна сырой ёмкости, делённой на эту величину. Форма 8+4 даёт 1,5, то есть треть сырой ёмкости уходит на чётность; форма 12+3 даёт 1,25; форма 10+2 даёт 1,2. Форму следует выбирать вместе с составом дисков, а не после его определения.

Внимание

Форма, под которой уже есть данные, не изменяется: изменение отклоняется при загрузке конфигурации.

Геометрия хранится в строке группы размещения, а не в строке объекта, и одинакова для всех записанных в группу блоков.

Контроль целостности

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

Кроме того, целостность проверяют два фоновых процесса. Процесс orphan последовательно обходит запечатанные экстенты, проверяет контрольные суммы записей и удаляет фрагменты, на которые не ссылаются метаданные. Возраст экстента, начиная с которого выполняется такой обход, задаётся параметром orphan_grace_s.

Процесс scrub проверяет избыточное кодирование: заново вычисляет фрагменты чётности по k фрагментам данных и сравнивает результат с сохранёнными m фрагментами. Параметр scrub_staleness_s задаёт наибольший допустимый возраст полной проверки группы размещения, а не период запуска процесса.

Межплощадочная репликация

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

Блок передаётся между площадками один раз и в исходном виде, а принимающая площадка кодирует его в собственные k+m фрагментов средствами своей группы размещения. Передача k+m готовых фрагментов расходовала бы канал между площадками на тот самый объём, который кодирование должно экономить.

Межплощадочная репликация

Столбец placements содержит по записи на каждую площадку:

Состояние Значение
live копия записана и доступна для чтения
pending копия ещё не записана
lost площадка или её диски утрачены

Досылку копий выполняет фоновый процесс siterepl, а сверку содержимого площадок между собой выполняет процесс siterepl-reconcile.

Репликация как свойство кластера

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

Причина в устройстве плагина. Площадка является свойством группы размещения, а группы размещения общие для кластера. Арендатор представляет собой пространство имён со своим набором таблиц, а не собственный набор оборудования.

Арендаторам с разными требованиями к географии данных нужны разные кластеры.

Изоляция арендаторов

Один кластер обслуживает несколько арендаторов, и каждый арендатор представляет собой отдельное пространство имён. Объекты, каталоги, составные загрузки и служебные очереди арендатора хранятся в его собственных таблицах: s3r_t<N>_object, s3r_t<N>_dir, s3r_t<N>_mpu и других. Запрос не может обратиться к объектам другого арендатора, потому что не может назвать его таблицу. Бакеты и ключи доступа хранятся в глобальных таблицах s3r_bucket и s3r_credential: идентификатор арендатора входит в ключ строки бакета и указан в строке ключа доступа.

Арендатор с номером 0 и именем default служит арендатором по умолчанию. Если в кластере не создано других арендаторов, кластер целиком принадлежит арендатору по умолчанию, и всё описанное в остальных главах относится к нему.

Создание и удаление арендатора

Арендаторы управляются командами SQL над глобальной таблицей s3r_tenant, доступной роли s3r_superuser (см. «Ролевая модель арендаторов»).

Для создания арендатора добавьте строку со значением state = 'creating':

INSERT INTO s3r_tenant (tenant_id, name, domain, state, created_at)
VALUES (1, 'acme', 'acme.s3.example.com', 'creating', CURRENT_TIMESTAMP);

Изменение таблицы запускает процесс согласования, который создаёт таблицы нового арендатора и переводит его в состояние active. Удаление выполняется через состояние draining. Запросы обслуживаются только для арендатора в состоянии active. Арендатор в состоянии creating ещё не готов, а арендаторы в состояниях draining и dropped больше не проходят аутентификацию, поэтому перевод арендатора в удаление отзывает его доступ той же записью Raft.

Основные столбцы таблицы s3r_tenant:

Столбец Назначение
tenant_id малое постоянное число; входит в имена таблиц и в заголовки фрагментов блоков, поэтому переименование арендатора эти данные не меняет
name уникальное имя, которое задаёт оператор
domain FQDN, по которому отвечает арендатор (см. «Адресация арендатора»), или NULL
cert_chain, cert_key, mtls_ca материал TLS (см. «Сертификат арендатора и выбор по SNI»)
state одно из значений creating, active, draining, dropped

Два арендатора принадлежат самому кластеру и не удаляются. Первый из них арендатор 0, пространство имён по умолчанию. Второй системный арендатор с последним идентификатором 4294967295, в таблицах которого хранятся данные, не принадлежащие ни одному пользовательскому арендатору, а именно объекты дедупликации. У системного арендатора нет ни домена, ни ключей доступа; если перевести его в состояние draining, процесс согласования вернёт его в состояние active.

Поля описания оборудования

Столбец appliance хранит поля, которые описывают развёртывание арендатора на программно-аппаратном комплексе: ns_count, os_count, s3gw_count, storage_lvl и failure_domain. API управления принимает эти поля при создании и изменении арендатора и возвращает их в том же виде, но плагин их не применяет.

Применить их нельзя: все арендаторы S3R делят один кластер и один набор инстансов, а сервисы s3r_api, s3r_meta и s3r_storage работают на одном тире. Поля сохраняются, чтобы клиент, который их задал, мог прочитать их обратно.

Поле redundancy_lvl составляет исключение и проверяется. Его значение задаётся строкой k+m, например 2+2, из числа уровней, которые возвращает запрос GET /v2/cluster/tiers-redundancy-levels. Уровень, которого в кластере нет, отклоняется при создании арендатора ответом 400 с перечнем доступных уровней. Без этой проверки арендатор создавался бы успешно, а ошибка возникала бы только при первой записи. Размещение объектов к этому уровню не привязывается: объекты по-прежнему размещаются в соответствии с классом хранения.

Дедупликация

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

UPDATE s3r_bucket SET dedup = true WHERE tenant_id = 0 AND name = 'archive';
UPDATE s3r_tenant SET dedup = true WHERE tenant_id = 0;

Переключатель бакета доступен также в консоли, рядом с переключателем сжатия, и в API управления: PUT /v2/buckets/{bucket}/deduplication с телом {"dedup": true}.

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

Разрешение арендатора запроса

Запрос может указывать арендатора двумя способами, и решение принимается по обоим:

  • заголовок Host с FQDN арендатора из s3r_tenant.domain называет арендатора ещё до разбора запроса;
  • ключ доступа указывает арендатора через столбец s3r_credential.tenant_id.

Если запрос указывает арендатора обоими способами, они должны совпадать. Ключ одного арендатора, пришедший на FQDN другого, отклоняется с ответом 403, а не разрешается в пользу одного из них: молчаливый выбор открыл бы путь к чтению данных другого арендатора. Запрос без обоих признаков относится к арендатору 0.

Адресация арендатора

Арендатор с заданным domain отвечает по своему FQDN в обеих формах адресации:

Стиль пути: FQDN арендатора, бакет и ключ указаны в пути
https://acme.s3.example.com/documents/report.pdf

Виртуально-хостовая адресация: бакет указан меткой перед FQDN арендатора
https://documents.acme.s3.example.com/report.pdf

Точка входа по умолчанию, то есть обращение по IP-адресу или имени узла без FQDN арендатора, работает в стиле пути, и арендатор определяется по ключу доступа, по умолчанию это арендатор 0. Хост, похожий на схему адресов арендаторов, но не принадлежащий ни одному из них, отклоняется, а не обслуживается арендатором по умолчанию, потому что иначе запросы к несуществующему арендатору попадали бы к данным арендатора по умолчанию.

Собственный сертификат арендатора и обязательный клиентский сертификат описаны в разделе «Сертификат арендатора и выбор по SNI», роли s3r_superuser и s3r_tenant_admin_<id> описаны в разделе «Ролевая модель арендаторов».

Работа с хранилищем

Учётные данные

Ключ доступа S3 сопоставляется с пользователем Picodata, и права на операции S3 проверяются средствами СУБД. Отдельной системы управления доступом плагин не вводит. Ключ действителен, пока существует пользователь, которому он выдан.

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

  • через API управления или консоль: POST /v2/credentials с телом {"username": "alice"} создаёт ключ и возвращает секретный ключ один раз, в ответе на этот запрос;
  • для арендатора 0 параметром s3r_api.credentials, как описано ниже;
  • для арендаторов, созданных после установки, только через API управления арендатора.

Параметр s3r_api.credentials служит начальным списком ключей арендатора 0. При каждом запуске сервиса s3r_api ключи из списка добавляются в таблицу s3r_credential. Пользователь, указанный в pico_user, должен существовать заранее:

CREATE USER "alice" WITH PASSWORD '...' USING scram-sha256;

ALTER PLUGIN s3r 2.0.0 SET s3r_api.credentials =
  '[{"access_key":"AKIA...","secret_key":"...","pico_user":"alice"}]';

Если параметр pico_user не указан, пользователем считается сам ключ доступа. Пользователя с таким именем, как правило, нет, и подписанные запросы отклоняются с сообщением о неизвестном ключе доступа.

Список credentials только добавляет ключи и не удаляет ключи, созданные администратором. Пустой список не переводит конечную точку в режим без аутентификации: ключи из таблицы s3r_credential продолжают действовать, а неизвестные ключи отклоняются. Запрос без подписи выполняется, только если это разрешает список управления доступом или политика бакета. Запросы без аутентификации при пустом списке обслуживает только отладочный режим backend = fs, который таблицу Picodata не использует.

Действующие ключи показывает запрос:

SELECT access_key, tenant_id, pico_user, state FROM s3r_credential;

Роли создаются миграциями плагина; см. «Ролевая модель арендаторов».

Смена и отзыв ключей

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

Ключ отзывается запросом DELETE /v2/credentials/{access_key} или в консоли. Запрос PUT /v2/credentials/{access_key} выдаёт ключу новый секретный ключ, и прежний секретный ключ после этого не действует.

Внимание

Удаление ключа из списка s3r_api.credentials ключ не отзывает: строка в таблице s3r_credential остаётся. И наоборот, ключ, отозванный через API управления, но оставшийся в списке, снова добавляется в таблицу при следующем запуске сервиса s3r_api. Отзывая ключ из начального списка, удалите его и из списка, и через API управления.

Чтобы отозвать все ключи пользователя, удалите или заблокируйте пользователя средствами SQL: ключ, выданный несуществующему пользователю, не действует. Срок действия ключа доступа не задаётся.

Пароль для входа по SQL

Пользователь, созданный через консоль или API управления, получает случайный пароль, который никому не сообщается, потому что ключ доступа S3 не даёт права входа в СУБД. Подключиться таким пользователем через psql можно только после того, как пароль задан явно.

Пароль задаётся для отдельного пользователя кнопкой «SQL password» в списке пользователей консоли или запросом к API управления:

PUT /v2/users/password?tenant_id=0
{"username": "alice", "password": "..."}

Пароль сохраняется методом scram-sha256. Только этот метод принимают одновременно psql, консоль и протокол iproto. Метод chap-sha1 принадлежит Tarantool, и протокол PostgreSQL его отклоняет, намеренно не уточняя причину, чтобы по ответу нельзя было подбирать имена пользователей; метод md5 слабее. Тот же запрос переводит на scram-sha256 пользователя, созданного ранее с другим методом.

Примечание

Пароль задаётся только там, где пароли проверяет сам кластер (auth_type: "picodata"). Если настроен внешний поставщик учётных записей, пароли принадлежат ему: запрос отклоняется с кодом ProviderOwnsPasswords, а консоль не показывает кнопку.

Смена пароля записывается в журнал аудита Picodata событием change_password. Инициатором в этом событии указан служебный пользователь плагина, поэтому для полной картины событие сопоставляется с журналом обращений к API управления.

Пароль пользователя, созданного средствами SQL, меняется штатной командой Picodata:

ALTER USER "alice" WITH PASSWORD '...';

Поддерживаемые операции

Запросы подписываются по схеме AWS Signature Version 4, в заголовке или в параметрах запроса (предподписанная ссылка). Поддерживается потоковая подпись STREAMING-AWS4-HMAC-SHA256-PAYLOAD для передачи тела запроса частями.

Нереализованная операция, как правило, возвращает NotImplemented. Проверка доступа может выполняться раньше выбора обработчика, поэтому запрос без требуемых прав получит ответ AccessDenied.

Операция Есть Примечание
AbortMultipartUpload да
CompleteMultipartUpload да условная публикация If-Match и If-None-Match
CopyObject да CopySource с versionId, директивы COPY и REPLACE
CreateBucket да в том числе ObjectLockEnabledForBucket
CreateMultipartUpload да
DeleteBucket да только для пустого бакета
DeleteBucketCors да
DeleteBucketEncryption нет шифрование на стороне сервера не реализовано
DeleteBucketLifecycle да
DeleteBucketPolicy да
DeleteBucketReplication нет межплощадочная репликация настраивается не через S3 API
DeleteBucketTagging да
DeleteBucketWebsite да удаляет конфигурацию; сайт не отдаётся, см. «Ограничения»
DeleteObject да в том числе удаление конкретной версии
DeleteObjects да до 1000 ключей, результат по каждому ключу отдельно
DeleteObjectTagging да
DeletePublicAccessBlock да
GetBucketAcl да
GetBucketCors да 404, если правила не задавались
GetBucketEncryption нет
GetBucketLifecycleConfiguration да
GetBucketLocation да регион задаётся параметром region
GetBucketLogging нет
GetBucketNotificationConfiguration нет уведомлений в очереди сообщений нет
GetBucketPolicy да документ возвращается без изменений
GetBucketPolicyStatus да
GetBucketReplication нет
GetBucketTagging да
GetBucketVersioning да
GetBucketWebsite да без конфигурации отвечает NoSuchWebsiteConfiguration
GetObject да Range, PartNumber, условные заголовки, versionId
GetObjectAcl да
GetObjectAttributes да Checksum, ObjectParts с размерами и смещениями; ETag возвращается в кавычках
GetObjectLegalHold да
GetObjectLockConfiguration да
GetObjectRetention да режимы GOVERNANCE и COMPLIANCE
GetObjectTagging да
GetPublicAccessBlock да 404, если настройка не задавалась
HeadBucket да
HeadObject да
ListBuckets да в том числе max-buckets и continuation-token
ListDirectoryBuckets нет каталожные бакеты S3 Express не поддерживаются
ListMultipartUploads да
ListObjects да
ListObjectsV2 да
ListObjectVersions да
ListParts да
POST Object да загрузка формой из браузера; см. «Ограничения»
PutBucketAcl да
PutBucketCors да до 100 правил, документ проверяется при записи
PutBucketEncryption нет
PutBucketLifecycleConfiguration да
PutBucketLogging нет
PutBucketNotificationConfiguration нет
PutBucketPolicy да документ проверяется при записи
PutBucketReplication нет
PutBucketTagging да
PutBucketVersioning да Enabled и Suspended
PutBucketWebsite да конфигурация сохраняется целиком; сайт не отдаётся
PutObject да условная запись If-Match и If-None-Match, контрольные суммы SHA-256 и CRC64/NVME
PutObjectAcl да
PutObjectLegalHold да
PutObjectLockConfiguration да
PutObjectRetention да
PutObjectTagging да
PutPublicAccessBlock да четыре флага, заменяются целиком
RestoreObject нет архивного класса хранения нет
SelectObjectContent нет S3 Select не поддерживается
UploadPart да контрольные суммы SHA-256 и CRC64/NVME
UploadPartCopy да в том числе copy-source-range

Адресация

По умолчанию используется адресация в стиле пути: http://узел:8000/бакет/ключ. В клиенте она включается параметром addressing_style: path или флагом force_path_style. На точке входа по умолчанию, то есть при обращении по IP-адресу или имени узла, это единственная поддерживаемая форма.

Виртуально-хостовая адресация, при которой имя бакета входит в имя узла (бакет.домен), поддерживается для арендатора с заданным FQDN. Такой арендатор отвечает и по своему FQDN, и в форме бакет.FQDN, для чего нужна запись DNS с подстановочным знаком на домен арендатора. См. главу «Изоляция арендаторов».

Совместимость с клиентами

Работает любой клиент протокола S3 с подписью версии 4, например aws-sdk-go, aws-sdk-java, boto3, aws-sdk-cpp, aws-cli, s3cmd, rclone и mc. Собственного протокола плагин не вводит: в настройках клиента задаются адрес конечной точки, ключ доступа и адресация в стиле пути.

Ключи объектов и логическая структура

Ключ объекта представляет собой произвольную строку. Символ / в ключе образует логическую структуру каталогов: перечисление с разделителем / возвращает объекты текущего уровня в Contents, а вложенные уровни в CommonPrefixes.

aws s3api list-objects-v2 --bucket documents --prefix проекты/ --delimiter /

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

Префикс служит также единицей разграничения доступа. Политика бакета с ресурсом arn:aws:s3:::documents/проекты/* действует на весь подкаталог, в том числе при массовом удалении, где право проверяется для каждого ключа отдельно.

Метаданные объекта

Пользовательские метаданные передаются заголовками x-amz-meta-* и возвращаются в ответах GET и HEAD. Сохраняются также заголовки Content-Type, Content-Encoding, Content-Disposition, Content-Language, Cache-Control и Expires.

aws s3api put-object --bucket documents --key report.pdf --body report.pdf \
    --content-type application/pdf \
    --metadata 'author=alice,department=finance'

aws s3api head-object --bucket documents --key report.pdf

При копировании метаданные по умолчанию переносятся, а параметр --metadata-directive REPLACE заменяет их значениями из запроса.

Примеры обращения

Настройка профиля и работа через AWS CLI:

aws configure set aws_access_key_id AKIA...
aws configure set aws_secret_access_key ...

aws --endpoint-url http://node1:8000 s3 mb s3://documents
aws --endpoint-url http://node1:8000 s3 cp report.pdf s3://documents/
aws --endpoint-url http://node1:8000 s3 ls s3://documents/
aws --endpoint-url http://node1:8000 s3 rm s3://documents/report.pdf

Обращение из Python:

import boto3
from botocore.config import Config

s3 = boto3.client(
    "s3",
    endpoint_url="http://node1:8000",
    aws_access_key_id="AKIA...",
    aws_secret_access_key="...",
    config=Config(s3={"addressing_style": "path"}),
)
s3.put_object(Bucket="documents", Key="report.pdf", Body=data)

Далее в примерах вместо aws --endpoint-url http://node1:8000 пишется aws.

Права доступа к объектам

Владельцем объекта становится пользователь, который его создал. Владелец бакета прав на объект не получает; такое поведение определено спецификацией S3.

Поддерживаются предопределённые списки управления доступом (private, public-read, public-read-write, authenticated-read, bucket-owner-read, bucket-owner-full-control) и явные разрешения для отдельных пользователей, а также для групп «все пользователи» и «все аутентифицированные пользователи». По умолчанию объект доступен только владельцу и не хранит списка управления доступом (ACL), поэтому при чтении такого объекта список не используется.

Справочник операций

Глава описывает операции, которые не сводятся к одному вызову. Примеры приведены для AWS CLI; тот же порядок действий воспроизводится любым SDK, работающим по протоколу S3.

Чтение диапазона

Поддерживаются диапазоны вида bytes=начало-конец, bytes=начало- и bytes=-длина. С дисков читаются только те части блоков, в которые попадает диапазон.

aws s3api get-object --bucket documents --key big.bin \
    --range bytes=1048576-2097151 part.bin

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

aws s3api get-object --bucket documents --key big.bin --part-number 3 part3.bin

Ответ содержит заголовок Content-Range, а ответ на запрос по номеру части дополнительно содержит заголовок x-amz-mp-parts-count.

Составная загрузка

При составной загрузке клиент передаёт объект частями, а хранилище собирает части в единое целое. Номера частей лежат в диапазоне от 1 до 10000. Все части, кроме последней, должны иметь размер не менее 5 МиБ, иначе завершение загрузки возвращает ошибку EntityTooSmall.

Как правило, клиент выполняет составную загрузку автоматически: aws s3 cp переходит на неё для файлов больше порога multipart_threshold. Явная последовательность вызовов:

# 1. Начать загрузку
aws s3api create-multipart-upload --bucket documents --key big.bin
# { "UploadId": "0197f2c1..." }

# 2. Передать части
aws s3api upload-part --bucket documents --key big.bin \
    --upload-id 0197f2c1... --part-number 1 --body part1.bin
# { "ETag": "\"9b2c...\"" }

# 3. Собрать объект
aws s3api complete-multipart-upload --bucket documents --key big.bin \
    --upload-id 0197f2c1... \
    --multipart-upload '{"Parts":[{"PartNumber":1,"ETag":"\"9b2c...\""}]}'

ETag собранного объекта имеет вид "<md5 склеенных md5 частей>-<число частей>" и намеренно не совпадает с MD5 содержимого, как и в Amazon S3.

Незавершённые загрузки можно просмотреть и отменить:

aws s3api list-multipart-uploads --bucket documents
aws s3api list-parts --bucket documents --key big.bin --upload-id 0197f2c1...
aws s3api abort-multipart-upload --bucket documents --key big.bin \
    --upload-id 0197f2c1...

Часть можно взять из существующего объекта, не передавая её по сети:

aws s3api upload-part-copy --bucket documents --key merged.bin \
    --upload-id 0197f2c1... --part-number 2 \
    --copy-source documents/source.bin --copy-source-range bytes=0-5242879

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

CompleteMultipartUpload, как и PutObject, принимает условные заголовки If-Match и If-None-Match. Условие проверяется в момент публикации собранного объекта.

Контрольные суммы S3

При записи вычисляются контрольные суммы SHA-256 и CRC64/NVME. Клиент может передать значение ChecksumSHA256 или ChecksumCRC64NVME в запросах PutObject и UploadPart в кодировке Base64. Если значение не совпадает с принятым содержимым, запрос завершается ответом 400 BadDigest, и запись не публикуется.

sha256=$(openssl dgst -sha256 -binary report.pdf | base64 -w0)
aws s3api put-object --bucket documents --key report.pdf \
    --body report.pdf --checksum-sha256 "$sha256"

aws s3api head-object --bucket documents --key report.pdf \
    --checksum-mode ENABLED
aws s3api get-object-attributes --bucket documents --key report.pdf \
    --object-attributes Checksum

GetObject и HeadObject возвращают контрольные суммы только при ChecksumMode=ENABLED. Ответ на чтение диапазона или части не содержит контрольной суммы всего объекта, потому что содержит только часть его данных.

Для объекта из нескольких частей возвращается составная контрольная сумма SHA-256: сумма SHA-256 от последовательности двоичных сумм SHA-256 всех частей в кодировке Base64 с суффиксом -<число частей>. Составная сумма CRC64/NVME сейчас не возвращается. GetObjectAttributes с атрибутом Checksum возвращает ту же составную сумму без чтения содержимого.

Копирование

Копия создаётся на стороне сервера, и содержимое объекта по сети не передаётся.

aws s3api copy-object --bucket archive --key report-2026.pdf \
    --copy-source documents/report.pdf

Источником может служить конкретная версия объекта:

aws s3api copy-object --bucket archive --key report-old.pdf \
    --copy-source 'documents/report.pdf?versionId=0000019874f3a1c2'

По умолчанию метаданные копируются (--metadata-directive COPY). Значение REPLACE заменяет пользовательские метаданные и тип содержимого значениями из запроса. Так же работает параметр --tagging-directive для тегов. Для условного копирования используются заголовок x-amz-copy-source-if-match и родственные ему заголовки.

Заголовок x-amz-expected-bucket-owner защищает операцию над бакетом, который пересоздан другим владельцем: при несовпадении владельца сервер возвращает AccessDenied. В S3R ожидаемым значением служит имя пользователя Picodata, которому принадлежит бакет, а не идентификатор учётной записи AWS. Для бакета-источника в CopyObject и UploadPartCopy применяется заголовок x-amz-source-expected-bucket-owner.

Копирование объекта в самого себя допускается только с параметром --metadata-directive REPLACE, иначе возвращается ошибка InvalidRequest.

Условная запись

PutObject принимает два условных заголовка. Заголовок If-None-Match: * разрешает запись, только если ключа ещё нет. Заголовок If-Match: "<etag>" разрешает запись, только если текущее содержимое объекта имеет указанный ETag. На этих двух проверках строятся взаимное исключение и оптимистическое обновление без внешнего координатора.

# Создать, только если ключа нет
aws s3api put-object --bucket documents --key lock --body /dev/null \
    --if-none-match '*'
# Второй такой же вызов вернёт PreconditionFailed (412)

# Обновить, только если содержимое не менялось
aws s3api put-object --bucket documents --key state.json --body new.json \
    --if-match '"d41d8cd98f00b204e9800998ecf8427e"'

Запрос с If-Match к отсутствующему ключу возвращает NoSuchKey (404), а не 412.

При чтении поддерживаются условные заголовки If-Match, If-None-Match, If-Modified-Since и If-Unmodified-Since.

Версионирование

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

aws s3api put-bucket-versioning --bucket documents \
    --versioning-configuration Status=Enabled
aws s3api get-bucket-versioning --bucket documents

Каждая запись создаёт новую версию с собственным VersionId, и чтение без указания версии возвращает последнюю. Удаление без указания версии не удаляет данные, а создаёт маркер удаления.

aws s3api list-object-versions --bucket documents --prefix report

# Прочитать конкретную версию
aws s3api get-object --bucket documents --key report.pdf \
    --version-id 0000019874f3a1c2 old.pdf

# Удалить конкретную версию: данные удаляются безвозвратно
aws s3api delete-object --bucket documents --key report.pdf \
    --version-id 0000019874f3a1c2

Ответ на удаление содержит заголовки x-amz-delete-marker: true и x-amz-version-id созданного маркера. Если последней версией ключа служит маркер удаления, запросы GET и HEAD без указания версии возвращают NoSuchKey (404) с заголовком x-amz-delete-marker: true. Запрос, в котором versionId указывает на сам маркер удаления, возвращает MethodNotAllowed (405) с тем же заголовком.

Состояние Suspended останавливает создание новых версий: запись заменяет версию с идентификатором null, а прежние версии сохраняются и остаются доступны по VersionId.

Теги

Теги задаются для бакета и для объекта, не более 10 тегов в обоих случаях.

aws s3api put-object-tagging --bucket documents --key report.pdf \
    --tagging 'TagSet=[{Key=class,Value=confidential}]'
aws s3api get-object-tagging --bucket documents --key report.pdf
aws s3api delete-object-tagging --bucket documents --key report.pdf

Теги объекта используются в правилах жизненного цикла и в условиях политики (s3:ExistingObjectTag/<ключ>, s3:RequestObjectTag/<ключ>).

Списки управления доступом

Поддерживаются предопределённые списки управления доступом (private, public-read, public-read-write, authenticated-read, bucket-owner-read, bucket-owner-full-control) и явные разрешения.

aws s3api put-object-acl --bucket documents --key report.pdf --acl public-read
aws s3api get-object-acl --bucket documents --key report.pdf

# Явное разрешение отдельному пользователю
aws s3api put-object-acl --bucket documents --key report.pdf \
    --grant-read 'id=bob'

Идентификатором получателя разрешения служит имя пользователя Picodata. Группы задаются идентификаторами URI http://acs.amazonaws.com/groups/global/AllUsers и http://acs.amazonaws.com/groups/global/AuthenticatedUsers.

Политика бакета

Политика служит вторым источником разрешений, независимым от списков управления доступом. Явный запрет действует всегда; если запрета нет, разрешение даёт либо политика, либо список управления доступом.

cat > policy.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam:::user/bob"},
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::documents/public/*"]
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::documents/secret/*"
    }
  ]
}
EOF

aws s3api put-bucket-policy --bucket documents --policy file://policy.json
aws s3api get-bucket-policy --bucket documents
aws s3api get-bucket-policy-status --bucket documents
aws s3api delete-bucket-policy --bucket documents

Субъект доступа задаётся именем пользователя Picodata. Распознаются имя без ARN и ARN вида arn:aws:iam::<учётная-запись>:user/<имя>, в котором значима последняя составляющая. Значение "Principal": "*" разрешает анонимное обращение.

Поддерживаются элементы Action и NotAction, Resource и NotResource с подстановочными знаками * и ?, а также условия с операторами StringEquals, StringNotEquals, StringLike, StringNotLike и суффиксом IfExists. Доступны ключи условий s3:prefix, s3:ExistingObjectTag/<ключ>, s3:RequestObjectTag/<ключ> и заголовки запроса, например s3:x-amz-acl, s3:x-amz-copy-source и s3:x-amz-metadata-directive.

Неизвестный оператор условия трактуется в пользу отказа: инструкция Allow с оператором, который плагин не реализует, доступа не даёт, а инструкция Deny с таким оператором запрещает доступ.

Совместное использование ресурсов между источниками (CORS)

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

cat > cors.json <<'EOF'
{
  "CORSRules": [
    {
      "AllowedMethods": ["GET", "PUT"],
      "AllowedOrigins": ["https://app.example.com", "https://*.example.com"],
      "AllowedHeaders": ["x-amz-*"],
      "ExposeHeaders": ["ETag", "x-amz-request-id"],
      "MaxAgeSeconds": 3000
    }
  ]
}
EOF

aws s3api put-bucket-cors --bucket documents --cors-configuration file://cors.json
aws s3api get-bucket-cors --bucket documents
aws s3api delete-bucket-cors --bucket documents

Допустимы методы GET, PUT, POST, DELETE и HEAD и не более 100 правил. Документ проверяется при записи: неизвестный метод или образец с несколькими символами * отклоняются.

Образец источника содержит не более одного символа * и сопоставляется со значением целиком. Образец *suffix совпадает с foo.suffix и не совпадает с foo.suffix.get; образец start*end совпадает с startend и start12end, но не с 0start12end. Одиночный * разрешает любой источник, и в ответе возвращается именно *, а не имя источника, поэтому браузер кэширует такой ответ для всех источников сразу.

Применяется первое правило, у которого совпали источник, метод и все заголовки из Access-Control-Request-Headers. Правило, в котором запрошенный заголовок не перечислен, не считается совпавшим, и предварительный запрос получает ответ 403.

Предварительный запрос обслуживается без подписи, потому что браузер её не присылает, и не обращается к объекту: OPTIONS для несуществующего ключа возвращает 200. Запрос без заголовка Origin или без заголовка Access-Control-Request-Method возвращает 400.

Заголовки Access-Control-* добавляются и к обычным ответам, в том числе к ответам с ошибкой: без них браузер не покажет приложению даже код ошибки.

Блокировка публичного доступа

Блокировка публичного доступа состоит из четырёх флагов бакета, которые действуют поверх списков управления доступом и политики: флаг имеет приоритет над любым разрешением из них.

aws s3api put-public-access-block --bucket documents \
    --public-access-block-configuration \
    'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'

aws s3api get-public-access-block --bucket documents
aws s3api delete-public-access-block --bucket documents
Флаг Действие
BlockPublicAcls отклоняет запись списка управления доступом, который даёт доступ группам «все пользователи» и «все аутентифицированные пользователи»
IgnorePublicAcls сохраняет такие разрешения, но не учитывает их при проверке
BlockPublicPolicy отклоняет запись политики с "Principal": "*" без условий
RestrictPublicBuckets не применяет публичную политику к запросам без подписи

Различие первых двух флагов существенно при разборе инцидента. BlockPublicAcls не даёт публичному разрешению появиться. IgnorePublicAcls оставляет разрешение в списке и перестаёт его учитывать, поэтому GetBucketAcl и GetObjectAcl по-прежнему его показывают, а снятие флага возвращает разрешение в силу.

Запрос GetPublicAccessBlock для бакета, где настройка не задавалась, возвращает NoSuchPublicAccessBlockConfiguration (404). Настройка из четырёх значений false считается заданной и читается обратно. PutPublicAccessBlock заменяет настройку целиком: опущенный флаг означает false, а не сохранение прежнего значения.

Правила жизненного цикла

Правило жизненного цикла определяет, какие объекты и когда удаляются или переносятся в другой класс хранения.

cat > lifecycle.json <<'EOF'
{
  "Rules": [
    {
      "ID": "expire-logs",
      "Status": "Enabled",
      "Filter": {"Prefix": "logs/"},
      "Expiration": {"Days": 30}
    },
    {
      "ID": "tidy-versions",
      "Status": "Enabled",
      "Filter": {},
      "NoncurrentVersionExpiration": {"NoncurrentDays": 7},
      "AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 1}
    },
    {
      "ID": "large-temp",
      "Status": "Enabled",
      "Filter": {
        "And": {
          "Prefix": "tmp/",
          "ObjectSizeGreaterThan": 10485760,
          "Tags": [{"Key": "class", "Value": "scratch"}]
        }
      },
      "Expiration": {"Days": 1}
    }
  ]
}
EOF

aws s3api put-bucket-lifecycle-configuration --bucket documents \
    --lifecycle-configuration file://lifecycle.json
aws s3api get-bucket-lifecycle-configuration --bucket documents
aws s3api delete-bucket-lifecycle --bucket documents

Поддерживаются следующие действия:

  • Expiration по числу дней Days, по дате Date и с параметром ExpiredObjectDeleteMarker;
  • NoncurrentVersionExpiration, в том числе с параметром NewerNoncurrentVersions;
  • AbortIncompleteMultipartUpload;
  • переходы между классами хранения Transition и NoncurrentVersionTransition.

Фильтр правила задаётся префиксом Prefix, тегом Tag, границами размера ObjectSizeGreaterThan и ObjectSizeLessThan либо их сочетанием через And. Конфигурация проверяется при записи, и ошибка в ней возвращает ответ InvalidArgument.

Срок Days отсчитывается от создания объекта и округляется вверх до ближайшей полуночи UTC, как в AWS. Дата Date принимается с точностью до секунды и исполняется в указанный момент, тогда как AWS требует, чтобы дата указывала на полночь.

Переход выполняется только в класс с более редким доступом: класс назначения должен находиться в карте классов ниже текущего, иначе конфигурация отклоняется с ответом InvalidArgument. Переходы вычисляются тем же проходом, что и удаление. Версия, срок перехода которой наступил, ставится в очередь s3r_t<N>_transition. Фоновый процесс transition переписывает её данные в группу яруса нового класса тем же путём, что и запись, обновляет строку объекта и добавляет прежние фрагменты в очередь сборки мусора. До завершения переноса объект читается из прежнего размещения. Для объекта, хранящегося в строке метаданных, переход меняет только метку класса. В кластере с единственным ярусом переход также сводится к смене метки, и классом назначения может быть любое имя класса AWS.

Если объект попадает под действующее правило удаления, ответы GET и HEAD содержат заголовок x-amz-expiration с датой удаления и идентификатором правила. Значение вычисляется по правилам при каждом запросе и после изменения правил сразу отражает новые сроки.

Правила выполняет фоновый процесс lifecycle. Проверить действие правил, не дожидаясь очередного прохода, можно через диагностическую конечную точку, описанную в главе «Администрирование».

Блокировка объектов

Блокировка объектов включается только при создании бакета и требует версионирования.

aws s3api create-bucket --bucket vault --object-lock-enabled-for-bucket

# Режим и срок хранения по умолчанию для новых объектов
aws s3api put-object-lock-configuration --bucket vault \
    --object-lock-configuration \
    'ObjectLockEnabled=Enabled,Rule={DefaultRetention={Mode=GOVERNANCE,Days=30}}'

# Срок хранения отдельной версии
aws s3api put-object-retention --bucket vault --key contract.pdf \
    --retention 'Mode=COMPLIANCE,RetainUntilDate=2027-01-01T00:00:00Z'

# Юридическое удержание без срока
aws s3api put-object-legal-hold --bucket vault --key contract.pdf \
    --legal-hold Status=ON

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

Действие Без обхода С обходом режима GOVERNANCE
Удаление версии в режиме GOVERNANCE отклоняется разрешено
Удаление версии в режиме COMPLIANCE отклоняется отклоняется
Сокращение срока в режиме GOVERNANCE отклоняется разрешено
Продление срока в любом режиме разрешено разрешено
Смена режима GOVERNANCE на COMPLIANCE отклоняется разрешено
Смена режима COMPLIANCE на GOVERNANCE отклоняется отклоняется
Удаление версии с юридическим удержанием отклоняется отклоняется

Обход режима GOVERNANCE запрашивается заголовком x-amz-bypass-governance-retention: true и требует права s3:BypassGovernanceRetention. Режим COMPLIANCE не обходится никем, включая владельца бакета. Юридическое удержание снимается запросом PutObjectLegalHold со значением Status=OFF и требует права s3:PutObjectLegalHold.

aws s3api delete-object --bucket vault --key contract.pdf \
    --version-id 0000019874f3a1c2 --bypass-governance-retention

Внимание

Срок хранения сравнивается с системными часами узлов. Если часы отстают или переведены назад, срок хранения в режиме COMPLIANCE истечёт раньше назначенного. На узлах хранилища требуется синхронизация времени.

Атрибуты объекта

GetObjectAttributes возвращает запрошенные сведения об объекте одним ответом, без чтения содержимого.

aws s3api get-object-attributes --bucket documents --key big.bin \
    --object-attributes ETag ObjectSize StorageClass ObjectParts

Для объекта, собранного составной загрузкой, атрибут ObjectParts перечисляет части с номерами и размерами и поддерживает постраничный обход с параметрами --max-parts и --part-number-marker.

В отличие от Amazon S3, поле ETag в ответе этой операции сейчас возвращается в кавычках, что связано с представлением значения в используемой библиотеке протокола. Для проверки содержимого используйте атрибут Checksum.

Массовое удаление

cat > delete.json <<'EOF'
{"Objects": [{"Key": "a.txt"}, {"Key": "b.txt", "VersionId": "0000019874f3a1c2"}],
 "Quiet": false}
EOF

aws s3api delete-objects --bucket documents --delete file://delete.json

Один запрос принимает до 1000 ключей. Права проверяются для каждого ключа отдельно, поэтому часть ключей в ответе может оказаться в списке Deleted, а часть в списке Errors.

Предподписанные ссылки и анонимный доступ

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

aws s3 presign s3://documents/report.pdf --expires-in 3600

Анонимное обращение разрешает либо предопределённый список управления доступом public-read, либо политика бакета с "Principal": "*".

aws s3api put-object-acl --bucket documents --key public/logo.png --acl public-read
curl http://node1:8000/documents/public/logo.png

Потоковая загрузка

Поддерживаются клиенты, которые подписывают тело запроса частями (Content-Encoding: aws-chunked, x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD). Тело запроса при этом не накапливается в памяти целиком: фрагменты блоков кодируются и рассылаются по мере поступления данных, поэтому размер объекта ограничен только свободным местом.

Администрирование

Сводный перечень административных действий с запросами API управления и командами SQL приведён в приложении Д.

Квоты и ограничение скорости

Квоты задаются в консоли или через API управления: разделы /v2/quotas/tenant_quota и /v2/quotas/bucket_quota, а для бакета также /v2/buckets/{бакет}/quota. В установке с включённым control_api следует пользоваться этим способом.

Ниже описана таблица, которая хранит данные этих запросов. Её устройство полезно знать в двух случаях: когда API управления не включён и квоту нужно задать средствами SQL, и когда нужно понять, что именно означает установленное ограничение. Остальные таблицы плагина не являются его интерфейсом, и их состав может меняться между выпусками без предупреждения.

Квоты хранятся в строках глобальной таблицы s3r_quota, и отсутствие строки означает отсутствие соответствующего ограничения. Каждая строка содержит идентификатор арендатора tenant_id, область scope, цель target, вид kind, предел value и, для ограничений скорости, допустимый кратковременный всплеск burst. Изменять таблицу может пользователь с ролью s3r_superuser.

Области действия квоты:

  • tenant: весь арендатор; значение target должно быть пустой строкой;
  • user: пользователь Picodata, указанный в target;
  • bucket: бакет, указанный в target.

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

kind Единица и действие при достижении предела
read_rate, write_rate запросы в секунду; сервер отвечает 503 SlowDown с заголовком Retry-After
read_bytes, write_bytes байты в секунду; передача замедляется до заданной скорости, а ожидание при приёме данных ограничено временем внутренней обработки, после которого возможен ответ 503 SlowDown
buckets число бакетов; CreateBucket отвечает TooManyBuckets
bytes, objects хранимый объём и число версий объектов; отказ возвращается ответом 403 QuotaExceeded

Значение burst задаётся в запросах для видов *_rate и в байтах для видов *_bytes, а для остальных видов должно быть равно NULL. Потребление хранимого объёма и числа объектов хранится в таблице s3r_quota_usage. Доли ограничений скорости данного инстанса и дерево их распределения показывает GET /-/debug/quota.

-- Весь арендатор 0: не более 100 бакетов
INSERT INTO s3r_quota
       (tenant_id, scope, target, kind, value, burst)
VALUES (0, 'tenant', '', 'buckets', 100, NULL);

-- Пользователь alice: 200 запросов на чтение в секунду,
-- с кратковременным всплеском до 400 запросов
INSERT INTO s3r_quota
       (tenant_id, scope, target, kind, value, burst)
VALUES (0, 'user', 'alice', 'read_rate', 200, 400);

-- Бакет archive: не более 1 ТБ
INSERT INTO s3r_quota
       (tenant_id, scope, target, kind, value, burst)
VALUES (0, 'bucket', 'archive', 'bytes', 1000000000000, NULL);

SELECT scope, target, kind, value, burst
  FROM s3r_quota WHERE tenant_id = 0;
SELECT scope, target, kind, used
  FROM s3r_quota_usage WHERE tenant_id = 0;

-- Удаление строки снимает только это ограничение
DELETE FROM s3r_quota
 WHERE tenant_id = 0 AND scope = 'user'
   AND target = 'alice' AND kind = 'read_rate';

Те же ограничения всех видов, включая ограничения скорости, задаются в консоли на экране «Quotas» и через API управления:

GET /v2/quotas?tenant_id=0
PUT /v2/quotas?tenant_id=0
{"scope": "user", "target": "alice", "kind": "read_rate", "value": 200, "burst": 400}

Значение null снимает ограничение, а ответ содержит все ограничения арендатора после изменения. Потребление сообщается для видов, которые его накапливают. У ограничений скорости потребления нет, потому что они ограничивают допуск запросов, а не накопленный объём.

Изменение квоты не перекодирует и не удаляет уже записанные данные. При первом добавлении квоты bytes или objects имеющиеся объекты учитываются сканированием пространства имён. Известные границы точности учёта и его восстановления после аварии перечислены в главе «Ограничения», раздел «Квоты».

Состояние кластера

Диски и группы размещения описаны глобальными таблицами, и их состояние доступно через запросы SQL.

-- Диски, их принадлежность, домены отказа и ярусы
SELECT instance_name, path, site, failure_domain, tier, state,
       capacity_bytes, extent_count
  FROM s3r_disk
 ORDER BY instance_name;

-- Группы размещения и их геометрия
SELECT pg_id, epoch, site, tier, k, m, block_bytes, state, members
  FROM s3r_pg
 ORDER BY pg_id;

-- Занятость дисков по числу экстентов
SELECT disk_id, count(*) FROM s3r_extent GROUP BY disk_id;

-- Распределение объектов арендатора 0 по внутреннему способу размещения
SELECT class, count(*) FROM s3r_t0_object
 WHERE part_no = 0 GROUP BY class;

-- Распределение объектов арендатора 0 по классам хранения S3
SELECT storage_class, count(*) FROM s3r_t0_object
 WHERE part_no = 0 GROUP BY storage_class;

Диск находится в одном из состояний opening, active, draining или lost, группа размещения в одном из состояний clean, degraded или repairing. Столбец members содержит отображение идентификатора диска в номер его позиции в группе. Переходы между состояниями показаны на схеме:

Состояния диска и группы размещения

Замена исправного диска

Состояние draining означает перевод диска в обслуживание, а не отказ. Диск продолжает отвечать на чтения, планировщик перестаёт размещать на нём новые группы, а слоты диска переносятся на другие диски той же площадки и того же яруса, и записи при этом не прекращаются. Диск можно извлекать, когда ответ GET /v2/disks показывает drained: true, то есть когда диск не входит ни в одну группу размещения.

Перевод в обслуживание выполняется запросом к API управления:

curl -u ivanov -X PUT https://mhd.example.ru:6006/s3gateway/api/v2/disks/{диск}/maintenance \
  -H 'content-type: application/json' -d '{"in_service": false}'

Слоты переносятся по одной группе за раз, потому что перестраиваемая группа не принимает записи. Если в пределах площадки и яруса не остаётся ни одной чистой группы, перенос не начинается и в журнал записывается предупреждение: для продолжения нужен ещё один диск. В веб-консоли ход переноса показан на экране «Кластер».

Запрос с {"in_service": true} отменяет незавершённый перевод. Отмена не является откатом: перенесённые слоты остаются на новых дисках, а диск снова становится доступен планировщику. Перезапуск инстанса перевод в обслуживание не отменяет.

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

Диагностические конечные точки

Диагностические конечные точки обслуживаются на порту S3 по путям, начинающимся с /-/, и подписи не требуют. Набор доступных конечных точек задаётся параметром s3r_api.diagnostics:

Значение Что доступно
health (по умолчанию) только /-/health
debug конечные точки /-/debug/*, кроме средств внесения ошибок и повреждения данных
bench все конечные точки, включая /-/bench/* и средства внесения ошибок и повреждения данных

Порт S3 обычно доступен клиентам, а пути /-/ обслуживаются до проверки подписи, чтобы проверка наличия процесса работала и при ошибках аутентификации. Уровень debug раскрывает состав кластера, адреса узлов, план размещения и пути к дискам. Обращение к конечной точке, недоступной на текущем уровне, возвращает 404 с командой, которая включает нужный уровень.

Внимание

Уровень bench выполняет ресурсоёмкие операции и открывает средства намеренного повреждения данных. Его следует применять только в изолированном испытательном контуре.

Путь Уровень Назначение
GET /-/health health проверка наличия процесса; готовность дисков, групп размещения и фоновых процессов не проверяется
/-/debug/cluster debug состав кластера: инстансы, пригодные для размещения данных
/-/debug/peers debug адреса обмена фрагментами блоков из таблицы _pico_peer_address
/-/debug/replicasets debug репликасеты тира Picodata, их состав и фактор репликации
/-/debug/topology debug группы размещения, которые были бы созданы для заданной формы; параметры k, m, replicas
/-/debug/disks debug диски данного инстанса, их ярус и число хранимых фрагментов блоков
/-/debug/repair debug очередь восстановления: что подлежит перестроению и на какой стадии
/-/debug/catalog debug отчёт о проверке каталога на данном инстансе: найденные расхождения и то, что можно восстановить
/-/debug/quota debug распределение долей ограничений скорости на данном инстансе
/-/debug/admission debug общий объём памяти api_memory, свободная и занятая части
/-/debug/bucket-id debug вычисление номера шарда vshard для ключа
/-/debug/frag-in debug вычисление служебного фрагмента для заданного шарда vshard
/-/debug/bucket-ref debug проверка получения ссылки vshard для чтения или записи
/-/debug/binary-sql debug проверка представления двоичных данных в текстовых столбцах
/-/debug/shard debug поиск указанного фрагмента блока на дисках данного инстанса
/-/debug/run/<процесс> debug немедленное выполнение одного прохода фонового процесса
/-/debug/pause/<процесс> debug приостановка фонового процесса
/-/debug/resume/<процесс> debug возобновление фонового процесса
/-/bench/bridge bench измерение пропускной способности взаимодействия с потоком TX
/-/bench/access bench измерение стоимости проверки прав
/-/bench/list bench измерение отдельных этапов перечисления объектов
/-/debug/errinj bench включение точки внесения ошибок
/-/debug/gate bench установка барьера, который задерживает запрос в заданной точке обработки
POST /-/debug/drop-shard bench удаление указанного фрагмента с диска
POST /-/debug/corrupt bench намеренное изменение содержимого фрагмента
/-/debug/rewind bench намеренное удаление строк каталогов для проверки их восстановления

Конечные точки errinj, gate, drop-shard, corrupt и rewind изменяют поведение или данные и предназначены только для автоматизированных испытаний. Ответы уровней debug и bench не являются интерфейсом мониторинга со стабильной схемой.

Конечная точка /-/debug/disks сообщает только о дисках того инстанса, к которому обращён запрос, и берёт число фрагментов из индекса самого диска. Столбец s3r_extent.used_bytes отвечает на другой вопрос: он записывается при закрытии экстента, поэтому для открытого экстента показывает ноль независимо от того, сколько в него записано.

Проверка возможности собрать группу формы 8+4 в текущей топологии:

curl -s "http://node1:8000/-/debug/topology?k=8&m=4"

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

Фоновые процессы

Работу, которая не выполняется в ходе обработки запроса, ведут фоновые процессы. Процесс запускается изменением таблицы, наступлением сохранённого срока или резервным таймером на случай пропущенного уведомления.

Имя для /-/debug/run Назначение
repair восстановление потерянного фрагмента группы размещения по сохранившимся фрагментам
scrub проверка согласованности данных и фрагментов чётности в группах размещения
compact уплотнение экстентов, в которых доля живых данных ниже compact_live_percent
gc освобождение фрагментов объектов, удалённых из пространства имён
bucketgc освобождение того, что осталось после удаления бакета
dirgc удаление строк опустевших каталогов
orphan обход запечатанных экстентов, проверка контрольных сумм и удаление фрагментов без строки объекта
mpu отмена составных загрузок, заброшенных дольше mpu_abandon_after_s
lifecycle применение правил жизненного цикла
transition перенос объектов между ярусами по правилам жизненного цикла
siterepl досылка объектов на площадки, где их ещё нет
siterepl-reconcile сверка содержимого площадок между собой
shortfall дозапись фрагментов, не принятых в момент записи
tenants согласование состояния арендаторов и их таблиц
catalog сверка каталога с дисками и восстановление производных записей, например строк каталогов над существующими объектами
dedup перенос сведений о совпадениях содержимого в индекс дедупликации
seal закрытие открытого экстента на каждом локальном диске
superblock обновление сведений о группах размещения в суперблоках дисков
views принудительное обновление представлений кластера и карты размещения
dirgc-unchecked удаление строк каталогов без предварительной проверки на пустоту; только для испытаний

Имена seal и views обозначают служебные действия, а не постоянно работающие процессы. Процесс catalog запускается сам с периодом, который по умолчанию равен 336 часам (двум неделям) и меняется запросом PUT /v2/reconcile с телом {"every_hours": N}; значение 0 отключает запуск по расписанию. После события, которое кластер не может обнаружить сам, например отказа нескольких дисков одновременно, отключения питания или извлечения дисков вручную, внеочередной проход запускается запросом POST /v2/reconcile. Время и результат последнего прохода возвращает GET /v2/reconcile. Проход процесса или служебное действие выполняется немедленно обращением к /-/debug/run/<имя>:

# Применить правила жизненного цикла сейчас
curl -s "http://node1:8000/-/debug/run/lifecycle"

# Применить их так, как если бы наступило заданное время (секунды с начала эпохи Unix)
curl -s "http://node1:8000/-/debug/run/lifecycle?as_of=1800000000"

# Освободить место после удаления объектов
curl -s "http://node1:8000/-/debug/run/gc"
curl -s "http://node1:8000/-/debug/run/compact"

Параметр as_of процесса lifecycle задаёт момент в секундах с начала эпохи Unix (unix time), на который вычисляются сроки, поэтому правило со сроком в тридцать дней можно проверить сразу, не переводя системное время.

Приостановка и возобновление (pause и resume) поддерживаются для процессов gc, dirgc, siterepl, shortfall, repair, superblock, compact, orphan, scrub, tenants, transition и dedup. Процессы compact и orphan приостанавливаются и возобновляются только вместе. Приостановка позволяет, например, отложить восстановление на время испытаний под клиентской нагрузкой.

Целостность и восстановление

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

-- Очередь восстановления: слот группы, целевой диск, стадия
SELECT pg_id, slot, target_disk, state, blocks_done, blocks_failed
  FROM s3r_repair ORDER BY pg_id;

-- Ход проверки контрольных сумм запечатанных экстентов по дискам
SELECT disk_id, cursor_extent, cursor_offset, last_full_sweep_at,
       chunks_verified, chunks_bad, repaired, quarantined
  FROM s3r_scrub ORDER BY disk_id;

-- Блоки арендатора 0, которые восстановить не удалось
SELECT * FROM s3r_t0_quarantine;

Восстановление читает все сохранившиеся фрагменты блока, а не только первые k, поэтому результат проверяется по избыточным фрагментам, и повреждённый фрагмент среди сохранившихся обнаруживается. Блок, для которого сохранившихся фрагментов недостаточно, помещается в карантин и перечисляется в таблице s3r_t<N>_quarantine своего арендатора вместе с объектом, которому принадлежит.

Ход восстановления показывает также конечная точка /-/debug/repair.

Занятость и освобождение места

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

Освобождённое место становится доступным для повторного использования после уплотнения: экстент, в котором доля живых данных упала ниже compact_live_percent, переписывается, а его файл используется повторно.

-- Число экстентов на каждом диске и занятый в них объём
SELECT disk_id, count(*), sum(used_bytes) FROM s3r_extent GROUP BY disk_id;

-- Очередь освобождения арендатора 0
SELECT count(*) FROM s3r_t0_gc;

Наблюдение за межплощадочной репликацией

Устройство межплощадочной репликации описано в главе «Классы хранения и группы размещения». Отдельной настройки она не требует: площадка задаётся компонентом dc домена отказа инстанса.

-- Объекты арендатора 0, которые есть не на всех площадках
SELECT count(*) FROM s3r_t0_siterepl;

-- Карта размещения объекта по площадкам
SELECT name, placements FROM s3r_t0_object
 WHERE name = 'report.pdf' AND part_no = 0;

Пустая таблица s3r_t<N>_siterepl означает, что у арендатора нет ожидающих межплощадочных копий.

Метрики

Плагин публикует метрики в формате Prometheus через конечную точку Picodata /metrics. Каждый инстанс публикует собственные ряды, а суммирование по кластеру выполняет Prometheus. Метки метрик имеют ограниченное число значений, поэтому имя пользователя и имя бакета меткой не служат.

В первую очередь контролируются следующие метрики:

  • s3r_placement_groups с меткой state="degraded": число групп размещения с пониженной избыточностью;
  • s3r_repair_queue_depth и s3r_shortfall_pending: очереди восстановления и дозаписи фрагментов;
  • s3r_ec_reconstructions_total: восстановления блоков при чтении, число которых на исправном кластере не растёт;
  • s3r_scrub_inconsistent_total: расхождения данных чётности, которые означают ошибку записи или искажение данных;
  • s3r_worker_runs_total: проходы фоновых процессов; если очередь растёт, а счётчик не меняется, процесс не выполняет задания.

В репозитории плагина поставляются панель Grafana deploy/grafana/s3r-dashboard.json и правила Prometheus deploy/prometheus/s3r-alerts.yml. Панель состоит из четырёх рядов: обслуживание запросов, исправность кластера, нагрузка и свободное место. Правила задают выражения, а условия оповещения определяет служба эксплуатации.

Ниже перечислены семейства метрик по сервисам. Тип указан словом: счётчик накапливает значение, датчик отражает текущее значение, гистограмма показывает распределение.

Сервис s3r_api:

Метрика Метки Значение
s3r_requests_total op, status счётчик обслуженных запросов S3
s3r_request_duration_seconds op гистограмма длительности запроса
s3r_request_bytes_total op, direction счётчик переданных байт объекта
s3r_requests_in_flight датчик числа запросов в обработке
s3r_admission_bytes датчик объёма памяти, занятой обрабатываемыми запросами
s3r_admission_rejected_total счётчик запросов, отклонённых из-за ограничения памяти
s3r_auth_failures_total reason счётчик отказов аутентификации и авторизации
s3r_quota_rejected_total scope, limit отказы по квотам на число бакетов, число объектов и объём данных
s3r_ratelimit_rejected_total scope отказы по ограничениям частоты запросов и скорости передачи
s3r_class_refused_total class отказы записи из-за отсутствия группы размещения для класса на площадке

Сервис s3r_meta:

Метрика Метки Значение
s3r_cache_lookups_total kind, result обращения к кэшу атрибутов
s3r_cas_retries_total operation повторы операции «сравнить и заменить» (CAS) из-за одновременного изменения данных
s3r_bridge_wait_seconds гистограмма ожидания задания в очереди к потоку TX
s3r_meta_rpc_total op обращения к другим репликасетам за метаданными; показывает, во сколько обращений обходится запись, в частности по одному на каждый каталог в пути ключа
s3r_bridge_queue_depth датчик числа заданий в очереди к потоку TX
s3r_bridge_rejected_total задания, отклонённые при остановке сервиса
s3r_cache_attr_bytes датчик объёма атрибутов в кэше
s3r_tenants датчик числа арендаторов в кластере
s3r_dedup_index_entries tier, shape число записей в индексе дедупликации
s3r_dedup_duplicate_parts tier, shape число частей объектов с ранее зарегистрированным совпадающим содержимым
s3r_dedup_duplicate_bytes tier, shape объём совпадающего содержимого, освобождаемый разделением
s3r_dedup_resolves_total found чтения объектов через общую копию содержимого; метка local означает, что общая копия находится на том же инстансе, routed означает одно обращение к инстансу с копией, no означает, что общей копии уже нет

Сервис s3r_storage:

Метрика Метки Значение
s3r_disks датчик числа смонтированных дисков
s3r_shard_ops_total op, path, result операции обмена фрагментами блоков, локально или по сети
s3r_shard_bytes_total path, direction объём фрагментов блоков по пути и направлению
s3r_shard_network_seconds гистограмма времени сетевой операции с фрагментом блока
s3r_disk_io_seconds disk, op гистограмма времени ввода-вывода на диск
s3r_disk_capacity_bytes disk датчик ёмкости диска
s3r_disk_used_bytes disk датчик занятого объёма диска; вместе с ёмкостью даёт заполненность
s3r_extents disk, state датчик числа экстентов по состоянию: free, open, sealed
s3r_disks_drained датчик числа выведенных дисков, которые больше не входят ни в одну группу размещения и могут быть извлечены
s3r_drain_stalled датчик числа групп размещения, вывод диска из которых невозможен без нового диска в пуле
s3r_ec_reconstructions_total восстановления блока из сохранившихся фрагментов
s3r_placement_groups state датчик числа групп размещения по состоянию
s3r_pg_unreadable датчик числа групп размещения, в которых сохранившихся фрагментов меньше, чем требуется для чтения
s3r_quarantine_objects датчик числа объектов, которые не удалось восстановить
s3r_repair_queue_depth state датчик глубины очереди восстановления
s3r_shortfall_pending датчик числа фрагментов, ожидающих дозаписи
s3r_worker_runs_total worker, result проходы фоновых процессов
s3r_worker_duration_seconds worker гистограмма длительности прохода фонового процесса
s3r_scrub_stripes_checked_total полосы контрольных сумм, проверенные по данным чётности
s3r_scrub_inconsistent_total полосы с расхождением данных чётности
s3r_scrub_groups датчик числа групп размещения, проверку которых ведёт этот инстанс
s3r_scrub_oldest_sample_timestamp_seconds время последнего полного прохода по самой давно проверявшейся группе, в секундах с начала эпохи Unix; ноль, если группа не проверялась ни разу
s3r_scrub_staleness_bound_seconds допустимый возраст последнего полного прохода из настроек кластера
s3r_repair_bytes_total объём данных, восстановленных фоновым процессом
s3r_gc_reclaimed_bytes_total байты, освобождённые сборкой мусора
s3r_compact_extents_total экстенты, освобождённые уплотнением
s3r_compression_bytes_total direction объём данных до и после сжатия: logical и stored
s3r_transition_total result завершённые попытки перехода между классами хранения по результату
s3r_transition_bytes_total объём данных, переписанных при переходах между классами

Журнал

Плагин записывает сообщения в журнал инстанса Picodata и наследует уровень подробности от настройки Picodata: при уровне журнала debug отладочные сообщения плагина выводятся вместе с сообщениями СУБД.

Сообщения, которые подтверждают штатный запуск:

Сообщение Значение
s3r_storage started, configured with N disk(s), listening on ..., advertised as ... сервис принял конфигурацию; число дисков указано по конфигурации, до их монтирования
disk <uuid> at <path> mounted: ... tier ..., domain ... диск смонтирован; указаны его ярус и полный домен отказа
disk <uuid> at <path> recovered: N shard(s) индекс диска восстановлен после перезапуска; указано число найденных фрагментов
shard endpoint serving on ... over mutual TLS узел принимает запросы обмена фрагментами; в конце указан режим шифрования
placement group N created in site ... tier ... создана группа размещения; указаны число участников и доменов и устойчивость к потере домена и инстанса

Сообщение no disk of this instance came up; it stores nothing означает, что на инстансе не смонтирован ни один диск.

Балансировка нагрузки

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

Для проверки доступности процесса балансировщик может использовать конечную точку /-/health, которая не требует подписи. Ответ 200 подтверждает только работу слушателя S3, но не готовность дисков, групп размещения и фоновых процессов, поэтому состояние хранилища контролируется отдельно по метрикам и очередям.

curl -sf http://node1:8000/-/health && echo up

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

Отказы и восстановление

Отказ диска

Группа размещения, потерявшая не более m участников, продолжает обслуживать чтение, и недостающие фрагменты вычисляются во время чтения. Одновременно в очередь s3r_repair ставится задание на перестроение потерянного слота на другом диске. Запись в группу продолжается, пока в ней остаётся не менее k + m − write_tolerance доступных участников и не менее k.

Отказ узла хранения

Участники группы находятся в различных доменах отказа, поэтому отказ одного узла лишает группу одного слота, как и отказ диска. При обычном перезапуске хранилище блоков восстанавливает индекс из снимка и журнала на диске, а недостающие фрагменты дописывают процессы repair и shortfall. Инстанс, исключённый из кластера, к обмену фрагментами не допускается.

Отказ площадки

Объект читается с другой площадки только после того, как запись этой площадки в placements перешла в состояние live. Если межплощадочная копия ещё находилась в состоянии pending, потеря единственной площадки с данными делает содержимое объекта недоступным. Доступность метаданных зависит от сохранения кворума Raft для глобальных таблиц и от доступности реплик репликасетов для таблиц пространства имён.

Сетевой сбой

Отдельных действий не требуется. Фрагменты, не принятые в момент записи, перечислены в s3r_shortfall и дописываются процессом shortfall после восстановления связности. Объекты, ещё не переданные на другую площадку, перечислены в s3r_t<N>_siterepl и досылаются процессом siterepl.

Проверка завершения работы:

SELECT count(*) FROM s3r_repair;      -- 0: перестраивать нечего
SELECT count(*) FROM s3r_shortfall;   -- 0: недописанных фрагментов нет
SELECT count(*) FROM s3r_t0_siterepl; -- 0: у арендатора 0 нет ожидающих копий

Добавление и вывод дисков

Новый диск добавляется в следующем порядке.

  1. Подготовьте каталог на новом устройстве.
  2. Добавьте путь в переменную S3R_DISKS инстанса либо в параметр s3r_storage.disks, если пути дисков совпадают на всех узлах.
  3. Перезапустите инстанс.

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

Новый диск форматируется, регистрируется в таблице s3r_disk и становится кандидатом для новых групп размещения. Состав существующих групп при этом не меняется, и фрагменты блоков между группами не переносятся (см. главу «Ограничения»). Это не относится к штатной перебалансировке шардов vshard: Picodata переносит строки метаданных между репликасетами, а обращение к метаданным повторяется при устаревшем маршруте.

Примечание

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

Диски разной ёмкости и разных типов используются одновременно. Тип носителя (NVMe, SSD или HDD) автоматически не определяется: оператор назначает диску ярус свойством tier=, а карта классов хранения направляет объекты в группы соответствующего яруса.

Исправный диск выводится из эксплуатации через перевод в обслуживание, как описано в разделе «Замена исправного диска». После того как диск перестал входить в группы размещения, его путь удаляется из списка дисков, и инстанс перезапускается.

Внимание

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

Добавление и вывод узлов

Узел добавляется в кластер средствами Picodata. Диски узла регистрируются при первом запуске сервиса s3r_storage и становятся кандидатами для новых групп размещения.

Узел выводится исключением из кластера средствами Picodata. Группы, в которые входили его диски, переходят в состояние degraded, и их слоты перестраиваются на оставшихся дисках. До завершения перестроения избыточность понижена, поэтому узлы выводятся по одному, и перед выводом следующего узла нужно дождаться опустошения очереди s3r_repair.

Перезапуск

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

Инстанс возвращается с прежними адресами: Picodata отклоняет перезапуск инстанса с изменённым объявленным адресом iproto.

Ограничения

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

Интерфейс S3

Ограничение Описание Примечание
Удаление с многофакторным подтверждением (MFA Delete) Не поддерживается. Поле MFADelete в настройке версионирования и заголовок x-amz-mfa защиты не обеспечивают. Неизменяемость данных обеспечивается блокировкой объектов.
Шифрование на стороне сервера Операции PutBucketEncryption, GetBucketEncryption и DeleteBucketEncryption, заголовки x-amz-server-side-encryption и схема SSE-C не поддерживаются. Данные на дисках не шифруются. Данные на дисках шифруются средствами носителя или файловой системы. Шифрование трафика описано в главе «Шифрование трафика».
Загрузка формой из браузера (POST Object) Подстановка ${filename}, перенаправление по success_action_redirect и теги в поле формы не поддерживаются. Невыполненное условие политики возвращает ответ 400 вместо 403. Подпись, срок действия политики и условия eq, starts-with и content-length-range проверяются.
Уведомления о событиях Не поддерживаются. Изменения отслеживаются перечислением объектов либо запросом SQL к таблице s3r_t<N>_object.
Статический веб-сайт Конфигурация сайта сохраняется, но сайт не обслуживается: индексный документ, страница ошибки и правила перенаправления не применяются.
Журналирование обращений к бакету (PutBucketLogging) Не поддерживается. Запросы записываются в журнал инстанса.
Выборка внутри объекта (SelectObjectContent) Не поддерживается.
Каталожные бакеты S3 Express (ListDirectoryBuckets) Не поддерживаются.
Настройка репликации (PutBucketReplication) Не поддерживается. Межплощадочная репликация определяется топологией кластера, см. «Межплощадочная репликация».
Восстановление архивных объектов (RestoreObject) Не поддерживается. Объект в классе GLACIER или DEEP_ARCHIVE доступен для чтения сразу. См. «Классы хранения S3 и ярусы».
Перенос в класс с более частым доступом Правила жизненного цикла переносят объекты только в классы с более редким доступом.
Условия IpAddress и NotIpAddress Не поддерживаются в политике бакета. Инструкция с таким условием трактуется в пользу отказа.
Временные учётные данные (STS) и Bearer-токены Не поддерживаются. Срок действия ключа доступа не задаётся. Ключ действует, пока существуют запись о нём и пользователь, которому он выдан.
Интеграции Отправка событий в Kafka, вызов функций, интеграция с системами биллинга, драйвер CSI, векторный поиск и RDMA не поддерживаются.

Дедупликация и сжатие

Ограничение Описание Примечание
Объекты класса inline Не дедуплицируются и не сжимаются. Содержимое таких объектов хранится в строке метаданных.
Ранее записанные объекты Включение сжатия не сжимает записанные объекты. Копия, записанная до того, как содержимое стало общим, сохраняет собственные данные до перезаписи, и процесс согласования её не объединяет.
Выключение дедупликации Уже объединённое содержимое остаётся общим.
Граница дедупликации Дедупликация не выходит за пределы яруса.
Дедупликация без передачи содержимого Проверка совпадения по контрольной сумме до передачи тела и CopyObject без копирования данных не поддерживаются.
Выбор алгоритма сжатия Не поддерживается. Применяется алгоритм zstd. Сжатие включается для бакета или арендатора, уровень сжатия задаётся для арендатора.

Адресация и арендаторы

Ограничение Описание Примечание
Виртуально-хостовая адресация На точке входа по умолчанию поддерживается только адресация в стиле пути. Виртуально-хостовая адресация доступна для арендатора с заданным FQDN, см. «Адресация арендатора».
Пул дисков арендатора Не поддерживается. Столбец s3r_tenant.pool_id зарезервирован.
Межплощадочная репликация арендатора Репликацию нельзя включить или отключить для отдельного арендатора. См. «Репликация как свойство кластера».

Квоты

Ограничение Описание Примечание
Точность ограничения частоты и скорости Пока инстанс не получил свою долю общего предела, он применяет локальное ограничение, и суммарное значение может кратковременно превысить заданное. См. «Квоты и ограничение скорости».
Учёт потребления Таблица s3r_quota_usage не сверяется с хранимыми объектами автоматически. После аварийного завершения учтённый объём может быть завышен.

Хранение

Ограничение Описание Примечание
Тип носителя Тип носителя автоматически не определяется, кэширование на твердотельных накопителях не выполняется. Носители разделяются по ярусам свойством tier=, см. «Классы хранения S3 и ярусы».
Перебалансировка фрагментов Расширение кластера не переносит фрагменты блоков между группами размещения. Новые диски используются для новых групп. Перебалансировка метаданных средствами vshard выполняется.
Запись при write_tolerance = 0 Недоступность одного участника группы делает запись в группу невозможной. См. «Кворум записи».

Управление и эксплуатация

Ограничение Описание Примечание
Журнал действий пользователей S3 Не ведётся. Выгрузка событий по протоколу syslog и в формате CEF не поддерживается. Административные действия попадают в журнал аудита Picodata.
Набор ролей Роли фиксированы: s3r_superuser, s3r_observer и s3r_tenant_admin_<идентификатор>. Конструктора ролей и роли аудитора нет. См. «Роли».
Учётные записи из LDAP и двухфакторная аутентификация Средствами плагина не поддерживаются. Обе возможности настраиваются у внешнего поставщика аутентификации, см. «Первый вход в консоль управления».
Статистика обращений по бакетам В метриках не публикуется. Метрики перечислены в разделе «Метрики».
Конфигурация через API управления API управления не изменяет конфигурацию плагина и состав кластера. Конфигурация изменяется командой ALTER PLUGIN, состав кластера изменяется средствами Picodata.
Резервное копирование Процедура согласованного резервного копирования и восстановления кластера не определена. Снимок таблиц Picodata не содержит данных объектов, а копия каталогов дисков не содержит метаданных.
Обновление между версиями Обновление кластера с данными более ранних сборок и поочерёдное обновление инстансов разных версий не проверялись. Версия 2.0.0 является первым выпуском.

Проверенные границы

Ограничение Описание Примечание
Объём хранилища свыше 64 ПБ Установки такого объёма не испытывались. Программного ограничения нет.
Формы кодирования с числом фрагментов больше двадцати Не проверялись и целевым сценарием не являются. Например, форма 61+3.

Запуск без внешнего поставщика аутентификации

Поставщика OpenID Connect может не быть: изолированный контур, испытательный стенд, установка, куда Keycloak придёт позже. В таком кластере вход в консоль проверяет сама Picodata.

Для этого в настройке s3r_api.iam указывается auth_type со значением picodata. Консоль тогда спрашивает имя пользователя и пароль Picodata — те же, с которыми администратор подключается к кластеру через picodata connect. Ни поставщика, ни клиента, ни области (realm) не требуется.

Консоль и API управления работают полностью. Принципал — тот же пользователь Picodata, полномочия — те же роли: на них способ входа не влияет.

1. Кластер с установленным плагином

Порядок установки описан в разделе «Установка» и от способа входа не зависит: плагин ставится, миграции применяются, сервисы включаются. Для локального стенда достаточно cargo pike run, для установки вручную — команды от CREATE PLUGIN до ENABLE оттуда же.

Настройка iam для запуска не нужна. Инстанс поднимается и конечная точка S3 работает без неё: без iam недоступен только вход в консоль. Задать её можно когда угодно, на работающем кластере и без перезапуска.

Дополнительно потребуется один параметр конфигурации Picodata — instance.http_listen. На этом порте Picodata отдаёт консоль и API управления.

instance:
  http_listen: "0.0.0.0:6006"

Проверка того, что плагин установлен и включён:

SELECT name, version, enabled FROM _pico_plugin;

2. Настройка плагина

Выполняется через ALTER PLUGIN, перезапуск не требуется.

ALTER PLUGIN s3r 2.0.0 SET s3r_api.control_api = 'true';
ALTER PLUGIN s3r 2.0.0 SET s3r_api.iam = '{"auth_type": "picodata"}';

Весь раздел iam состоит из одной настройки: issuer, audience, client_id и адреса поставщика не указываются, потому что поставщика нет.

control_api по умолчанию выключен: существующая установка не должна получать поверхность управления просто оттого, что её обновили. Консоль и API управления обслуживаются встроенным HTTP-сервером Picodata — тем же, на котором работает её собственный веб-интерфейс, и на том же порте (шаг 1).

Значение picodata указывается явно. Кластер, в котором раздел iam не задан, во входе отказывает — и это намеренно: умолчание со смыслом «пускать всех» оставляет установку открытой по недосмотру.

3. Первый администратор

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

CREATE USER "ivanov" WITH PASSWORD 'Sup3rSecret...' USING scram-sha256;
GRANT "s3r_superuser" TO "ivanov";

Оба идентификатора — в двойных кавычках. Без кавычек Picodata приводит их к верхнему регистру, а роли создаются в нижнем, и выдача завершится ошибкой «нет такой роли».

Пароль здесь — это пароль от консоли. В установке с поставщиком он задаётся лишь потому, что Picodata требует указать способ аутентификации при создании пользователя, и при входе не спрашивается.

Роли те же, что и при работе с поставщиком: s3r_superuser, s3r_tenant_admin_<идентификатор>, s3r_observer — см. таблицу в разделе «Первый вход в консоль управления».

4. Вход

Адрес консоли — https://<адрес>:<порт>/s3gateway/console/. Вместо кнопки перенаправления к поставщику страница показывает форму с именем пользователя и паролем.

API управления в этом режиме принимает те же учётные данные в виде HTTP Basic:

curl -u ivanov -k https://mhd.example.ru:6006/s3gateway/api/v2/rights

Ответ содержит имя принципала и его роли — это самый короткий способ проверить, что вход настроен и роль выдана.

Чем этот режим отличается от работы с поставщиком

Пароль передаётся с каждым запросом. Сессии не создаётся, проверяется каждый запрос, поэтому нет ни таблицы сессий, ни ключа подписи, ни срока действия. Расплата за это — пароль в открытом виде на каждом запросе, поэтому консоль следует публиковать по HTTPS. На незащищённом соединении консоль предупреждает об этом на странице входа.

Отзыв выполняется средствами SQL и действует немедленно. ALTER USER с новым паролем или DROP USER закрывают доступ со следующего запроса; списка отозванных токенов здесь нет, потому что нет и токенов.

Ключи доступа S3 от режима входа не зависят. Подпись SigV4 проверяется по таблице учётных данных кластера и при любом auth_type работает одинаково.

Поставщик добавляется позже без перенастройки хранилища. Ключи доступа, бакеты и объекты от него не зависят: достаточно заменить раздел iam на настройки поставщика и продолжить с раздела «Первый вход в консоль управления». Пользователи Picodata при этом сохраняются — совпасть должно только имя, которое придёт в утверждении токена.

Первый вход в консоль управления

Этот раздел описывает путь от пустой установки до работающего входа в консоль через внешнего поставщика аутентификации. Шаги выполняются один раз и в указанном порядке.

Совет

Если поставщика аутентификации нет, пароль проверяет сам кластер, как описано в разделе «Запуск без внешнего поставщика аутентификации». Разворачивать Keycloak только ради входа в консоль не требуется.

Первый администратор создаётся средствами SQL: создать его через консоль нельзя, потому что для входа в консоль администратор уже нужен. Дальше всё делается через API управления.

1. Поставщик аутентификации

S3R доверяет ровно одному издателю токенов (issuer). Обычно это Keycloak. Если пользователи приходят из Google или другого внешнего каталога, Keycloak выступает посредником, и для S3R это ничего не меняет.

В области (realm) поставщика нужно создать клиента для консоли:

  • тип клиента — публичный (public), без секрета. Консоль — это код, выполняющийся в браузере: любой секрет, попавший в сборку, попадает и к пользователю. Вместо секрета используется PKCE;
  • разрешённый способ получения токена — код авторизации (authorization code) с PKCE (метод S256);
  • разрешённый адрес возврата (redirect URI) — адрес консоли со слешем на конце, например https://mhd.example.ru:6006/s3gateway/console/;
  • аудитория (aud) токена — значение, которое будет указано в настройке audience плагина. Токен без нужной аудитории отклоняется.

2. Утверждение с именем пользователя

Принципал S3R — это пользователь Picodata, и его имя берётся из утверждения (claim) токена. По умолчанию — preferred_username.

Форму имени стоит выбрать заранее. При посредничестве Keycloak имя локальной учётной записи часто заполняется из адреса электронной почты, и тогда preferred_username приходит в виде ivanov@example.ru. Для Picodata это допустимое имя, и работать будет всё. Но это же имя попадёт в каждую запись ACL, в каждую строку квоты и в каждую запись аудита. Если такая форма нежелательна, на стороне Keycloak настраивается отображение (claim mapper), выдающее короткое имя. Через год после первого входа сменить его гораздо дороже.

Имя утверждения меняется настройкой username_claim.

3. Первый пользователь Picodata

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

CREATE USER "ivanov" WITH PASSWORD 'Sup3rSecret...' USING scram-sha256;
GRANT "s3r_superuser" TO "ivanov";

Оба идентификатора — в двойных кавычках. Без кавычек Picodata приводит их к верхнему регистру, а роли создаются в нижнем, и выдача завершится ошибкой «нет такой роли».

Имя пользователя должно совпадать с тем, что придёт в утверждении токена (см. шаг 2). Если имена приходят в виде адресов почты, то и пользователь создаётся с таким именем: CREATE USER "ivanov@example.ru" ....

В установке, где пользователей заводит argus из каталога LDAP, пользователь уже существует — нужна только выдача роли.

Пароль в этой команде консолью не используется: вход выполняется по токену поставщика, и пароля консоль не спрашивает. Задать его приходится потому, что Picodata требует указать способ аутентификации при создании пользователя. Самая частая ошибка на этом шаге — принять его за пароль от консоли.

Роли

Роль Полномочия
s3r_superuser Весь кластер: арендаторы и их сертификаты, ярусы, обслуживание, все экраны и все операции
s3r_tenant_admin_<идентификатор> Пользователи, ключи и бакеты одного арендатора, чей идентификатор указан в имени роли
s3r_observer Только чтение: состояние кластера, ёмкость, группы размещения, восстановление

Роль администратора арендатора создаётся вместе с арендатором. Для арендатора по умолчанию это s3r_tenant_admin_0.

Внимание

При обновлении с версии, где роль называлась s3r_tenant_admin, выдачу нужно повторить с новым именем: GRANT "s3r_tenant_admin_0" TO "ivanov". Старой роли больше нет, и администратор арендатора без новой выдачи получит «не найдено» на свой собственный арендатор.

4. Настройка плагина

Выполняется через ALTER PLUGIN, перезапуск не требуется.

ALTER PLUGIN s3r 2.0.0 SET s3r_api.control_api = 'true';

ALTER PLUGIN s3r 2.0.0 SET s3r_api.iam = '{
  "auth_type": "keycloak",
  "auth_path": "https://keycloak.example.ru/realms/mhd/protocol/openid-connect/auth",
  "token_path": "https://keycloak.example.ru/realms/mhd/protocol/openid-connect/token",
  "issuer": "https://keycloak.example.ru/realms/mhd",
  "audience": "s3gateway",
  "client_id": "console",
  "username_claim": "preferred_username"
}';

control_api по умолчанию выключен: существующая установка не должна получать поверхность управления просто оттого, что её обновили.

auth_path и token_path указываются целиком, потому что их вид различается у разных поставщиков. Если они не заданы, адреса берутся из документа /.well-known/openid-configuration издателя.

Консоль и API управления обслуживаются встроенным HTTP-сервером Picodata — тем же, на котором работает её собственный веб-интерфейс. Порт задаётся параметром instance.http_listen в конфигурации Picodata (в программе испытаний — 6006).

5. Вход

Адрес консоли — https://<адрес>:<порт>/s3gateway/console/.

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

Вход в консоль управления

Если войти не удалось

Что видно Что это значит
Страница сообщает, что кластер не может никого аутентифицировать Настройка s3r_api.iam не задана. Шаг 4
Вход проходит, но консоль отвечает «нет такого принципала» (403) Токен подлинный, но пользователя Picodata с таким именем нет. Сравните утверждение токена с именем из шага 3 — чаще всего расходится форма имени
Вход проходит, экранов нет, операции запрещены (403) Пользователь есть, роль не выдана. Шаг 3
Арендатор отвечает «не найдено» (404) Нет роли s3r_tenant_admin_<идентификатор> этого арендатора. Ответ «не найдено», а не «запрещено», намеренно: ответ «запрещено» подтвердил бы, что такой арендатор существует
Ответ 503 с указанием, что поставщик недоступен Поставщик не отвечает. Это не выход из системы: уже выданные токены продолжают работать до истечения срока, а операции с данными по ключам S3 от поставщика не зависят вовсе
Страница сообщает, что консоль не собрана Сборка плагина выполнена без консоли. Соберите её и пересоберите плагин

Где живёт принципал консоли

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

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

Что умеет консоль управления

Консоль — веб-интерфейс, собранный в двоичный файл плагина и доступный по адресу https://<адрес>:<порт>/s3gateway/console/. Отдельного развёртывания она не требует, обновляется вместе с плагином и работает поверх того же API управления, что описано в следующей главе: всё перечисленное здесь можно выполнить и запросом.

Снимков экранов в руководстве нет намеренно: расположение элементов меняется от выпуска к выпуску, а перечень возможностей — нет. Ниже — что доступно и на каком разделе искать.

Разделы кластера

Эти разделы доступны обладателям s3r_superuser и s3r_observer; наблюдателю — только чтение.

Обзор

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

Сводка по подсистемам приходит из GET /v2/health: каждая запись несёт числа, по которым вынесена оценка, и то, что следует сделать. Отдельно отмечается ненастроенный публичный адрес S3 (s3r_api.s3_public_url либо домен арендатора): без него консоль не сможет загрузить файл, а предподписанная ссылка — быть выданной, поскольку подпись покрывает имя узла. На новой установке это первое, обо что спотыкается загрузка, поэтому состояние сообщает об этом заранее.

Кластер

Инстансы и диски с их состоянием. Диск переводится в режим обслуживания и возвращается из него; консоль показывает, безопасно ли извлекать диск сейчас и что на нём ещё лежит. Состав выгружается в файл.

Группы размещения

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

Восстановление

Очередь перестроения: работы с их стадией и долей выполненного, нехватка фрагментов, тишина как отдельное состояние. Отсюда же включается ручной режим и выполняются действия над отдельной работой — приостановить, возобновить, отказаться, повторить (см. «Управление восстановлением» в главе про API).

Репликация

Состояние межплощадочной репликации: что скопировано, что ещё должно, где отставание велико.

Целостность

Что нашла фоновая проверка данных и чётности, и что помещено в карантин.

Разделы арендатора

Арендаторы

Создание и удаление арендатора, его FQDN, сертификат TLS и материал mTLS, включая передачу сертификата и режим обязательного mTLS, срок действия и замену. Создание арендатора — операция, которая выполняется не мгновенно, и консоль показывает ожидание явно.

Пользователи и ключи

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

Бакеты

Список бакетов с владельцем и признаком версионирования, создание и удаление, передача бакета другому владельцу, включение блокировки объектов. Настройки бакета: версионирование, CORS, политика, сжатие, дедупликация, квота. Правила жизненного цикла редактируются отдельным разделом — срок жизни, переход в другой класс хранения, обращение со старыми версиями, обрыв незавершённых загрузок — и доступны также в виде JSON. Права на бакет задаются матрицей выдач.

Квоты

Ограничения арендатора, пользователя и бакета одним списком: хранимый объём, число версий объектов и бакетов, а также скоростные — запросы и байты в секунду на чтение и на запись, с величиной всплеска. Для накапливаемых видов рядом показано потребление.

Объекты

Обзор бакета по папкам, загрузка файла, скачивание и получение ссылки, которой можно поделиться. Загрузка и скачивание идут напрямую между браузером и конечной точкой S3 по подписанной ссылке, минуя плоскость управления; если бакет не разрешает обращение из браузера, консоль объясняет это и предлагает добавить нужное правило CORS.

Чего в консоли нет

Установка плагина, его конфигурация (ALTER PLUGIN), создание пользователей Picodata и выдача ролей выполняются средствами SQL: это операции уровня СУБД, и консоль их не подменяет. Состав кластера — тоже: узел вводится и выводится средствами Picodata (см. «Добавление и вывод узлов»).

API управления

Консоль не делает ничего, чего нельзя сделать запросом: она целиком построена на этом API. Поэтому всё, что описано в главах про арендаторов, пользователей, квоты и обслуживание, доступно и из скрипта — для автоматизации, разовой операции на сотне бакетов или интеграции с чужой системой управления.

Точное описание запросов и ответов — в файле doc/api/openapi.yaml репозитория плагина. Это спецификация OpenAPI: из неё генерируется клиент консоли, и она описывает каждое поле каждого ответа. Настоящая глава объясняет устройство и правила, спецификация определяет формат.

Адрес и включение

API обслуживает встроенный HTTP-сервер Picodata, тот же, на котором работает её собственный веб-интерфейс. Порт задаётся параметром instance.http_listen, базовый путь — /s3gateway/api, и публикуется поверхность настройкой s3r_api.control_api = 'true' (по умолчанию выключена).

Отвечает любой инстанс, на котором включён сервис s3r_api. Сессий нет, так что балансировщику не нужны «липкие» соединения: два последовательных запроса могут прийти на разные инстансы.

Аутентификация

Способ тот же, что и у консоли, и определяется настройкой s3r_api.iam.

При работе с поставщиком OpenID Connect запрос несёт маркер доступа:

curl -H "Authorization: Bearer $TOKEN" \
  https://mhd.example.ru:6006/s3gateway/api/v2/capacity

При auth_type: "picodata" — имя и пароль пользователя Picodata в виде HTTP Basic:

curl -u ivanov https://mhd.example.ru:6006/s3gateway/api/v2/capacity

Полномочия в обоих случаях определяют роли Picodata: s3r_superuser, s3r_tenant_admin_<идентификатор>, s3r_observer. Что даёт каждая, описано в разделе «Ролевая модель арендаторов» приложения А. Запрос к арендатору, роли которого у принципала нет, получает ответ «не найдено», а не «запрещено».

Начать удобно с GET /v2/rights: он отвечает именем принципала и списком его ролей, то есть сразу показывает, что учётные данные приняты и что этому принципалу разрешено.

Формат ответа

Успех и отказ имеют одну оболочку:

{"errors": [], "result": {"...": "..."}}

При отказе errors содержит сообщения для человека, а рядом приходит error_details — массив записей {code, resource, message}. Поле code устойчиво и предназначено для программы: Unauthenticated, Forbidden, NotFound, NameInUse, StaleVersion, PayloadTooLarge, RouteNotImplemented, ProviderUnavailable и коды уровня управления. Разбирать текст сообщений не нужно и не следует: тексты меняются, коды — нет.

Коды состояния HTTP обычные, с двумя, которые стоит знать заранее. Ответ 206 приходит на пакетную операцию, часть которой не удалась: выполненное перечислено в result, невыполненное — в errors и error_details. Ответ 409 с кодом NameInUse означает, что объект с таким именем уже есть.

Правила, о которых лучше знать заранее

Создание не идемпотентно. Повторный POST с тем же именем — это 409, а не повторная выдача уже созданного: два администратора, создающих одного арендатора, должны узнать об этом, а не получить по успешному ответу. Клиент, потерявший ответ, выполняет GET.

Постраничный вывод устроен по курсору, а не по номеру страницы. Ответ содержит курсор — непрозрачную метку последней выданной записи; следующая страница запрашивается с ней. Номеров страниц и общего числа записей нет: SQL Picodata не имеет OFFSET, и выдача по курсору вдобавок не пропускает и не повторяет записи при одновременном изменении данных.

Секретный ключ доступа возвращается один раз — в ответе на его выдачу или замену. Больше его не отдаёт ни один запрос: в таблице он хранится в виде, из которого исходный ключ не восстанавливается.

Одновременное изменение одного объекта разрешается по версии: запрос с устаревшей версией получает StaleVersion, и его следует повторить, прочитав свежее состояние.

Из чего состоит поверхность

Полный перечень — в спецификации; здесь разделы, чтобы понимать, где искать.

Раздел Маршруты О чём
Сессия /v2/start, /v2/code, /v2/rights, /v2/health способ входа, обмен кода на маркер, кто я и что мне можно, живость
Арендаторы /v2/tenants, /v2/tenants/extra_rights, /v2/tenants/{id}/mtls, /v2/tenants/{id}/set_mtls, /v2/tenants/{id}/load_mtls_cert создание и удаление арендаторов, их домены и клиентские сертификаты
Пользователи и ключи /v2/users, /v2/credentials, /v2/credentials/{ключ} учётные записи арендатора, выдача, замена и удаление ключей доступа, блокировка
Бакеты /v2/buckets, /v2/buckets/{бакет}/settings, /versioning, /cors, /policy, /lifecycle, /compression, /quota список бакетов, передача бакета другому владельцу (PUT /v2/buckets), настройки, те же, что задаются средствами S3
Доступ и квоты /v2/acl, /v2/quotas/tenant_quota, /v2/quotas/bucket_quota права на бакеты, ограничения по объёму и числу объектов
Объекты /v2/objects, /v2/objects/presign обзор содержимого бакета и подписанная ссылка на объект
Ёмкость и кластер /v2/capacity, /v2/cluster/servers, /v2/cluster/attention сколько занято и сколько осталось, состав кластера, что требует внимания
Диски /v2/disks, /v2/disks/{диск}/maintenance список дисков и перевод диска в обслуживание
Целостность /v2/integrity, /v2/repair, /v2/replication, /v2/memory проверка целостности, очередь восстановления, межплощадочная репликация, расход памяти под метаданные
Управление восстановлением /v2/repair/mode, /v2/repair/{группа}/{слот} ручной режим и действия над отдельной перестройкой; только s3r_superuser

Ввод и вывод узла кластера в этот перечень не входит, хотя маршруты для него предусмотрены спецификацией: add_server_to_storage, del_server_from_storage и их аналоги для S3 отвечают 501 и называют команду, которой это делается. Состав кластера меняет Picodata, а не плагин, — см. «Добавление и вывод узлов».

Обзорные разделы (/v2/capacity, /v2/cluster/*, /v2/disks, /v2/integrity, /v2/repair, /v2/replication) доступны и наблюдателю: они ничего не меняют. Всё, что меняет состояние кластера, требует s3r_superuser, а операции в пределах арендатора — его роли администратора.

Управление восстановлением

Перестройка потерянного фрагмента запускается сама: группа размещения, лишившаяся участника, ставится в очередь, и плагин перестраивает её на свободный диск. Обычно вмешиваться не нужно. Но бывает и иначе: идут работы в стойке и лишний трафик некстати; диск, на который идёт перестройка, ведёт себя подозрительно; перестройка трижды не удалась и стоит разобраться, прежде чем пробовать снова.

Состояние очереди читается запросом GET /v2/repair: он отвечает списком работ с их стадией, числом перестроенных и не перестроенных блоков, числом попыток, причиной последнего отказа и временем следующей, а также глубиной очереди и общим режимом.

Режим переключается запросом на /v2/repair/mode:

curl -u ivanov -X PUT https://mhd.example.ru:6006/s3gateway/api/v2/repair/mode   -H 'content-type: application/json' -d '{"mode": "manual"}'

В режиме manual новые перестройки не начинаются; уже идущие доводятся до конца. Значение auto возвращает обычное поведение. Переключение записывается в журнал инстанса и в таблицу с именем того, кто его выполнил: вопрос «почему ничего не восстанавливается» задают через несколько часов и обычно не тот, кто переключал.

Отдельная работа управляется запросом на /v2/repair/<группа>/<слот>:

curl -u ivanov -X PUT https://mhd.example.ru:6006/s3gateway/api/v2/repair/12/3   -H 'content-type: application/json' -d '{"action": "pause"}'
Действие Что делает
pause остановить на ближайшей контрольной точке, сохранив позицию
resume вернуть приостановленную работу в очередь
cancel отказаться от работы; группа возвращается в то же состояние, что и после отказа
retry начать заново работу, завершившуюся отказом, обнулив счётчик попыток

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

Неудавшаяся перестройка повторяется сама: три попытки с паузами в одну минуту, пять минут и час. После третьей работа остаётся в состоянии отказа и ждёт человека — дальнейшие автоматические попытки только повторяли бы одну и ту же ошибку. Причина отказа сохраняется и видна в ответе /v2/repair: недоступность источника, невозможность перестроить блок по сохранившимся фрагментам, ошибка записи на целевой диск.

Отличия от спецификации

Описание API управления, принятое в программе испытаний, в трёх местах расходится с тем, что здесь реализовано, и расхождения намеренные: постраничный вывод по курсору вместо номеров страниц, набор кодов состояния шире табличного, базовый путь /s3gateway/api. Перечень с обоснованием каждого — в doc/dev/CONTROL-API.md.

Диагностика типовых ситуаций

Плагин не включается, в сообщении приведены две версии

Несовпадение версии Picodata и версии библиотеки picodata-plugin, с которой собран плагин. Проверка установки:

SELECT name, version, enabled FROM _pico_plugin;
SELECT plugin, name, tiers FROM _pico_service WHERE plugin = 's3r';

Инстанс не запускается, сообщение has N disk(s) but no listener

На инстансе заданы диски и не задан слушатель s3r_storage в конфигурации Picodata. Отказ предусмотрен: без слушателя диски недоступны остальным узлам.

Диски не монтируются

Проверить наличие записи disk ... mounted в журнале инстанса. Отсутствие записи означает недоступность каталога, отсутствие поддержки io_uring или O_DIRECT в окружении либо принадлежность диска другому кластеру; в последнем случае журнал содержит оба идентификатора.

Группы размещения не создаются

Проверить ответ /-/debug/topology для нужной формы. Поле reason различает причины: no_disks — диски не объявлены; no_declared_subdomains — диски есть, но их поддомены отказа не позволяют собрать безопасную форму; not_enough_disks — в указанном ярусе и площадке недостаточно свободных дисков; not_enough_instances — недостаточно инстансов. Все диски также могут уже входить в группы, если форму кодирования добавили после начала заполнения кластера.

Запись возвращает ServiceUnavailable

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

Настроен TLS на слушателе s3r_storage, плагин не загружается

Раздел tls задан без ca_file. Сертификат подтверждает право узла запрашивать фрагменты блоков, поэтому цепочка без удостоверяющего центра не принимается; см. главу «Шифрование трафика».

Неясно, шифруется ли обмен фрагментами блоков

Найдите в журнале инстанса строку shard endpoint serving on ...: она заканчивается либо over mutual TLS, либо over plaintext; carry it over a trusted network.

Растёт время ответа на малых объектах

Смотреть метрику s3r_bridge_wait_secondss3r_bridge_queue_depth): рост времени ожидания в мосту — это то, что двигают параметры bridge_queue и bridge_fibers сервиса s3r_meta. Заполнение очереди означает, что поток TX достиг предела пропускной способности, и видно это как рост глубины очереди раньше, чем как рост задержки запросов.

Чтения возвращают устаревшие данные

Проверить параметр read_consistency: значение eventual разрешает чтение с реплик и гарантии «чтение видит запись» не даёт.

Приложение А. Таблицы плагина

Глобальные таблицы имеют постоянные имена. Таблицы пространства имён создаются отдельно для каждого арендатора и физически называются s3r_t<tenant_id>_<суффикс>: например, s3r_t0_object для арендатора 0 и s3r_t7_gc для арендатора 7. Обозначение <N> ниже — числовой tenant_id, а не часть имени таблицы.

Таблица Размещение Содержимое
s3r_tenant глобальная арендаторы, домены, состояние, сертификаты и параметры сжатия
s3r_seq глобальная счётчики выдаваемых идентификаторов
s3r_bucket глобальная бакеты: владельцы, права, политика, версионирование, правила жизненного цикла, блокировка объектов, теги
s3r_credential глобальная ключи доступа и сопоставление с пользователями
s3r_quota глобальная ограничения ресурсов
s3r_quota_usage шардированная по арендатору учтённое потребление хранимого объёма и числа объектов
s3r_hash шардированная по SHA-256 индекс совпадающего содержимого для дедупликации
s3r_dedup_ref шардированная по размещению общего объекта ссылки на общие объекты: по одной строке на каждый объект, который читает через общую копию
s3r_disk глобальная диски кластера, владельцы, домены отказа, ёмкость
s3r_pg глобальная группы размещения: состав, геометрия, эпоха
s3r_tier глобальная соответствие класса хранения тиру и геометрии
s3r_repair глобальная задания на восстановление потерянного слота группы
s3r_shortfall глобальная части, не принятые при записи и подлежащие дозаписи
s3r_clock глобальная нижняя граница гибридных логических часов репликасета
s3r_scrub_pg глобальная ход проверки данных и чётности в разрезе групп размещения
s3r_t<N>_object шардированная версии объектов: метаданные, теги, блокировка, внутренний способ размещения, класс хранения и карта размещения; part_no = 0 означает строку целого объекта
s3r_t<N>_dir шардированная каталоги для перечисления с разделителем
s3r_t<N>_mpu шардированная начатые составные загрузки
s3r_t<N>_mpu_part шардированная принятые части составных загрузок
s3r_t<N>_gc шардированная очередь освобождения фрагментов удалённых объектов
s3r_t<N>_dir_gc шардированная очередь проверки опустевших каталогов
s3r_t<N>_siterepl шардированная объекты, которые есть не на всех площадках
s3r_t<N>_quarantine шардированная блоки, восстановить которые не удалось
s3r_t<N>_transition шардированная очередь переходов между классами хранения
s3r_t<N>_hash_pending шардированная очередь обновления индекса дедупликации
s3r_extent шардированная по диску экстенты диска и их состояние
s3r_scrub шардированная по диску состояние фоновой проверки целостности диска

Таблицы пространства имён распределены по производным от бакета, каталога и фрагмента ключам; таблицы блокового хранилища — по диску. Они размещаются в тире Picodata, указанном параметром storage_tier. Строки видны запросу SQL, выполненному на инстансе этого тира.

Доступ к перечисленным таблицам дают связки табличных разрешений s3r_table_reader и s3r_table_writer. Их не выдают человеку: они входят в роли s3r_observer и s3r_superuser (см. «Ролевая модель арендаторов»).

Ролевая модель арендаторов

Миграции создают три роли. Субъект доступа S3 соответствует пользователю SQL Picodata, поэтому ролевая модель использует роли Picodata, а не отдельную таблицу плагина.

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

GRANT "s3r_superuser" TO "kosipov";

s3r_superuser

Роль s3r_superuser даёт полные полномочия над плагином в кластере: тиры и уровни избыточности, режим обслуживания, арендаторы и их сертификаты, а также доступ SQL ко всем таблицам плагина. Роль получает доступ к s3r_tenant: её обладатель создаёт арендаторов и их сертификаты, а также получает список арендаторов и сведения об их ёмкости с помощью SQL. Это единственная роль с правом чтения s3r_tenant, поскольку она же записывает в таблицу сертификаты.

s3r_observer

Роль s3r_observer даёт только чтение: ёмкость, состояние кластера и дисков, группы размещения, восстановление, проверка целостности. Роль для того, кто наблюдает за кластером и ничего в нём не меняет; без неё такому человеку пришлось бы выдать полномочия администратора. Секреты наблюдателю недоступны: s3r_credential хранит секретные ключи, s3r_tenant хранит закрытые ключи TLS, и обе таблицы выданы только s3r_superuser.

s3r_tenant_admin_<идентификатор>

Роль s3r_tenant_admin_<идентификатор> даёт управление пользователями, ключами и бакетами одного арендатора, идентификатор которого указан в имени роли. Такая роль создаётся для каждого арендатора: само полномочие нельзя выразить табличным разрешением, потому что s3r_credential является глобальной таблицей, а разрешение SQL нельзя сузить до строк одного арендатора. Область действия задаёт выдача роли.

Операции предоставляет API управления. Он принимает маркер доступа OIDC и арендатора в самом запросе, поэтому именно выданная роль определяет, к какому арендатору обращение допустимо. Арендатор, роли которого нет, отвечает «не найдено», а не «запрещено»: ответ «запрещено» подтвердил бы, что такой арендатор существует.

Роли не наследуют друг друга: если человеку нужны полномочия двух видов, ему выдают две роли. Имя роли администратора содержит идентификатор арендатора, а не его имя: идентификатор не переиспользуется после удаления арендатора, поэтому выданная роль никогда не станет означать другого арендатора, и переименование арендатора её не ломает.

Ответ на создание или замену ключа содержит секретный ключ доступа только один раз — больше его не возвращает ни один запрос:

Запрос Действие
GET /v2/users?tenant_id=<id> перечислить пользователей арендатора и их ключи (без секретов)
POST /v2/users зарегистрировать пользователя
PUT /v2/users?tenant_id=<id> заблокировать или разблокировать пользователей (state)
DELETE /v2/users?tenant_id=<id> удалить пользователей
POST /v2/credentials?tenant_id=<id> выдать ключ доступа
PUT /v2/credentials/<ключ>?tenant_id=<id> заменить секрет, сохранив ключ
DELETE /v2/credentials/<ключ>?tenant_id=<id> удалить ключ

Бакет можно передать другому владельцу: PUT /v2/buckets с именем бакета и именем нового владельца, он же — действие «передать» в консоли. Новый владелец должен быть принципалом того же арендатора. Прежний владелец не сохраняет ничего: передача, оставляющая ему полный доступ, передачей не является. В ответе назван тот, кто владение потерял, — больше нигде прежний владелец не записан.

Блокировка действует на пользователя, а не на отдельный ключ: все ключи пользователя переходят в состояние «отключён» вместе. Операция обратима — ключи остаются, и разблокировка возвращает то, что было.

CREATE USER — полномочие уровня кластера, которое нельзя сузить до арендатора. Поэтому администратор арендатора не получает это полномочие напрямую: пользователя Picodata создаёт плагин.

Приложение Б. Сетевые порты

Назначение Источник значения
Конечная точка S3 instance.plugin.s3r.service.s3r_api.listener либо S3R_API_LISTEN
Обмен фрагментами блоков между узлами instance.plugin.s3r.service.s3r_storage.listener
Диагностика плагина порт конечной точки S3, пути /-/
Веб-интерфейс Picodata, консоль и API управления S3R, метрики /metrics instance.http_listen

Консоль загружает и скачивает файлы по предподписанным ссылкам напрямую через конечную точку S3, поэтому браузеру администратора нужен доступ к двум портам: HTTP-порту Picodata и порту конечной точки S3 по адресу из s3r_api.s3_public_url либо домену арендатора.

Обмен фрагментами блоков ведётся по протоколу HTTP/2 между узлами кластера. Соответствующий порт предназначен для внутрикластерного трафика и должен быть недоступен клиентам.

Приложение В. Параметры конфигурации

Параметры задаются командой ALTER PLUGIN и действуют на весь кластер, кроме отмеченных как инстансные — те задаются в конфигурационном файле Picodata или переменными окружения.

s3r_api

Параметр По умолчанию Назначение
listen 127.0.0.1:8000 адрес конечной точки S3 (инстансный, S3R_API_LISTEN)
max_body_bytes 268435456 устаревший параметр для совместимости; не ограничивает размер запроса
region default значение, возвращаемое GetBucketLocation, и допустимое значение LocationConstraint
credentials пусто начальные ключи доступа; при запуске они добавляются в s3r_credential, но не удаляют созданные администратором ключи
inline_max 4096 верхняя граница размера объекта класса inline
api_memory 0 предел памяти для содержимого объектов в запросах; 0 выбирает четверть доступной памяти
service_timeout_s 30 предельное время ожидания внутренних ресурсов; ожидание данных от клиента не учитывается
diagnostics health объём открытой поверхности /-/: health, debug, bench
backend picodata реализация хранилища; fs используется при разработке
fs_root каталог для backend = fs
control_api false включает консоль и API управления на HTTP-порту Picodata
iam аутентификация в консоли и API управления
s3_public_url адрес конечной точки S3 для предподписанных ссылок
grafana_url адрес Grafana для ссылки из консоли

s3r_meta

Параметр По умолчанию Назначение
bridge_fibers 16 число волокон, обслуживающих обращения к потоку TX
bridge_queue 256 глубина очереди к потоку TX
read_consistency strong strong — чтение с мастера; eventual — разрешено чтение с реплики

s3r_storage

Параметр По умолчанию Назначение
disks пусто пути к дискам, их поддомены отказа, ярус (tier, по умолчанию standard), ёмкость и размер экстента (инстансный, S3R_DISKS)
erasure пусто формы кодирования: k, m, block_bytes (по умолчанию 2 МиБ), tier
tiers пусто карта классов хранения: {name, class} в порядке от наиболее частого к наиболее редкому доступу
write_tolerance 1 сколько фрагментов блока запись вправе оставить недописанными
gc_reclaim_after_s 60 задержка перед освобождением фрагментов удалённого объекта
dirgc_grace_s при 0: max(2, 2 × service_timeout_s), сейчас 60 с выдержка перед проверкой опустевшего каталога; ненулевое значение задаёт её явно
orphan_grace_s 86400 возраст запечатанного экстента, с которого проверяются контрольные суммы и удаляются фрагменты без строки объекта
mpu_abandon_after_s 604800 срок, после которого заброшенная составная загрузка отменяется
scrub_staleness_s 604800 наибольший допустимый возраст полной проверки данных и чётности группы размещения
compact_live_percent 50 доля живых данных, ниже которой экстент уплотняется

block_bytes по умолчанию — 2 МиБ. Форма кодирования, под которой уже есть данные, не изменяется: изменение отклоняется при загрузке конфигурации.

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

Приложение Г. Глоссарий

В названиях операций, параметров, заголовков и состояний сохранены обозначения из API Amazon S3 и интерфейсов Picodata. В пояснительном тексте используются русские термины, принятые в документации S3-совместимых хранилищ.

В русскоязычных руководствах для термина bucket встречаются варианты «бакет», «корзина» и «сегмент». В этом документе используется наиболее распространённый среди S3-совместимых российских сервисов термин бакет.

Термин Обозначение в API или коде Определение
Арендатор tenant, s3r_tenant Изолированное пространство имён S3 в одном кластере. В именах таблиц, параметров и ролей используется английское обозначение tenant.
Бакет bucket Контейнер объектов S3. Бакет имеет уникальное имя в пределах арендатора и собственные настройки доступа, версионирования и жизненного цикла.
Блок block Единица разбиения содержимого крупного объекта перед избыточным кодированием. Размер задаётся параметром block_bytes.
Версионирование versioning Режим, в котором бакет хранит несколько версий объекта с одним ключом.
Восстановление repair Создание утраченного фрагмента на другом диске по сохранившимся данным и фрагментам чётности. В именах процесса, таблиц и метрик используется обозначение repair.
Группа размещения placement group, PG Упорядоченный набор дисков одной площадки с фиксированной схемой репликации или избыточного кодирования.
Домен отказа failure domain Группа компонентов, которые могут отказать одновременно, например узел, стойка или площадка. Фрагменты одного блока размещаются в разных доменах отказа.
Доступность для чтения readability Возможность восстановить содержимое блока из имеющихся фрагментов. Для чтения требуется не менее k фрагментов.
Избыточное кодирование erasure coding, EC Разделение блока на k фрагментов данных и m фрагментов чётности. Позволяет восстановить блок при потере не более m фрагментов.
Идентификатор ключа доступа Access Key ID, access_key Открытая часть учётных данных S3, которая указывает, каким ключом подписан запрос.
Инстанс instance Экземпляр процесса Picodata. На одном физическом узле может работать несколько инстансов.
Кворум записи write quorum Минимальное число дисков, которые должны подтвердить запись блока.
Класс хранения storage class, x-amz-storage-class Атрибут S3, который клиент выбирает при записи объекта. В S3R класс хранения сопоставляется с ярусом хранения.
Ключ объекта object key Имя объекта внутри бакета. Символ / в ключе может использоваться для логического представления каталогов.
Конечная точка S3 S3 endpoint Адрес HTTP(S), на который клиент отправляет запросы S3.
Кэш cache Данные в оперативной памяти, повторное получение которых из основного источника не требуется до их изменения.
Квота quota Изменяемое администратором ограничение для арендатора, пользователя или бакета. Не следует смешивать с техническим пределом реализации.
Маркер удаления delete marker Специальная версия, которую S3 создаёт при удалении объекта из бакета с включённым версионированием.
Межплощадочная репликация site replication Асинхронное копирование объекта между площадками одного кластера.
Метаданные metadata Сведения об объекте или бакете, не являющиеся содержимым объекта: ключ, размер, тип содержимого, теги и другие атрибуты.
Ограничение частоты запросов rate limiting Ограничение числа запросов за единицу времени. Для ограничения объёма передаваемых данных используется термин «ограничение скорости передачи».
Предподписанная ссылка presigned URL URL с подписью SigV4 и сроком действия, который предоставляет ограниченный доступ без передачи секретного ключа.
Пространство имён namespace Совокупность бакетов, ключей, версий и связанных метаданных, доступных арендатору.
Репликация replication Хранение нескольких полных копий данных. Не следует смешивать с избыточным кодированием.
Секретный ключ доступа Secret Access Key, secret_key Закрытая часть учётных данных S3, используемая для вычисления подписи SigV4.
Составная загрузка multipart upload, MPU Загрузка объекта отдельными частями с последующей операцией завершения. Названия операций CreateMultipartUpload, UploadPart и CompleteMultipartUpload не переводятся.
Сохранность данных durability Вероятность того, что записанные данные не будут безвозвратно утрачены. Не следует смешивать с доступностью сервиса.
Субъект доступа principal Пользователь или группа, которым правило доступа разрешает или запрещает действие.
Тир Picodata Picodata tier Группа инстансов Picodata, на которой размещаются сервисы и таблицы. Тир Picodata и ярус хранения S3R — разные понятия.
Фоновая проверка целостности scrub Сопоставление данных и фрагментов чётности в группах избыточного кодирования, выполняемое независимо от клиентских чтений. Проверку контрольных сумм записей при обходе экстентов выполняет процесс orphan.
Фрагмент блока shard Часть блока после репликации или избыточного кодирования. Не следует смешивать с шардом vshard. В именах протокола и метрик сохранено слово shard.
Шард vshard vshard shard Единица распределения строк шардированных таблиц Picodata.
Экстент extent Файл фиксированного размера в хранилище блоков, содержащий множество записей с фрагментами.
Ярус хранения storage tier, tier Группа дисков с одинаковыми эксплуатационными характеристиками. Ярус сопоставляется с одним классом хранения S3.

Приложение Д. Справочник административных действий

Таблицы перечисляют административные действия и способы их выполнения. Для большинства действий рекомендуется API управления: запросы проверяют права по ролям Picodata, записывают в журнал, кто выполнил изменение, и отклоняют недопустимые значения до их сохранения. Команды SQL и параметры плагина применяются там, где API управления такого действия не предоставляет, а также в установке, где API управления не включён.

Пути API управления указаны относительно базового пути /s3gateway/api, а запросы к данным арендатора принимают параметр tenant_id. Порядок включения API описан в разделе «Адрес и включение», состав ролей описан в разделе «Ролевая модель арендаторов».

Установка и конфигурация

Действие API управления SQL и другие способы Раздел
Установить и включить плагин нет CREATE PLUGIN, ALTER PLUGIN ... MIGRATE TO, ALTER PLUGIN ... ENABLE Пошаговая установка
Изменить параметр плагина нет ALTER PLUGIN s3r 2.0.0 SET <сервис>.<параметр> = '...' Конфигурация
Включить консоль и API управления нет ALTER PLUGIN s3r 2.0.0 SET s3r_api.control_api = 'true' Адрес и включение
Выбрать схему избыточности нет cluster.tier.<тир>.replication_factor в конфигурации Picodata, s3r_storage.erasure, поддомены дисков hba= Схема избыточности
Удалить плагин нет ALTER PLUGIN ... DISABLE, DROP PLUGIN ... WITH DATA Удаление

Арендаторы

Действие API управления SQL и другие способы Раздел
Создать арендатора POST /v2/tenants INSERT INTO s3r_tenant со state = 'creating' Создание и удаление арендатора
Просмотреть арендаторов GET /v3/tenants, GET /v3/tenants/{id} SELECT ... FROM s3r_tenant Создание и удаление арендатора
Изменить домен и сертификат арендатора PUT /v2/tenants UPDATE s3r_tenant Сертификат арендатора и выбор по SNI
Загрузить цепочку для проверки клиентских сертификатов PUT /v2/tenants/{id}/load_mtls_cert UPDATE s3r_tenant SET mtls_ca = ... Сертификат арендатора и выбор по SNI
Включить или выключить требование клиентского сертификата PUT /v2/tenants/{id}/set_mtls нет Сертификат арендатора и выбор по SNI
Разрешить администратору арендатора менять материал TLS PUT /v2/tenants/extra_rights нет Из чего состоит поверхность
Удалить арендатора нет UPDATE s3r_tenant SET state = 'draining' Создание и удаление арендатора

Пользователи и ключи доступа

Действие API управления SQL и другие способы Раздел
Создать пользователя POST /v2/users CREATE USER Учётные данные
Просмотреть пользователей и их ключи GET /v2/users SELECT ... FROM s3r_credential Учётные данные
Заблокировать или разблокировать пользователя PUT /v2/users средства SQL Picodata Учётные данные
Удалить пользователя DELETE /v2/users DROP USER Учётные данные
Задать пароль для входа по SQL PUT /v2/users/password ALTER USER ... WITH PASSWORD Пароль для входа по SQL
Выдать ключ доступа POST /v2/credentials параметр s3r_api.credentials, только для арендатора 0 Учётные данные
Заменить секретный ключ PUT /v2/credentials/{access_key} нет Смена и отзыв ключей
Отозвать ключ доступа DELETE /v2/credentials/{access_key} нет Смена и отзыв ключей

Бакеты, объекты и права доступа

Действие API управления SQL и другие способы Раздел
Создать бакет для пользователя POST /v2/buckets S3: CreateBucket от имени пользователя Поддерживаемые операции
Просмотреть бакеты GET /v2/buckets S3: ListBuckets Поддерживаемые операции
Передать бакет другому владельцу PUT /v2/buckets нет Из чего состоит поверхность
Удалить пустой бакет DELETE /v2/buckets S3: DeleteBucket Поддерживаемые операции
Просмотреть настройки бакета GET /v2/buckets/{bucket}/settings S3: операции Get... бакета Поддерживаемые операции
Включить или приостановить версионирование PUT /v2/buckets/{bucket}/versioning S3: PutBucketVersioning Версионирование
Задать правила CORS PUT /v2/buckets/{bucket}/cors S3: PutBucketCors Совместное использование ресурсов между источниками (CORS)
Задать политику бакета PUT /v2/buckets/{bucket}/policy S3: PutBucketPolicy Политика бакета
Задать правила жизненного цикла PUT /v2/buckets/{bucket}/lifecycle S3: PutBucketLifecycleConfiguration Правила жизненного цикла
Настроить блокировку публичного доступа PUT /v2/buckets/{bucket}/public-access S3: PutPublicAccessBlock Блокировка публичного доступа
Включить сжатие PUT /v2/buckets/{bucket}/compression UPDATE s3r_bucket SET compress = true Дедупликация и сжатие
Включить дедупликацию PUT /v2/buckets/{bucket}/deduplication UPDATE s3r_bucket SET dedup = true Дедупликация
Выдать пользователю права на бакет PUT /v2/acl S3: PutBucketAcl Списки управления доступом
Просмотреть классы хранения кластера GET /v2/storage-classes SELECT ... FROM s3r_tier Классы хранения S3 и ярусы
Просмотреть объекты бакета GET /v2/objects S3: ListObjectsV2 Поддерживаемые операции
Удалить объекты DELETE /v2/objects, POST /v2/objects/delete S3: DeleteObject, DeleteObjects Массовое удаление
Получить предподписанную ссылку POST /v2/objects/presign aws s3 presign Предподписанные ссылки и анонимный доступ

Квоты

Действие API управления SQL и другие способы Раздел
Просмотреть квоты и потребление GET /v2/quotas SELECT ... FROM s3r_quota, s3r_quota_usage Квоты и ограничение скорости
Задать или снять квоту арендатора, пользователя или бакета PUT /v2/quotas INSERT INTO s3r_quota, DELETE FROM s3r_quota Квоты и ограничение скорости
Задать квоты бакета PUT /v2/buckets/{bucket}/quota INSERT INTO s3r_quota с областью bucket Квоты и ограничение скорости

Диски, восстановление и сверка

Действие API управления SQL и другие способы Раздел
Просмотреть диски GET /v2/disks SELECT ... FROM s3r_disk Состояние кластера
Просмотреть группы размещения GET /v2/placement-groups SELECT ... FROM s3r_pg Состояние кластера
Перевести диск в обслуживание или вернуть в работу PUT /v2/disks/{disk_id}/maintenance нет Замена исправного диска
Добавить или вывести диск нет S3R_DISKS или s3r_storage.disks, перезапуск инстанса Добавление и вывод дисков
Просмотреть очередь восстановления GET /v2/repair SELECT ... FROM s3r_repair Целостность и восстановление
Приостановить или возобновить перестроения PUT /v2/repair/mode нет Управление восстановлением
Приостановить, отменить или повторить отдельную перестройку PUT /v2/repair/{pg_id}/{slot} нет Управление восстановлением
Просмотреть результаты проверки целостности GET /v2/integrity SELECT ... FROM s3r_scrub Целостность и восстановление
Запустить сверку каталога POST /v2/reconcile /-/debug/run/catalog Фоновые процессы
Просмотреть результат сверки и изменить её период GET /v2/reconcile, PUT /v2/reconcile нет Фоновые процессы
Просмотреть межплощадочную репликацию GET /v2/replication SELECT count(*) FROM s3r_t<N>_siterepl Наблюдение за межплощадочной репликацией

Кластер и наблюдение

Действие API управления SQL и другие способы Раздел
Проверить учётные данные и роли GET /v2/rights нет Из чего состоит поверхность
Просмотреть ёмкость GET /v2/capacity SELECT ... FROM s3r_disk, s3r_extent Состояние кластера
Просмотреть расход памяти под метаданные GET /v2/memory нет Из чего состоит поверхность
Проверить состояние подсистем GET /v2/health /-/health проверяет только работу процесса Диагностические конечные точки
Просмотреть состав кластера GET /v2/cluster/servers /-/debug/cluster Диагностические конечные точки
Добавить или вывести узел нет средства Picodata Добавление и вывод узлов
Выполнить проход фонового процесса нет /-/debug/run/<процесс> Фоновые процессы