Когда данных становится больше, чем влезает на один диск, самое время задуматься о RAID. В детстве часто слышал от старших: «однажды RAID уйдут в прошлое, объектные хранилища заполонят мир, а ты даже не знаешь, что такое CEPH»,- поэтому первым делом в самостоятельной жизни стало создание своего кластера. Целью эксперимента было ознакомиться с внутренним устройством ceph и понять рамки его применения. Насколько оправдано внедрение ceph в средний бизнес, а в малый? После нескольких лет эксплуатации и пары необратимых потерь данных возникло понимание тонкостей, что не всё так однозначно. Особенности CEPH создают препятствия его широкому распространению, и из-за них эксперименты зашли в тупик. Ниже приводится описание всех пройденных шагов, полученный результат и сделанные выводы. Если знающие люди поделятся опытом и пояснят некоторые моменты — буду благодарен.

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

Стратегия CEPH


Кластер CEPH объединяет произвольное количество K дисков произвольного размера и хранит данные на них, дублируя каждый кусочек (4 МБ по умолчанию) заданное число N раз.

Рассмотрим простейший случай с двумя одинаковыми дисками. Из них можно либо собрать RAID 1, либо кластер с N=2 — результат получится один и тот же. Если дисков три, и они разного размера, то собрать кластер с N=2 легко: часть данных будут на дисках 1 и 2, часть — на 1 и 3, а часть — на 2 и 3, тогда как RAID — нет (можно собрать такой RAID, но это будет извращением). Если дисков ещё больше, то возможно создание RAID 5, у CEPH есть аналог — erasure_code, который противоречит ранним концепциям разработчиков, и поэтому не рассматривается. RAID 5 предполагает, что имеется небольшое количество дисков, и все они в хорошем состоянии. При отказе одного, остальные должны продержаться до момента, пока не заменят диск и не будут восстановлены на него данные. CEPH же, при N>=3, поощряет использование старых дисков, в частности, если держать несколько хороших дисков для хранения одной копии данных, а оставшиеся две-три копии хранить на большом количестве старых дисков, то информация будет в сохранности, так как пока живы новые диски — проблем нет, а если один из них сломается, то одновременный отказ трёх дисков со сроком службы более пяти лет, желательно, из разных серверов — событие крайне маловероятное.

В распределении копий есть тонкость. По умолчанию подразумевается, что данные делятся на больше количество (~по 100 на диск) групп распределения PG, каждая из которых дублируется на каких-то дисках. Допустим, K=6, N=2, тогда при выходе из строя двух любых дисков, гарантированно теряются данные, так как по теории вероятности, найдётся хотя бы одна PG, которая расположится именно на этих двух дисках. А потеря одной группы делает недоступными все данные в пуле. Если же диски разбить на три пары и разрешить хранить данные только на дисках внутри одной пары, то такое распределение также устойчиво к отказу одного любого диска, зато при отказе двух вероятность потери данных не 100%, а всего 3/15, и даже при отказе трёх дисков — только 12/20. Отсюда, энтропия в распределении данных не способствует отказоустойчивости. Также заметим, что для файлового сервера свободная оперативная память значительно увеличивает скорость отклика. Чем больше памяти в каждом узле, и чем больше памяти во всех узлах — тем будет быстрее. Это несомненно преимущество кластера перед одиночным сервером и, тем более, аппаратным NAS-ом, куда встраивают очень малый объём памяти.

Отсюда следует, что CEPH — хороший способ с минимальными вложениями из устаревшего оборудования создать надёжную систему хранения данных на десятки ТБ с возможностью масштабирования (тут, конечно, потребуются затраты, но небольшие по сравнению с коммерческими СХД).

Реализация кластера


Для эксперимента возьмём списанный компьютер Intel DQ57TM + Intel core i3 540 + 16 ГБ ОЗУ. Четыре диска по 2 ТБ организуем в подобие RAID10, после успешного испытания добавим второй узел и ещё столько же дисков.

Устанавливаем Linux. От дистрибутива требуется возможность кастомизации и стабильность. Под требования подходят Debian и Suse. У Suse более гибкий установщик, позволяющий отключить любой пакет; к сожалению, я не смог понять, какие можно выкинуть без ущерба для системы. Ставим Debian через debootstrap buster. Опция min-base устанавливает нерабочую систему, в которой не хватает драйверов. Разница в размере по сравнению с полной версией не так велика, чтобы заморачиваться. Поскольку работа ведётся на физической машине, хочется делать снапшоты, как на виртуалках. Такую возможность предоставляет либо LVM, либо btrfs (или xfs, или zfs — разница не велика). У LVM снапшоты — не сильная сторона. Ставим btrfs. И загрузчик — в MBR. Нет смысла засорять диск 50 МБ разделом с FAT, когда можно затолкать его в 1 МБ область таблицы разделов и всё пространство выделить под систему. Заняло на диске 700 МБ. Сколько у базовой установки SUSE — не запомнил, кажется, около 1.1 или 1.4 ГБ.

