
История началась год назад, когда к нам пришел наш друг, коллега и большой эксперт по энтерпрайз стораджам со словами: «Парни, у меня тут завалялась шикарная хранилка со всеми модными фичами. 90Tb».
Особой необходимости мы в ней не видели, но, естественно, отказываться не стали. Настроили туда пару бекапов и на какое-то время благополучно забыли.
Это распределенная файловая система, которая давно дружит с Openstack и интегрирована в oVIrt/RHEV. Хоть наш IaaS и не на Openstack, у Гластера большое активное коммьюнити и есть нативная поддержка qemu в виде интерфейса libgfapi. Тем самым мы убиваем 2х зайцев:
1. Поднимаем сторадж для бекапов, полностью поддерживаемый нами. Больше не придется бояться в ожидании, когда вендор пришлет сломанную запчасть.
2. Тестируем новый тип хранения (volume type), который мы в перспективе можем предоставить нашим заказчикам.
Месяц ушёл на эксперименты и сборки разнообразных конфигураций и версий, потом была тестовая эксплуатация в продакшне как второй дестинейшн для наших технических бекапов. Мы хотели посмотреть, как он себя ведет полгода, прежде чем полностью положиться на него.
Палок для экспериментов у нас хватало с излишком - стойка с Dell Poweredge r510 и пачка не очень шустрых SATA двухтерабайтников, оставшихся у нас по наследству от старого S3. Мы прикинули, что нам не нужно хранилище больше чем на 20тб и после этого нам понадобилось около получаса, чтобы набить в 2 стареньких Dell Power Edge r510 по 10 дисков, выбрать еще 1 сервер для роли арбитра, скачать пакетики и задеплоить его. Получилась вот такая схема.

