Tips & tricks у роботі з Ceph у навантажених проектах

Tips & tricks у роботі з Ceph у навантажених проектах

Використовуючи Ceph як мережеве сховище у різних за навантаженими проектами, ми можемо зіткнутися з різними завданнями, які з першого погляду не здаються простими чи тривіальними. Наприклад:

  • міграція даних зі старого Ceph до нового з частковим використанням попередніх серверів у новому кластері;
  • вирішення проблеми розподілу дискового простору в Ceph.

Розбираючись з такими завданнями, ми стикаємося з необхідністю коректно отримати OSD без втрати даних, що особливо актуально при великих обсягах даних. Про це й йтиметься у статті.

Нижче наведені способи актуальні для будь-яких версій Ceph. Крім того, буде враховано той факт, що в Ceph може зберігатися великий обсяг даних: для запобігання втратам даних та інших проблем деякі дії «дробляться» на кілька інших.

Передмова про OSD

Оскільки два з трьох розглянутих рецептів присвячені OSD (Object Storage Daemon), перед зануренням у практичну частину - коротко про те, що це взагалі таке в Ceph і чому він такий важливий.

Насамперед слід сказати, що весь Ceph-кластер складається з безлічі OSD. Чим більше, тим більше вільний обсяг даних у Ceph. Звідси легко зрозуміти головну функцію OSD: він зберігає дані об'єктів Ceph на файлових системах всіх вузлів кластера та надає мережевий доступ до них (для читання, запису та інших запитів).

На цьому рівні встановлюються параметри реплікації за рахунок копіювання об'єктів між різними OSD. І тут можна зіткнутися з різними проблемами, про вирішення яких і буде наведено далі.

Кейс №1. Безпечне вилучення OSD із кластера Ceph без втрати даних

Необхідність вилучення OSD може бути викликана виведенням сервера з кластера — наприклад, для заміни на інший сервер, — що й трапилося у нас, послуживши приводом для написання статті. Таким чином, кінцева мета маніпуляцій - витягти всі OSD і mon'и на даному сервері, щоб його можна було зупинити.

Для зручності та виключення ситуації, де ми в процесі виконання команд помилимося із зазначенням потрібного OSD, задамо окрему змінну, значенням якої і буде номер OSD, що видаляється. Назвемо її ${ID} — тут така змінна замінює номер OSD, з якою ми працюємо.

Подивимося на стан перед початком робіт:

root@hv-1 ~ # ceph osd tree
ID CLASS WEIGHT  TYPE NAME      STATUS REWEIGHT PRI-AFF
-1       0.46857 root default
-3       0.15619      host hv-1
-5       0.15619      host hv-2
 1   ssd 0.15619      osd.1     up     1.00000  1.00000
-7       0.15619      host hv-3
 2   ssd 0.15619      osd.2     up     1.00000  1.00000

Щоб ініціювати видалення OSD, потрібно плавно виконати reweight на ній до нуля. Таким чином, ми знижуємо кількість даних в OSD за рахунок балансування в інші OSD. Для цього виконуються такі команди:

ceph osd reweight osd.${ID} 0.98
ceph osd reweight osd.${ID} 0.88
ceph osd reweight osd.${ID} 0.78

… і так далі до нуля.

Плавне балансування необхідне, щоб не втратити дані. Це особливо актуально, якщо OSD знаходиться великий обсяг даних. Щоб точно переконатися, що після виконання команд reweight все пройшло успішно, можна виконати ceph -s або ж в окремому вікні терміналу запустити ceph -w для того, щоб спостерігати за змінами у реальному часі.

Коли OSD «спустошена», можна розпочати стандартну операцію з її видалення. Для цього переведемо потрібну OSD у стан down:

ceph osd down osd.${ID}

«Витягнемо» OSD із кластера:

ceph osd out osd.${ID}

Зупинимо сервіс OSD та відмонтуємо його розділ у ФС:

systemctl stop ceph-osd@${ID}
umount /var/lib/ceph/osd/ceph-${ID}

Видалимо OSD з CRUSH map:

ceph osd crush remove osd.${ID}

Видалимо користувача OSD:

ceph auth del osd.${ID}

І, нарешті, видалимо саму OSD:

ceph osd rm osd.${ID}

Примітка: якщо ви використовуєте версію Ceph Luminous або вище, вищезгадані дії з видалення OSD можна звести до двох команд:

ceph osd out osd.${ID}
ceph osd purge osd.${ID}

Якщо після виконання описаних вище дій виконати команду ceph osd tree, то має бути видно, що на сервері, де робилися роботи, більше немає OSD, для яких виконувались операції вище:

root@hv-1 ~ # ceph osd tree
ID CLASS WEIGHT  TYPE NAME     STATUS REWEIGHT PRI-AFF
-1       0.46857      root default
-3       0.15619      host hv-1
-5       0.15619      host hv-2
-7       0.15619      host hv-3
 2   ssd 0.15619      osd.2    up     1.00000  1.00000

Принагідно зауважимо, що стан кластера Ceph перейде в HEALTH_WARN, а також побачимо зменшення кількості OSD та об'єму доступного дискового простору.

Далі будуть описані дії, які потрібно, якщо ви хочете повністю зупинити сервер і, відповідно, видалити його з Ceph. У такому разі важливо пам'ятати, що перед вимкненням сервера необхідно витягти всі OSD на цьому сервері.

Якщо на цьому сервері не залишилося більше OSD, то після їх видалення потрібно виключити з картки OSD сервер hv-2, Виконавши наступну команду:

ceph osd crush rm hv-2

видаляємо mon із сервера hv-2, запускаючи команду нижче на іншому сервері (тобто в даному випадку - на hv-1):

ceph-deploy mon destroy hv-2

Після цього можна зупиняти сервер і починати наступні дії (його повторного розгортання тощо).

Кейс №2. Розподіл дискового простору у вже створеному Ceph-кластері

Другу історію почну з передмови про PG (Placement Groups). Основна роль PG в Ceph полягає в першу чергу в агрегації Ceph-об'єктів та подальшої реплікації в OSD. Формула, за допомогою якої можна порахувати необхідну кількість PG, знаходиться в відповідному розділі документації Ceph. Саме там це питання розібрано і на конкретних прикладах.

Так ось: одна з найпоширеніших проблем під час експлуатації Ceph — незбалансована кількість OSD та PG між пулами в Ceph.

По-перше, через це може виникнути ситуація, коли вказується занадто велика кількість PG в невеликому за об'ємом пулі, що є нераціональним використанням дискового простору в кластері. По-друге, на практиці виходить серйозніша проблема: переповнення даних в одній з OSD. Це спричиняє перехід кластера спочатку в стан HEALTH_WARN, а потім і HEALTH_ERR. У всьому виною те, що Ceph при розрахунку доступного обсягу даних (дізнатися його можна за MAX AVAIL у висновку команди ceph df для кожного пулу окремо) спирається на обсяг доступних даних OSD. Якщо хоча б в одному OSD буде недостатньо місця, більше записати дані не вийде, поки дані не будуть розподілені належним чином між усіма OSD.