Устанавливаем CEPH. Игнорируем версию 12 в репозитории debian и подключаем прямо с сайта 15.2.3. Следуем инструкции из раздела «устанавливаем CEPH вручную» со следующими оговорками:

  • Перед подключением репозитория необходимо установить gnupg wget ca-certificates
  • После подключения репозитория, но перед установкой кластера опущена установка пакетов: apt -y --no-install-recommends install ceph-common ceph-mon ceph-osd ceph-mds ceph-mgr
  • В момент установки ceph-osd по (уже понятным) причинам будет пытаться установиться lvm2. Острой необходимости в этом нет. При возникновении проблем с установкой пакета отказаться от него можно путём удаления зависимости в /var/lib/dpkg/status для ceph-osd.

    При написании статьи использовался менее гуманный патч:
    cat << EOF >> /var/lib/dpkg/status
    Package: lvm2
    Status: install ok installed
    Priority: important
    Section: admin
    Installed-Size: 0
    Maintainer: Debian Adduser Developers <adduser@packages.debian.org>
    Architecture: all
    Multi-Arch: foreign
    Version: 113.118
    Description: No-install
    EOF
    


Обзор кластера


ceph-osd — отвечает за хранение данных на диске. Для каждого диска запускается сетевая служба, которая принимает и исполняет запросы на чтение или запись в объекты. В этой статье рассматривается хранилище bluestore, как наиболее низкоуровневое. В каталоге службы создаются служебные файлы, описывающие ID кластера, хранилища, его тип итд, а также обязательный файл block — эти файлы не меняются. Если файл физический, то osd создаст в нём файловую систему и будет накапливать данные. Если файл является ссылкой, то данные будут в устройстве, на которое указывает ссылка. Помимо основного устройства могут быть дополнительно указаны block.db — метаданные (RocksDB) и block.wal — журнал (RocksDB write-ahead log). Если дополнительные устройства не указаны, то метаданные и журнал буду храниться в основном устройстве. Очень важно следить за наличием свободного места для RocksDB, в противном случае OSD не запустится!
При стандартном создании osd в старых версиях диск делится на два раздела: первый — 100 МБ xfs, монтируется в /var/lib/… и содержит служебную информацию, второй — отдаётся под основное хранилище. В новой версии используется lvm.
Теоретически, миниатюрный раздел можно не монтировать, а поместить файлы в /var/lib/..., продублировав их на все узлы, а диск целиком выделить под данные, не создавая, ни GPT, ни LVM заголовка. При ручном добавлении OSD необходимо убедиться, что пользователь ceph имеет права на запись в блочные устройства с данными, и каталог с данными службы автоматически монтируется в /var/lib..., если принято решение располагать их там. Желательно также указать параметр osd memory target, чтобы хватило физической памяти.

ceph-mds. На низком уровне CEPH — объектное хранилище. Возможность блочного хранения сводится к сохранению каждого блока 4МБ в виде объекта. По тому же принципу работает и файловое хранение. Создаётся два пула: один для метаданных, другой — для данных. Они объединяются в файловую систему. В этот момент создаётся какая-то запись, поэтому если удалить файловую систему, но сохранить оба пула, то восстановить её не получится. Есть процедура по извлечению файлов по блокам, не тестировал. За доступ к файловой системе отвечает служба ceph-mds. Для каждой файловой системы необходим отдельный экземпляр службы. Есть опция «ранг», которая позволяет создать подобие нескольких файловых систем в одной — тоже не тестировалось.

сeph-mon — эта служба хранит карту кластера. В неё входит информация обо всех OSD, алгоритм распределения PG в OSD и, самое главное, информация обо всех объектах (детали этого механизма мне непонятны: есть каталог /var/lib/ceph/mon/.../store.db, в нём лежит большой файл — 26МБ, а в кластере 105К объектов, получается чуть более 256 байт на объект,- я думаю, что монитор хранит список всех объектов и PG, в которых они лежат). Повреждение этого каталога приводит к потере всех данных в кластере. Отсюда и сделан вывод, что CRUSH показывает как PG расположены по OSD, а как объекты расположены по PG — в базе данных (вывод оказался неверным, что именно в ней содержится, требует уточнения). Как следствие, во-первых, мы не можем установить систему на флешку в режиме RO, так как в базу данных ведётся постоянная запись, необходим дополнительный диск под эти (вряд ли более 1 ГБ) данные, во-вторых, необходимо в реальном времени иметь копию этой базы. Если мониторов несколько, то отказоустойчивость обеспечивается за счёт них, но если монитор один, максимум — два, то необходимо обеспечить защиту данных. Есть теоретическая процедура восстановления монитора на основе данных OSD, на текущий момент получилось восстановить на объектном уровне, файловую систему на текущий момент не получилось восстановить. Пока что полагаться на этот механизм нельзя.

rados-gw — экспортирует объектное хранилище по протоколу S3 и подобные. Создаёт множество пулов, непонятно зачем. Особо не экспериментировал.

ceph-mgr — при установке этой службы запускаются несколько модулей. Один из них — не отключаемый autoscale. Он стремится поддерживать правильное количество PG/OSD. При желании управлять соотношением вручную, можно запретить масштабирование для каждого пула, но в таком случае модуль падает с делением на 0, и статус кластера становится ERROR. Модуль написан на питоне, и если закомментировать в нём нужную строчку, это приводит к его отключению. Детали лень вспоминать.

Литература:

Установка CEPH
Восстановление при полном отказе монитора
Статья о BlueStore в Ceph
Описание архитектуры ceph. Sage A. Weil

Листинги скриптов:

Установка системы через debootstrap
blkdev=sdb1
mkfs.btrfs -f /dev/$blkdev
mount /dev/$blkdev /mnt
cd /mnt
for i in {@,@var,@home}; do btrfs subvolume create $i; done
mkdir snapshot @/{var,home}
for i in {var,home}; do mount -o bind @${i} @/$i; done
debootstrap buster @ http://deb.debian.org/debian; echo $?
for i in {dev,proc,sys}; do mount -o bind /$i @/$i; done
cp /etc/bash.bashrc @/etc/

chroot /mnt/@ /bin/bash
echo rbd1 > /etc/hostname
passwd
uuid=`blkid | grep $blkdev | cut -d "\"" -f 2`
cat << EOF > /etc/fstab
UUID=$uuid / btrfs noatime,nodiratime,subvol=@ 0 1
UUID=$uuid /var btrfs noatime,nodiratime,subvol=@var 0 2
UUID=$uuid /home btrfs noatime,nodiratime,subvol=@home 0 2
EOF
cat << EOF >> /var/lib/dpkg/status
Package: lvm2
Status: install ok installed
Priority: important
Section: admin
Installed-Size: 0
Maintainer: Debian Adduser Developers <adduser@packages.debian.org>
Architecture: all
Multi-Arch: foreign
Version: 113.118
Description: No-install

Package: sudo
Status: install ok installed
Priority: important
Section: admin
Installed-Size: 0
Maintainer: Debian Adduser Developers <adduser@packages.debian.org>
Architecture: all
Multi-Arch: foreign
Version: 113.118
Description: No-install
EOF

exit
grub-install --boot-directory=@/boot/ /dev/$blkdev
init 6

apt -yq install --no-install-recommends linux-image-amd64 bash-completion ed btrfs-progs grub-pc iproute2 ssh  smartmontools ntfs-3g net-tools man
exit
grub-install --boot-directory=@/boot/ /dev/$blkdev
init 6


Создание кластера
apt -yq install --no-install-recommends gnupg wget ca-certificates
echo 'deb https://download.ceph.com/debian-octopus/ buster main' >> /etc/apt/sources.list
wget -q -O- 'https://download.ceph.com/keys/release.asc' | apt-key add -
apt update
apt -yq install --no-install-recommends ceph-common ceph-mon

echo 192.168.11.11 rbd1 >> /etc/hosts
uuid=`cat /proc/sys/kernel/random/uuid`
cat << EOF > /etc/ceph/ceph.conf
[global]
fsid = $uuid
auth cluster required = cephx
auth service required = cephx
auth client required = cephx
mon allow pool delete = true
mon host = 192.168.11.11
mon initial members = rbd1
mon max pg per osd = 385
osd crush update on start = false
#osd memory target = 2147483648
osd memory target = 1610612736
osd scrub chunk min = 1
osd scrub chunk max = 2
osd scrub sleep = .2
osd pool default pg autoscale mode = off
osd pool default size = 1
osd pool default min size = 1
osd pool default pg num = 1
osd pool default pgp num = 1
[mon]
mgr initial modules = dashboard
EOF

ceph-authtool --create-keyring ceph.mon.keyring --gen-key -n mon. --cap mon 'allow *'
ceph-authtool --create-keyring ceph.client.admin.keyring --gen-key -n client.admin --cap mon 'allow *' --cap osd 'allow *' --cap mds 'allow *' --cap mgr 'allow *'
cp ceph.client.admin.keyring /etc/ceph/
ceph-authtool --create-keyring bootstrap-osd.ceph.keyring --gen-key -n client.bootstrap-osd --cap mon 'profile bootstrap-osd' --cap mgr 'allow r'
cp bootstrap-osd.ceph.keyring /var/lib/ceph/bootstrap-osd/ceph.keyring
ceph-authtool ceph.mon.keyring --import-keyring /etc/ceph/ceph.client.admin.keyring
ceph-authtool ceph.mon.keyring --import-keyring /var/lib/ceph/bootstrap-osd/ceph.keyring
monmaptool --create --add rbd1 192.168.11.11 --fsid $uuid monmap
rm -R /var/lib/ceph/mon/ceph-rbd1/*
ceph-mon --mkfs -i rbd1 --monmap monmap --keyring ceph.mon.keyring
chown ceph:ceph -R /var/lib/ceph
systemctl enable ceph-mon@rbd1
systemctl start ceph-mon@rbd1
ceph mon enable-msgr2
ceph status

# dashboard

apt -yq install --no-install-recommends ceph-mgr ceph-mgr-dashboard python3-distutils python3-yaml
mkdir /var/lib/ceph/mgr/ceph-rbd1
ceph auth get-or-create mgr.rbd1 mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-rbd1/keyring
systemctl enable ceph-mgr@rbd1
systemctl start ceph-mgr@rbd1
ceph config set mgr mgr/dashboard/ssl false
ceph config set mgr mgr/dashboard/server_port 7000
ceph dashboard ac-user-create root 1111115 administrator
systemctl stop ceph-mgr@rbd1
systemctl start ceph-mgr@rbd1


Добавление OSD (часть)
apt install ceph-osd

osdnum=`ceph osd create`
mkdir -p /var/lib/ceph/osd/ceph-$osdnum
mkfs -t xfs /dev/sda1
mount -t xfs /dev/sda1 /var/lib/ceph/osd/ceph-$osdnum
cd /var/lib/ceph/osd/ceph-$osdnum
ceph auth get-or-create osd.0 mon 'profile osd' mgr 'profile osd' osd 'allow *' > /var/lib/ceph/osd/ceph-$osdnum/keyring
ln -s /dev/disk/by-partuuid/d8cc3da6-02  block
ceph-osd -i $osdnum --mkfs
#chown ceph:ceph /dev/sd?2
chown ceph:ceph -R /var/lib/ceph
systemctl enable ceph-osd@$osdnum
systemctl start ceph-osd@$osdnum


Резюме


Главное маркетинговое преимущество CEPH — это CRUSH — алгоритм вычисления расположения данных. Мониторы распространяют клиентам этот алгоритм, после чего клиенты напрямую запрашивают нужный узел и нужный OSD. CRUSH обеспечивает отсутствие централизации. Он представляет собой маленький файл, который можно хоть распечатать и повесить на стену. Практика показала, что CRUSH не является исчерпывающей картой. Если уничтожить и заново создать мониторы, сохранив все OSD и CRUSH, то этого недостаточно для восстановления кластера. Отсюда сделан вывод, что на каждом мониторе хранятся некоторые метаданные обо всём кластере. Незначительный объём этих метаданных не накладывает ограничений на размер кластера, но требует обеспечить их сохранность, что исключает экономию диска за счёт установки системы на флешку и исключает кластеры с менее, чем тремя узлами. Агрессивная политика разработчика в отношении опциональных фич. Далеко до минимализма. Документация на уровне: «за то, что есть, — уже спасибо, но очень, очень скудно». Возможность взаимодействия со службами на низком уровне предусмотрена, но документация слишком поверхностно касается этой темы, поэтому скорее нет, чем да. Практически никаких шансов на восстановление данных при внештатной ситуации (благодаря объяснениям сообщества шанс всё ещё остаётся).

Варианты дальнейших действий: отказаться от CEPH и воспользоваться банальным много-дисковым btrfs (или xfs, zfs), узнать новую информацию о CEPH, которая позволит эксплуатировать его в указанных условиях, попробовать в качестве повышения квалификации написать собственное хранилище.