Мы выбрали именно striped-replicated с арбитром, потому что это быстро (данные размазываются равномерно по нескольким брикам), достаточно надежно (реплика 2), можно пережить падение 1 ноды, не получив split-brain. Как же мы ошибались...
Главный минус нашего кластера в текущей конфигурации — это очень узкий канал - всего 1G, но для нашего назначения его вполне хватает. Поэтому данный пост не о тестировании скорости работы системы, а о её стабильности и том, что делать при авариях. Хотя в будущем мы планируем переключить его на Infiniband 56G с rdma и провести перформанс тесты, но это уже совсем другая история.
Глубоко вдаваться в процесс сборки кластера я не буду, здесь все достаточно просто:
Создаём директории для бриков:for i in {0..9} ; do mkdir -p /export/brick$i ; done
for i in {b..k} ; do mkfs.xfs /dev/sd$i ; done
/dev/sdb /export/brick0/ xfs defaults 0 0 /dev/sdc /export/brick1/ xfs defaults 0 0Монтируем:
/dev/sdd /export/brick2/ xfs defaults 0 0 /dev/sde /export/brick3/ xfs defaults 0 0
/dev/sdf /export/brick4/ xfs defaults 0 0 /dev/sdg /export/brick5/ xfs defaults 0 0
/dev/sdh /export/brick6/ xfs defaults 0 0 /dev/sdi /export/brick7/ xfs defaults 0 0
/dev/sdj /export/brick8/ xfs defaults 0 0 /dev/sdk /export/brick9/ xfs defaults 0 0
mount -a
for i in {0..9} ; do mkdir -p /export/brick$i/holodilnik ; done
pdsh -w server[1-3] -- yum install glusterfs-server -y
systemctl enable glusterd systemctl start glusterd
gluster peer probe server2 gluster peer probe server3
gluster volume create holodilnik stripe 10 replica 3 arbiter 1 transport tcp server1:/export/brick0/holodilnik server2:/export/brick0/holodilnik
server3:/export/brick0/holodilnik server1:/export/brick1/holodilnik
server2:/export/brick1/holodilnik server3:/export/brick1/holodilnik
server1:/export/brick2/holodilnik server2:/export/brick2/holodilnik
server3:/export/brick2/holodilnik server1:/export/brick3/holodilnik
server2:/export/brick3/holodilnik server3:/export/brick3/holodilnik
server1:/export/brick4/holodilnik server2:/export/brick4/holodilnik server3:/export/brick4/holodilnik server1:/export/brick5/holodilnik
server2:/export/brick5/holodilnik server3:/export/brick5/holodilnik server1:/export/brick6/holodilnik server2:/export/brick6/holodilnik
server3:/export/brick6/holodilnik server1:/export/brick7/holodilnik server2:/export/brick7/holodilnik server3:/export/brick7/holodilnik
server1:/export/brick8/holodilnik server2:/export/brick8/holodilnik server3:/export/brick8/holodilnik server1:/export/brick9/holodilnik
server2:/export/brick9/holodilnik server3:/export/brick9/holodilnik force
gluster volume set holodilnik performance.write-behind on gluster volume set holodilnik nfs.disable on gluster volume set holodilnik cluster.lookup-optimize off gluster volume set holodilnik performance.stat-prefetch off gluster volume set holodilnik server.allow-insecure on gluster volume set holodilnik storage.batch-fsync-delay-usec 0 gluster volume set holodilnik performance.client-io-threads off gluster volume set holodilnik network.frame-timeout 60 gluster volume set holodilnik performance.quick-read on gluster volume set holodilnik performance.flush-behind off gluster volume set holodilnik performance.io-cache off gluster volume set holodilnik performance.read-ahead off gluster volume set holodilnik performance.cache-size 0 gluster volume set holodilnik performance.io-thread-count 64 gluster volume set holodilnik performance.high-prio-threads 64 gluster volume set holodilnik performance.normal-prio-threads 64 gluster volume set holodilnik network.ping-timeout 5 gluster volume set holodilnik server.event-threads 16 gluster volume set holodilnik client.event-threads 16Дополнительные полезные параметры:
sysctl vm.swappiness=0 sysctl vm.vfs_cache_pressure=120 sysctl vm.dirty_ratio=5 echo "deadline" > /sys/block/sd[b-k]/queue/scheduler echo "256" > /sys/block/sd[b-k]/queue/nr_requests echo "16" > /proc/sys/vm/page-cluster blockdev --setra 4096 /dev/sd[b-k]Стоит добавить, что эти параметры хороши в нашем случае с бекапами, а именно с линейными операциями. Для рандомных кейсов чтения/записи надо подбирать что-нибудь другое.
1. Gluster Native Client (glusterfs-fuse) с параметром backupvolfile-server.
Минусы: — установка дополнительного софта на клиенты; — скорость. Плюс/минус: — долгая недоступность данных в случае отвала одной из нод кластера. Проблема правится параметром network.ping-timeout на стороне сервера. Выставив параметр в 5, шара отваливается, соответственно, на 5 секунд. Плюс: — достаточно стабильно работает, не наблюдалось массовых проблем с битыми файлами.2. Gluster Native Client (gluster-fuse) + VRRP (keepalived). Настроили переезжающий IP между двумя нодами кластера и гасили одну из них.
Минус: — установка дополнительного софта.Плюс: — конфигурируемый таймаут при переключении в случае отвала ноды кластера. Как оказалось, указание параметра backupvolfile-server или настройка keepalived необязательны, клиент сам подключается к демону Гластера (неважно, по какому из адресов), узнаёт остальные адреса и запускает запись на все ноды кластера. В нашем случае мы видели симметричный трафик с клиента на server1 и server2. Даже если вы указываете ему VIP-адрес, клиент всё равно будет использовать кластерные адреса Glusterfs. Мы пришли к выводу, что данный параметр полезен в том случае, когда клиент при старте пытается подключиться к Glusterfs-серверу, который недоступен, тогда он следом обратится к хосту, указанному в backupvolfile-server.
The FUSE client allows the mount to happen with a GlusterFS “round robin” style connection. In /etc/fstab, the name of one node is used; however, internal mechanisms allow that node to fail, and the clients will roll over to other connected nodes in the trusted storage pool. The performance is slightly slower than the NFS method based on tests, but not drastically so. The gain is automatic HA client failover, which is typically worth the effect on performance.
gluster volume heal holodilnik info
Brick server2:/export/brick1/holodilnik /2018-01-20-weekly/billing.tar.gz Status: Connected Number of entries: 1 Brick server2:/export/brick5/holodilnik /2018-01-27-weekly/billing.tar.gz Status: Connected Number of entries: 1 Brick server3:/export/brick5/holodilnik /2018-01-27-weekly/billing.tar.gz Status: Connected Number of entries: 1 ...
По окончании лечения счётчики обнулились и скорость записи вернулась к прежним показателям.umount. umount /dev/sdX
lsof | grep sdXИ останавливаем этот процесс. После этого надо сделать рескан. Смотрим в
dmesg-Hболее подробную информацию о расположении вылетевшего диска:
[Feb14 12:28] quiet_error: 29686 callbacks suppressed [ +0.000005] Buffer I/O error on device sdf, logical block 122060815 [ +0.000042] lost page write due to I/O error on sdf [ +0.001007] blk_update_request: I/O error, dev sdf, sector 1952988564 [ +0.000043] XFS (sdf): metadata I/O error: block 0x74683d94 ("xlog_iodone") error 5 numblks 64 [ +0.000074] XFS (sdf): xfs_do_force_shutdown(0x2) called from line 1180 of file fs/xfs/xfs_log.c. Return address = 0xffffffffa031bbbe [ +0.000026] XFS (sdf): Log I/O Error Detected. Shutting down filesystem [ +0.000029] XFS (sdf): Please umount the filesystem and rectify the problem(s) [ +0.000034] XFS (sdf): xfs_log_force: error -5 returned. [ +2.449233] XFS (sdf): xfs_log_force: error -5 returned. [ +4.106773] sd 0:2:5:0: [sdf] Synchronizing SCSI cache [ +25.997287] XFS (sdf): xfs_log_force: error -5 returned. Где sd 0:2:5:0 — это: h == hostadapter id (first one being 0) c == SCSI channel on hostadapter (first one being 2) — он же PCI-слот t == ID (5) — он же номер слота вылетевшего диска l == LUN (first one being 0)echo 1 > /sys/block/sdY/device/delete echo "2 5 0" > /sys/class/scsi_host/host0/scan
где sdY
— неправильное имя заменяемого диска.Далее для замены брика нам надо создать новую директорию для монтирования, накатить файловую систему и примонтировать его:
mkdir -p /export/newvol/brick mkfs.xfs /dev/sdf -f mount /dev/sdf /export/newvol/Выполняем замену brick:
gluster volume replace-brick holodilnik server1:/export/sdf/brick server1:/export/newvol/brick commit force
gluster volume heal holodilnik full gluster volume heal holodilnik info summaryОтвал арбитра: Те же 5–7 секунд недоступности шары и 3 секунды просадки, связанные с синком метаданных на кворум ноду.
rm -rf /mnt/holodilnik/* rm: cannot remove ‘backups/public’: Remote I/O error rm: cannot remove ‘backups/mongo/5919d69b46e0fb008d23778c/mc.ru-msk’: Directory not empty rm: cannot remove ‘billing/2018-02-02_before-update_0.10.0/mongodb/’: Stale file handleПрочитал около 30 таких заявок, которые начинаются с 2013 года. Решения проблемы нигде нет. Red Hat рекомендует обновить версию, но нам это не помогло. Наш workaround — просто зачищать остатки битых директорий в бриках на всех нодах:
pdsh -w server[1-3] -- rm -rf /export/brick[0-9]/holodilnik/Но дальше — хуже.