Варто уточнити, що ці проблеми більшою мірою вирішуються на етапі конфігурації Ceph-кластера. Один із інструментів, яким можна скористатися, — Ceph PGCalc. За його допомогою наочно розраховується необхідна кількість PG. Втім, до нього можна вдатися і в ситуації, коли кластер Ceph вже настроєно неправильно. Тут варто уточнити, що в рамках робіт з виправлення вам, найімовірніше, знадобиться зменшувати кількість PG, а ця можливість недоступна у старих версіях Ceph (вона з'явилася лише з версії Nautilus).

Отже, представимо таку картину: у кластера - статус HEALTH_WARN через те, що в одному із OSD закінчується місце. Про це свідчить помилка HEALTH_WARN: 1 near full osd. Нижче наведено алгоритм виходу з такої ситуації.

Насамперед потрібно розподілити наявні дані між рештою OSD. Подібну операцію ми вже виконували в першому кейсі, коли «осушували» вузол — з тією різницею, що тепер потрібно трохи зменшити reweight. Наприклад, до 0.95:

ceph osd reweight osd.${ID} 0.95

Так звільняється дискове місце в OSD і виправляється помилка в ceph health. Однак, як уже говорилося, дана проблема переважно виникає через некоректне налаштування Ceph на початкових етапах: дуже важливо зробити реконфігурацію, щоб вона не виявлялася в майбутньому.

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

  • занадто велике значення replication_count в одному з пулів,
  • надто висока кількість PG в одному пулі і надто в маленьке — в іншому.

Скористаємося вже згаданим калькулятором. У ньому наочно показано, що потрібно запроваджувати і, в принципі, немає нічого складного. Задавши необхідні параметри, отримуємо наступні рекомендації:

Примітка: якщо ви налаштуєте Ceph-кластер з нуля, ще однією корисною функцією калькулятора виявиться генерація команд, які створять пули з нуля з параметрами, вказаними в таблиці.

Зорієнтуватися допомагає останній стовпець. Suggested PG Count. У нашому випадку корисний ще й другий, де вказано параметр реплікації, оскільки вирішили змінити і множник реплікації.

Отже, спочатку потрібно змінити параметри реплікації - це варто робити в першу чергу, оскільки, зменшивши множник, ми звільнимо дисковий простір. У процесі виконання команди можна помітити, що значення доступного дискового обсягу збільшуватиметься:

ceph osd pool $pool_name set $replication_size

А після її завершення – змінюємо значення параметрів pg_num и pgp_num наступним чином:

ceph osd pool set $pool_name pg_num $pg_number
ceph osd pool set $pool_name pgp_num $pg_number

Важливо: ми повинні послідовно в кожному пулі змінити кількість PG і не змінювати значення в інших пулах, доки не зникнуть попередження «Degraded data redundancy» и "n-number of pgs degraded".

Перевірити, що все пройшло успішно, можна також за висновками команд ceph health detail и ceph -s.

Кейс №3. Міграція віртуальної машини з LVM до Ceph RBD

У ситуації, коли у проекті використовуються віртуальні машини, встановлені на орендовані сервери bare-metal, часто постає питання з стійким до відмови сховищем. А ще дуже бажано, щоб місця в цьому сховищі було достатньо... Інша поширена ситуація: є віртуальна машина з локальним сховищем на сервері і потрібно розширити диск, але нікуди, оскільки на сервері не залишилося вільного простору.

Проблему можна вирішити різними способами - наприклад, міграцією на інший сервер (якщо є) або додаванням нових дисків на сервер. Але не завжди виходить це зробити, тому міграція з LVM до Ceph може стати відмінним вирішенням цієї проблеми. Вибравши такий варіант, ми також спрощуємо подальший процес міграції між серверами, тому що не потрібно буде переміщати локальне сховище з гіпервізора на інший. Єдина заковика - доведеться зупинити ВМ на час проведення робіт.

Як наведений далі рецепт взята стаття з цього блогу, інструкції якої були випробувані у дії. До речі, там же описаний і спосіб безпростої міграціїОднак у нашому випадку він просто не був потрібний, тому ми його не перевіряли. Якщо це критично для вашого проекту — будемо раді дізнатися про результати в коментарях.

Приступимо до практичної частини. У прикладі ми використовуємо virsh і, відповідно, libvirt. Для початку переконайтеся, що пул Ceph'а, до якого будуть мігровані дані, підключений до libvirt:

virsh pool-dumpxml $ceph_pool

В описі пулу повинні бути дані підключення до Ceph з даними для авторизації.

Наступний етап полягає в тому, що LVM-образ конвертується в Ceph RBD. Час виконання залежить насамперед від розміру образу:

qemu-img convert -p -O rbd /dev/main/$vm_image_name rbd:$ceph_pool/$vm_image_name

Після конвертації залишиться LVM-образ, який буде корисним у разі, якщо мігрувати ВМ в RBD не вийде і доведеться відкочувати зміни. Також – для можливості швидко відкотити зміни – зробимо бекап конфігураційного файлу віртуальної машини:

virsh dumpxml $vm_name > $vm_name.xml
cp $vm_name.xml $vm_name_backup.xml

… і відредагуємо оригінал (vm_name.xml). Знайдемо блок із описом диска (починається з рядка <disk type='file' device='disk'> і закінчується на </disk>) і наведемо його до такого вигляду:

<disk type='network' device='disk'>
<driver name='qemu'/>
<auth username='libvirt'>
  <secret type='ceph' uuid='sec-ret-uu-id'/>
 </auth>
<source protocol='rbd' name='$ceph_pool/$vm_image_name>
  <host name='10.0.0.1' port='6789'/>
  <host name='10.0.0.2' port='6789'/>
</source>
<target dev='vda' bus='virtio'/> 
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</disk>

Розберемо деякі деталі:

  1. У протокол source вказується адреса до сховища в Ceph RBD (це адреса із зазначенням назви Ceph-пулу та RBD-образу, який визначався на першому етапі).
  2. У блоці secret вказується тип ceph, а також UUID секрет для підключення до нього. Його uuid можна дізнатися за допомогою команди virsh secret-list.
  3. У блоці host вказуються адреси до моніторів Ceph.

Після редагування конфігураційного файлу та завершення конвертації LVM у RBD можна застосувати змінений конфігураційний файл та запустити віртуальну машину:

virsh define $vm_name.xml
virsh start $vm_name

Саме час перевірити, що віртуальна машина запустилася коректно: це можна дізнатися, наприклад, підключившись до неї SSH або через virsh.

Якщо віртуальна машина працює коректно і ви не виявили інших проблем, можна видалити LVM-образ, який більше не використовується:

lvremove main/$vm_image_name

Висновок

З усіма описаними випадками ми зіткнулися на практиці — сподіваємося, що інструкції допоможуть іншим адміністраторам вирішити схожі проблеми. Якщо у вас є зауваження або інші подібні історії з досвіду експлуатації Ceph – будемо раді побачити їх у коментарях!

PS

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук