Избор на CEPH. Част 1
Имахме пет шкафа, десет оптични суичове, настроен BGP, десетина SSD диска и куп SAS дискове във всевъзможни цветове и размери, а също и proxmox и желание да поставим всичката статичност в собствено S3 хранилище. Не беше, че всичко това беше необходимо за виртуализация, но след като започнах да използвам opensource — е, иди си изцяло на хобито. Единственото, което ме тревожеше, беше BGP. Няма никой по-безпомощен, безотговорен и безнравствен в света от вътрешната маршрутизация по BGP. И знаех, че много скоро ще се потопим в него.

Задачата беше банална — имаше CEPH, който не работеше много добре. Трябваше да стане „добре“.
Кластерът, който ми беше предоставен, беше хетерогенен, настроен на бързо и почти не тюнингован. Той се състоеше от две групи различни нодове, с една обща мрежа, изпълняваща ролята както на кластерна, така и на публична мрежа. Нодовете бяха натъпкани с четири типа дискове — два типа SSD, сглобени в две отделни правила за разположение, и два типа HDD с различни размери, сглобени в трета група. Проблемът с различните размери беше решен с различни тежести OSD.
Самото настройки бяха разделени на две части — тюнинг на операционната система и тюнинг на самия CEPH и неговите настройки.
Оптимизиране на ОС
Мрежа
Високата латентност се отразяваше както при запис, така и при балансиране. При записа — защото клиентът не получава отговор за успешен запис, докато репликите на данните в другите групи за разположение не потвърдят успеха. Понеже правилата за разпределение на репликите в CRUSH map бяха по една реплика на хост, за мрежата се използваше постоянно.
Затова първото нещо, което реших, беше да настроя текущата мрежа, паралелно опитвайки се да убедя всички да преминат на отделни мрежи.
За начало промених настройките на мрежовите карти. Започнах с настройка на опашките:
какво имаше:
ethtool -l ens1f1
root@ceph01:~# ethtool -l ens1f1
Параметри на канала за ens1f1:
Предварително зададени максимуми:
RX: 0
TX: 0
Други: 1
Комбинирани: 63
Текущи хардуерни настройки:
RX: 0
TX: 0
Други: 1
Комбинирани: 1
root@ceph01:~# ethtool -g ens1f1
Параметри на опашката за ens1f1:
Предварително зададени максимуми:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Текущи хардуерни настройки:
RX: 256
RX Mini: 0
RX Jumbo: 0
TX: 256
root@ceph01:~# ethtool -l ens1f1
Параметри на канала за ens1f1:
Предварително зададени максимуми:
RX: 0
TX: 0
Други: 1
Комбинирани: 63
Текущи хардуерни настройки:
RX: 0
TX: 0
Други: 1
Комбинирани: 1Ясно е, че текущите параметри са далеч от максималните. Увеличих:
root@ceph01:~#ethtool -G ens1f0 rx 4096
root@ceph01:~#ethtool -G ens1f0 tx 4096
root@ceph01:~#ethtool -L ens1f0 combined 63Ръководейки се от отлична статия
увеличи дължината на опашката за изпращане txqueuelen от 1000 до 10 000
root@ceph01:~#ip link set ens1f0 txqueuelen 10000Съобразявайки се с документацията на Ceph
увеличи MTU до 9000.
root@ceph01:~#ip link set dev ens1f0 mtu 9000Добавих в /etc/network/interfaces, за да се зареди всичко посочено по-горе при стартиране
cat /etc/network/interfaces
root@ceph01:~# cat /etc/network/interfaces
auto lo
iface lo inet loopback
auto ens1f0
iface ens1f0 inet manual
post-up /sbin/ethtool -G ens1f0 rx 4096
post-up /sbin/ethtool -G ens1f0 tx 4096
post-up /sbin/ethtool -L ens1f0 combined 63
post-up /sbin/ip link set ens1f0 txqueuelen 10000
mtu 9000
auto ens1f1
iface ens1f1 inet manual
post-up /sbin/ethtool -G ens1f1 rx 4096
post-up /sbin/ethtool -G ens1f1 tx 4096
post-up /sbin/ethtool -L ens1f1 combined 63
post-up /sbin/ip link set ens1f1 txqueuelen 10000
mtu 9000След което, в съответствие с тази статия, започнах старателно да настроявам ядрата 4.15. Имайки предвид, че нодовете имат 128G RAM, се получи някакъв конфигурационен файл за sysctl
cat /etc/sysctl.d/50-ceph.conf
net.core.rmem_max = 56623104
#Максимален размер на буфера за получаване на данни за всички връзки 54M
net.core.wmem_max = 56623104
#Максимален размер на буфера за предаване на данни за всички връзки 54M
net.core.rmem_default = 56623104
#Размер на буфера за получаване на данни по подразбиране за всички връзки. 54M
net.core.wmem_default = 56623104
#Размер на буфера за предаване на данни по подразбиране за всички връзки 54M
# за всеки сокет
net.ipv4.tcp_rmem = 4096 87380 56623104
#Векторна (минимум, по подразбиране, максимум) променлива в файла tcp_rmem
# съдържа 3 цели числа, които определят размера на буфера за получаване на сокети TCP.
# Минимум: всеки сокет TCP има право да използва тази памет при
# факта на създаването му. Възможността за използване на такъв буфер
# е гарантирана дори при достигане на границата на ограничения (умерено натоварване на паметта).
# Размерът на минималния буфер по подразбиране е 8 Кбайта (8192).
#Стойността по подразбиране: количеството памет, допустимо за буфера
# за предаване на сокета TCP по подразбиране. Тази стойност замества
# параметъра /proc/sys/net/core/rmem_default, използван от другите протоколи.
# Стойността на използвания по подразбиране буфер обикновено (по подразбиране)
# е 87830 байта. Това определя размера на прозореца 65535 с
# зададено по подразбиране значение tcp_adv_win_scale и tcp_app_win = 0,
# което е малко по-малко от определеното по подразбиране значение tcp_app_win.
# Максимум: максималният размер на буфера, който може да бъде автоматично
# разпределен за получаване на сокета TCP. Тази стойност не отменя максимума,
# зададен в файла /proc/sys/net/core/rmem_max. При "статично"
# разпределение на паметта чрез SO_RCVBUF този параметър няма значение.
net.ipv4.tcp_wmem = 4096 65536 56623104
net.core.somaxconn = 5000
# Максимален брой на отворените сокети, чакащи връзки.
net.ipv4.tcp_timestamps=1
# Разрешава използването на времеви печати (timestamps), в съответствие с RFC 1323.
net.ipv4.tcp_sack=1
# Разрешаване на изборни потвърждения за протокола TCP
net.core.netdev_max_backlog=5000 (дефолт 1000)
# максимален брой пакети в опашката за обработка, ако
# интерфейсът получава пакети по-бързо, отколкото ядрото може да ги обработи.
net.ipv4.tcp_max_tw_buckets=262144
# Максимален брой на сокетите, които са в състояние TIME-WAIT едновременно.
# При надвишаване на този праг – „излишният“ сокет се унищожава и се записва
# съобщение в системния журнал.
net.ipv4.tcp_tw_reuse=1
#Разрешаваме повторното използване на TIME-WAIT сокети в случаи,
# при които протоколът счита това за безопасно.
net.core.optmem_max=4194304
#Увеличаване на максималния общ буфер-пространство ALLOCATABLE
#измерва се в единици страници (4096 байта)
net.ipv4.tcp_low_latency=1
#Разрешава на TCP/IP стека да дава предимство на ниското време на изчакване
# пред силната пропускателна способност.
net.ipv4.tcp_adv_win_scale=1
# Тази променлива влияе на изчисляването на обема на паметта в буфера на сокета,
# выделяемой под размер TCP-прозореца и под буфера на приложението.
# Ако величината tcp_adv_win_scale е отрицателна, то за изчисляване на размера
# се използва следното изразяване:
# Bytes- bytes2 на степен -tcp_adv_win_scale
# Където bytes – това е размерът на прозореца в байтове. Ако величината tcp_adv_win_scale
# е положителна, то за определяне на размера се използва следното изразяване:
# Bytes- bytes2 на степен tcp_adv_win_scale
# Променливата приема цяло число. Стойността по подразбиране е 2,
# т.е. за буфера на приложението е запазена ¼ част от обема, определен от променливата
# tcp_rmem.
net.ipv4.tcp_slow_start_after_idle=0
# механизъм за повторно стартиране на бавния старт, който нулира стойността на прозореца
# на претоварване, ако връзката не е била използвана за зададен период от време.
# По-добре е да се деактивира SSR на сървъра, за да се подобри производителността
# на дългосрочните връзки.
net.ipv4.tcp_no_metrics_save=1
#Не запазвайте резултатите от измерванията на TCP връзката в кеша при нейното затваряне.
net.ipv4.tcp_syncookies=0
#Деактивирайте механизма за изпращане на syncookie
net.ipv4.tcp_ecn=0
#Explicit Congestion Notification (Явно Уведомление за Претоварване) в
# TCP-соединениях. Използва се за уведомление за настъпването на "запушване"
# на маршрута към зададения хост или мрежа. Може да се използва за уведомление
# на хост-изпращач за необходимостта от намаляване на скоростта на предаване на пакети през
# конкретен маршрутизатор или защитна стена.
net.ipv4.conf.all.send_redirects=0
# изключва издаването на ICMP Redirect … на други хостове. Тази опция е задължителна
# да бъде включена, ако хостът действа като рутер от какъвто и да е вид.
# Нямаме рутинг.
net.ipv4.ip_forward=0
#Същото изключване на форвардинга. Не сме шлюз, Docker на машините не е стартиран,
# не ни е необходимо.
net.ipv4.icmp_echo_ignore_broadcasts=1
#Не отговаряме на ICMP ECHO заявки, предадени чрез широковещателни пакети.
net.ipv4.tcp_fin_timeout=10
#определя времето за запазване на сокета в състояние FIN-WAIT-2 след него
# закриване от локалната страна. По подразбиране 60.
net.core.netdev_budget=600 # (по подразбиране 300)
# Ако извършването на софтуерни прекъсвания не продължава достатъчно дълго,
# тогава темпът на растеж на входящите данни може да надвиши способността на ядрото
# да опустоши буфера. В резултат на това буферите на NIC ще се препълнят и трафикът ще бъде загубен.
# Понякога е необходимо да се увеличи продължителността на работа на SoftIRQs
# (софтуерни прекъсвания) с CPU. За това отговаря netdev_budget.
# Стойността по подразбиране е 300. Параметърът ще накара процеса SoftIRQ да обработи
# 300 пакета от NIC преди да освободи CPU.
net.ipv4.tcp_fastopen=3
# TFO TCP Fast Open
# ако и клиентът, и сървърът поддържат TFO, за което се сигнализира чрез
# специален флаг в TCP пакета. В нашия случай е плацебо, просто
# изглежда красиво.Смрежа лустер беше отделена на отделни 10Gbps мрежови интерфейси в отделна плоска мрежа. На всяка машина бяха поставени мрежови двупортови карти mellanox 10/25 Gbps, свързани към два отделни 10Gbps суича. Агрегацията се осъществяваше с OSPF, тъй като бондингът с lacp по някаква причина показа максимална пропускателна способност от 16 Gbps, докато ospf успешно усвояваше напълно двете десетки на всяка машина. В по-нататъшните планове беше предвидено да се използва ROCE на тези меланокси, за да се намали латентността. Как настройвахме тази част от мрежата:
- Тъй като самите машини имат външни айпишници на BGP, ни е необходим софтуер — ( по-точно в момента на написване на статията това беше ) това вече беше инсталирано.
- Общо на машините имаше две мрежови карти с по два интерфейса — общо 4 порта. Една мрежова карта с два порта гледаше към фабриката и на нея беше настроен BGP, а втората — с два порта гледаше към два различни суича и на нея беше настроен OSPF
Подробности за настройката на OSPF: Основната задача е да се агрегат двата линка и да се има отказоустойчивост.
двата мрежови интерфейса са настроени в две прости плоски мрежи — 10.10.10.0/24 и 10.10.20.0/24
1: ens1f0: mtu 9000 qdisc mq state UP group default qlen 1000
inet 10.10.10.2/24 brd 10.10.10.255 scope global ens1f0
2: ens1f1: mtu 9000 qdisc mq state UP group default qlen 1000
inet 10.10.20.2/24 brd 10.10.20.255 scope global ens1f1по които машините виждат една друга.
ДИСК
Следващата стъпка беше да оптимизирам работата на дисковете. За SSD смених планировчика на noop, за HDD — deadline. Грубо казано — NOOP работи по принципа „който първи се е надигнал — този ще вземе чехлите“, което на английски се нарича „FIFO (First In, First Out)“. Запитванията влизат в опашка по реда на тяхното постъпване. DEADLINE е по-ориентиран към четене, плюс процесът от опашката получава практически монополен достъп до диска по време на операцията. Това отлично подхожда на нашата система — тъй като с всеки диск работи само един процес — OSD демон.
(Желаещите да се потопят в планировчика на входно-изходните операции могат да прочетат за него тук:
Предпочитащите да четат на руски: )
В препоръките за оптимизация на Linux се съветва също да се увеличи nr_request
nr_requests
Стойността на nr_requests определя броя на I/O исканията, които се буферизират преди I/O планиращия да изпрати/приеме данни от блоковото устройство. Ако използвате RAID карта или Блоково устройство, което може да обработва по-голяма опашка от това, което е зададено на I/O планиращия, увеличаването на стойността на nr_requests може да помогне за подобряване на продуктивността и намаляване на натоварването на сървъра, когато на сървъра се извършват големи количества I/O операции. Ако използвате Deadline или CFQ като планиращ, се предлага да зададете стойността на nr_request на 2 пъти стойността на дълбочината на опашката.
НО! Самите граждани разработчици на CEPH ни убеждават, че тяхната система от приоритети работи по-добре.

WBThrottle и/или nr_requests
WBThrottle и/или nr_requests
Файловото хранилище използва буферизирани операции за запис на вход/изход; това предоставя редица предимства, ако журналът на файловото хранилище е на по-бързо устройство. Клиентските заявки получават уведомления веднага щом данните бъдат записани в журнала, а след това се записват на основния диск по-късно, използвайки стандартната функционалност на Linux. Това позволява на OSD шпинделни дискове да предоставят латентност на запис, подобна на SSD при запис на малки пакети. Такова забавено записване също позволява на ядрото да пренаредить I/O операциите към диска, с надеждата да ги слее, или да позволи на вече наличните глави на диска да изберат по-оптимален маршрут сред техните платки. Крайният ефект е, че можете да извлечете леко повече операции вход/изход от всеки диск, отколкото би било възможно при директни или синхронни операции вход/изход.
Въпреки това, възниква определен проблем, ако обемът на входящите записи в този кластер Ceph надвишава всички възможности на базовите дискове. В такъв сценарий общото число на заявките за вход/изход в изчакване за запис на диск може неконтролируемо да нараства и да доведе до опашки от операции вход/изход, запълващи целия диск и опашките на Ceph. Заявките за четене оказват особено неблагоприятно влияние, тъй като те се блокират между заявките за запис, които може да изискват няколко секунди за сброс на основния диск.
За да се справите с този проблем, Ceph разполага с вградена система за контрол на отложените записи (writeback), наречена WBThrottle. Тази система е проектирана да ограничава общото количество операции за запис, които могат да се поставят в опашка и да започнат своя процес на изпразване по-рано, отколкото би се случило естествено, благодарение на активирането от самото ядро. За съжаление, тестването показва, че зададените по подразбиране стойности все още не могат да намалят съществуващото поведение до ниво, което да минимизира такова въздействие върху латентността на операциите за четене. Регулирането на тези стойности може да промени поведението и да намали общата дължина на опашките за записи, като направи въздействието по-слабо. Въпреки това, има известен компромис: като намалите общия максимален брой разрешени за поставяне в опашка записи, можете да намалите възможността на самото ядро да максимизира своята ефективност по отношение на подреждането на входящите заявки. Струва си да обмислите какво точно е необходимо за вашия конкретен случай на приложение и работни натоварвания, и да регулирате съответно.
За да управлявате дълбочината на опашката за отложени записи, можете или да намалите общия максимален брой неизпълнени операции за вход/изход, прилагаща настройките на WBThrottle, или да намалите максималната стойност за неизпълнени операции на самото блоково ниво на вашето ядро. И двете решения могат ефективно да управляват едно и също поведение и именно вашите предпочитания ще определят как ще се реализира тази настройка.
Важно е да се отбележи, че наличната в Ceph система за приоритизиране на операциите е по-ефективна за по-кратки заявки на дисково ниво. При съкращаване на общата опашка за конкретния диск, основното местоположение на опашката се премества в Ceph, където той има по-добър контрол върху приоритета на операциите за вход/изход. Нека разгледаме следния пример:
echo 8 > /sys/block/sda/queue/nr_requestsОБЩО
И още няколко настройки на ядрото, които ще направят вашата система по-гладка и ще извлекат още малко производителност от хардуера.
cat /etc/sysctl.d/60-ceph2.conf
kernel.pid_max = 4194303
# Дисковете в всяка машина са по 25, затова пресмятахме, че процесите ще бъдат много
kernel.threads-max=2097152
# Тредовете, естествено, също.
vm.max_map_count=524288
# Увеличихме броя на областите за картографиране на паметта на процеса.
# Както е посочено в документацията за ядрени променливи,
# областите за картографиране на паметта се използват като страничен ефект на извикването
# на malloc, директно чрез mmap, mprotect и madvise, както и при зареждане
# на общи библиотеки.
fs.aio-max-nr=50000000
# Настройваме параметрите на входно-изходния процес
# Ядро Linux предлага функция за асинхронен неблокиращ вход-изход (AIO),
# която позволява на процеса да инициира множество входно-изходни операции
# едновременно, без да чака завършването на някоя от тях.
# Това помага за повишаване на производителността на приложенията,
# които могат да припокриват обработката и входно-изходните операции.
# Параметърът aio-max-nr определя максималния брой допустими
# simultaneus запитвания.
vm.min_free_kbytes=1048576
# минималният размер на свободната памет, който е необходимо да се поддържа.
# Настроен е на 1Gb, което е напълно достатъчно за функционирането на операционната система,
# и позволява да се избегне OOM Killer за процесите OSD. Въпреки че паметта е в достатъчно количество,
# но запас за джоба не вреди
vm.swappiness=10
# Казваме да се използва своп, ако остане свободно 10% памет.
# На машините с 128G оперативна памет, 10% означава 12 Гига. По-отверно е за работа.
# Стандартният параметър от 60% предизвикваше забавяния на системата, влизайки в своп,
# когато имаше още много свободна памет
vm.vfs_cache_pressure=1000
# Увеличаваме от стандартните 100. Заставяме ядрото да освобождава
# неизползвани страници памет от кеша.
vm.zone_reclaim_mode=0
# Позволява да се задават по-агресивни или по-малко агресивни подходи
# за възстановяване на паметта, когато в зоната свърши паметта.
# Ако е зададено на нула, не се извършва възстановяване на зоната.
# За файлови сървъри или работни натоварвания
# е изгодно, ако данните им са кеширани, zone_reclaim_mode
# да остане отключен, тъй като ефектът на кеширане,
# вероятно ще бъде по-важен от местоположението на данните.
vm.dirty_ratio=20
# Процент оперативна памет, която може да бъде отделена за "мръсни" страници
# Пресметнахме от ориентировъчно изчисление:
# В системата има 128 гига памет.
# Приблизително по 20 SSD диска, при които е зададено в конфигурацията на CEPH
# да отделят по 3G оперативка за кеширане.
# Приблизително по 40 HDD диска, за които този параметър е равен на 1G.
# 20% от 128 е 25.6 гига. И така, в случай на максимална употреба на памет,
# за системата остава 2.4G памет. Кое би трябвало да е достатъчно, за да оцелее и да изчака
# пристигането на кавалерията - тоест идването на DevOps, който ще поправи всичко.
vm.dirty_background_ratio=3
# процент от системната памет, която може да запълни dirty pages, преди
# фоновите процеси pdflush/flush/kdmflush да ги запишат на диск
fs.file-max=524288
# И за откритите файлове вероятно ще имаме много повече, отколкото е зададено по подразбиране. Потапяне в CEPH
Настройки, на които бихме искали да се спрем по-подробно:
cat /etc/ceph/ceph.conf
osd:
journal_aio: true # Три параметра, включващи
journal_block_align: true # директен i/o
journal_dio: true # за журнал
journal_max_write_bytes: 1073714824 # Нека увеличим максималния размер
# на операцията, записвана в журнал
journal_max_write_entries: 10000 # А и броя на едновременните записи
journal_queue_max_bytes: 10485760000
journal_queue_max_ops: 50000
rocksdb_separate_wal_dir: true # Решихме да имаме отделен wal
# Опитахме се да отделим IGN
bluestore_block_db_create: true # И за журнала отделно устройство
bluestore_block_db_size: '5368709120 #5G'
bluestore_block_wal_create: true
bluestore_block_wal_size: '1073741824 #1G'
bluestore_cache_size_hdd: '3221225472 # 3G'
# голям обем оперативна памет позволява
# съхраняване на доста големи обеми
bluestore_cache_size_ssd: '9663676416 # 9G'
keyring: /var/lib/ceph/osd/ceph-$id/keyring
osd_client_message_size_cap: '1073741824 #1G'
osd_disk_thread_ioprio_class: idle
osd_disk_thread_ioprio_priority: 7
osd_disk_threads: 2 # брой нишки за демона на един диск
osd_failsafe_full_ratio: 0.95
osd_heartbeat_grace: 5
osd_heartbeat_interval: 3
osd_map_dedup: true
osd_max_backfills: 2 # брой едновременни операции за запълване на един ОСД.
osd_max_write_size: 256
osd_mon_heartbeat_interval: 5
osd_op_threads: 16
osd_op_num_threads_per_shard: 1
osd_op_num_threads_per_shard_hdd: 2
osd_op_num_threads_per_shard_ssd: 2
osd_pool_default_min_size: 1 # Характеристики на жадността. Много бързо стана
osd_pool_default_size: 2 # да не достига място, защото временно
# решение беше намаляване на броя
# дубли на данните
osd_recovery_delay_start: 10.000000
osd_recovery_max_active: 2
osd_recovery_max_chunk: 1048576
osd_recovery_max_single_start: 3
osd_recovery_op_priority: 1
osd_recovery_priority: 1 # параметърът се регулира при необходимост в движение
osd_recovery_sleep: 2
osd_scrub_chunk_max: 4Част от параметрите, които бяха тествани на QA на версия 12.2.12, липсват във версия ceph 12.2.2, например osd_recovery_threads. Ето защо в плановете беше включено обновление на продукцията до 12.2.12. Практиката показа съвместимост между версиите 12.2.2 и 12.2.12 в един и същи клъстер, което позволява извършване на rolling update.
Тестов клъстер
Естествено, за тестовете беше необходимо да имаме същата версия, каквато е на продукция, но в момента, в който започнах работа с кластера, в репозиторията имаше само по-нова версия. След като видяхме, че разликите в минорната версия не са особено големи (1393 редове в конфигурациите срещу 1436 в новата версия), решихме да започнем да тестваме новата версия (все пак трябва да се обновим, няма смисъл да работим с старата версия)
Единственото, което се опитахме да запазим от старата версия, е пакетът ceph-deploy, тъй като част от утилитите (и част от служителите) бяха адаптирани към нейния синтаксис. Новата версия значително се различаваше, но не оказа влияние на работата на самия кластер, затова я оставихме в версията 1.5.39
Тъй като екипът ceph-disk явно казва, че е остарял и ни призовава, уважаеми, да използваме командата ceph-volume — започнахме да създаваме OSD точно с тази команда, без да губим време за остарялата.
Планът беше такъв — да създадем огледало от два SSD диска, на които ще разположим журналите на OSD, които от своя страна са на ротационни SAS дискове. По този начин ще се предпазим от проблеми с данни при падане на диска с журнал.
Клъстерът започна да се изгражда по документацията
cat /etc/ceph/ceph.conf
root@ceph01-qa:~# cat /etc/ceph/ceph.conf # поставен предварително подготвен конфигурационен файл
[client]
rbd_cache = true
rbd_cache_max_dirty = 50331648
rbd_cache_max_dirty_age = 2
rbd_cache_size = 67108864
rbd_cache_target_dirty = 33554432
rbd_cache_writethrough_until_flush = true
rbd_concurrent_management_ops = 10
rbd_default_format = 2
[global]
auth_client_required = cephx
auth_cluster_required = cephx
auth_service_required = cephx
cluster network = 10.10.10.0/24
debug_asok = 0/0
debug_auth = 0/0
debug_buffer = 0/0
debug_client = 0/0
debug_context = 0/0
debug_crush = 0/0
debug_filer = 0/0
debug_filestore = 0/0
debug_finisher = 0/0
debug_heartbeatmap = 0/0
debug_journal = 0/0
debug_journaler = 0/0
debug_lockdep = 0/0
debug_mon = 0/0
debug_monc = 0/0
debug_ms = 0/0
debug_objclass = 0/0
debug_objectcatcher = 0/0
debug_objecter = 0/0
debug_optracker = 0/0
debug_osd = 0/0
debug_paxos = 0/0
debug_perfcounter = 0/0
debug_rados = 0/0
debug_rbd = 0/0
debug_rgw = 0/0
debug_throttle = 0/0
debug_timer = 0/0
debug_tp = 0/0
fsid = d0000000d-4000-4b00-b00b-0123qwe123qwf9
mon_host = ceph01-q, ceph02-q, ceph03-q
mon_initial_members = ceph01-q, ceph02-q, ceph03-q
public network = 8.8.8.8/28 # адресът е променен, естествено ))
rgw_dns_name = s3-qa.mycompany.ru # и този адрес е променен
rgw_host = s3-qa.mycompany.ru # и този също
[mon]
mon allow pool delete = true
mon_max_pg_per_osd = 300 # повече от триста плейсмънт групи
# на диск не решихме
# макар параметърът, естествено, да зависи от броя на пуловете,
# техните размери и броя на OSD. Имате малко, но здрави PG
# също не е най-добрият избор - страда точността на балансировката
mon_osd_backfillfull_ratio = 0.9
mon_osd_down_out_interval = 5
mon_osd_full_ratio = 0.95 # засега за SSD дискове пространството за техния
# журнал е същото устройство, което е и за ОSD
# решихме, че 5% от диска (който е с размер 1.2Tb)
# трябва да е напълно достатъчно, и корелира с параметъра
# bluestore_block_db_size плюс вариативност при големи
# плейсмънт групи
mon_osd_nearfull_ratio = 0.9
mon_pg_warn_max_per_osd = 520
[osd]
bluestore_block_db_create = true
bluestore_block_db_size = 5368709120 #5G
bluestore_block_wal_create = true
bluestore_block_wal_size = 1073741824 #1G
bluestore_cache_size_hdd = 3221225472 # 3G
bluestore_cache_size_ssd = 9663676416 # 9G
journal_aio = true
journal_block_align = true
journal_dio = true
journal_max_write_bytes = 1073714824
journal_max_write_entries = 10000
journal_queue_max_bytes = 10485760000
journal_queue_max_ops = 50000
keyring = /var/lib/ceph/osd/ceph-$id/keyring
osd_client_message_size_cap = 1073741824 #1G
osd_disk_thread_ioprio_class = idle
osd_disk_thread_ioprio_priority = 7
osd_disk_threads = 2
osd_failsafe_full_ratio = 0.95
osd_heartbeat_grace = 5
osd_heartbeat_interval = 3
osd_map_dedup = true
osd_max_backfills = 4
osd_max_write_size = 256
osd_mon_heartbeat_interval = 5
osd_op_num_threads_per_shard = 1
osd_op_num_threads_per_shard_hdd = 2
osd_op_num_threads_per_shard_ssd = 2
osd_op_threads = 16
osd_pool_default_min_size = 1
osd_pool_default_size = 2
osd_recovery_delay_start = 10.0
osd_recovery_max_active = 1
osd_recovery_max_chunk = 1048576
osd_recovery_max_single_start = 3
osd_recovery_op_priority = 1
osd_recovery_priority = 1
osd_recovery_sleep = 2
osd_scrub_chunk_max = 4
osd_scrub_chunk_min = 2
osd_scrub_sleep = 0.1
rocksdb_separate_wal_dir = true# создаем мониторы
root@ceph01-qa:~#ceph-deploy mon create ceph01-q
# генерируем ключи для аутентификации нод в кластере
root@ceph01-qa:~#ceph-deploy gatherkeys ceph01-q
# Это если поштучно. Если у нас несколько машин доступны - те, которые описаны в конфиге в секции
# mon_initial_members = ceph01-q, ceph02-q, ceph03-q
# можно запустить эти две команды в виде одной
root@ceph01-qa:~#ceph-deploy mon create-initial
# Положим ключи в указанные в конфиге места
root@ceph01-qa:~#cat ceph.bootstrap-osd.keyring > /var/lib/ceph/bootstrap-osd/ceph.keyring
root@ceph01-qa:~#cat ceph.bootstrap-mgr.keyring > /var/lib/ceph/bootstrap-mgr/ceph.keyring
root@ceph01-qa:~#cat ceph.bootstrap-rgw.keyring > /var/lib/ceph/bootstrap-rgw/ceph.keyring
# создадим ключ для управления кластером
root@ceph01-qa:~#ceph-deploy admin ceph01-q
# и менеджер, плагинами управлять
root@ceph01-qa:~#ceph-deploy mgr create ceph01-qПървото, с което се сблъсках в работата на тази версия ceph-deploy с клъстера версия 12.2.12, е грешка при опит за създаване на OSD с db на софтуерен RAID —
root@ceph01-qa:~#ceph-volume lvm create --bluestore --data /dev/sde --block.db /dev/md0
blkid не можа да открие PARTUUID за устройството: /dev/md1Наистина, blkid не показва PARTUUID, наложи се да създам разпределения ръчно:
root@ceph01-qa:~#parted /dev/md0 mklabel GPT
# ще има много разпределения,
# без GPT не могат да се създадат
# размерът на разпределението посочихме в конфигурацията по-горе = bluestore_block_db_size: '5368709120 #5G'
# Имам 20 диска за OSD, не ми се създават раздели на ръка
# затова направих цикъл
root@ceph01-qa:~#for i in {1..20}; do echo -e "nnnn+5Gnw" | fdisk /dev/md0; doneИзглежда всичко е готово, опитваме отново да създадем OSD и получаваме следната грешка (която, между другото, не се прояви на продукция)
при създаването на OSD тип bluestore без уточнение на пътя към WAL, но с указание на db
root@ceph01-qa:~#ceph-volume lvm create --bluestore --data /dev/sde --block.db /dev/md0
stderr: 2019-04-12 10:39:27.211242 7eff461b6e00 -1 bluestore(/var/lib/ceph/osd/ceph-0/) _read_fsid неразбираем uuid
stderr: 2019-04-12 10:39:27.213185 7eff461b6e00 -1 bdev(0x55824c273680 /var/lib/ceph/osd/ceph-0//block.wal) open open получи: (22) Невалиден аргумент
stderr: 2019-04-12 10:39:27.213201 7eff461b6e00 -1 bluestore(/var/lib/ceph/osd/ceph-0/) _open_db добави блоково устройство(/var/lib/ceph/osd/ceph-0//block.wal) върна: (22) Невалиден аргумент
stderr: 2019-04-12 10:39:27.999039 7eff461b6e00 -1 bluestore(/var/lib/ceph/osd/ceph-0/) mkfs неуспешно, (22) Невалиден аргумент
stderr: 2019-04-12 10:39:27.999057 7eff461b6e00 -1 OSD::mkfs: ObjectStore::mkfs неуспешно с грешка (22) Невалиден аргумент
stderr: 2019-04-12 10:39:27.999141 7eff461b6e00 -1 ** ГРЕШКА: грешка при създаването на празен обект хранилище в /var/lib/ceph/osd/ceph-0/: (22) Невалиден аргументПри това, ако на същия RAID (или на друго място, по избор) създам още едно разпределение под WAL и го посоча при създаването на OSD — всичко ще мине гладко (с изключение на появата на отделно WAL, което, може би, не искате).
Но, тъй като все пак в далечните планове беше да преместя WAL на NVMe, то практиката не се оказа излишна.
root@ceph01-qa:~#ceph-volume lvm create --bluestore --data /dev/sdf --block.wal /dev/md0p2 --block.db /dev/md1p2Създадохме монитори, мениджъри и OSD. Сега искаме да ги групираме по различен начин, тъй като в плановете имаме дискове от различен тип — бързи пули на SSD и големи, но бавни на SAS дискове.
Да приемем, че на сървърите има по 20 диска, първата десетка е един тип, втората — друг.
Първоначалната, дефолтна, карта изглежда така:
ceph osd tree
root@ceph01-q:~# ceph osd tree
ID КЛАС ТЕГЛО ТИП ИМЕ СТАТУС ПРЕОЦЕНКА PRI-AFF
-1 14.54799 корен по подразбиране
-3 9.09200 хост ceph01-q
0 ssd 1.00000 osd.0 нагоре 1.00000 1.00000
1 ssd 1.00000 osd.1 нагоре 1.00000 1.00000
2 ssd 1.00000 osd.2 нагоре 1.00000 1.00000
3 ssd 1.00000 osd.3 нагоре 1.00000 1.00000
4 hdd 1.00000 osd.4 нагоре 1.00000 1.00000
5 hdd 0.27299 osd.5 нагоре 1.00000 1.00000
6 hdd 0.27299 osd.6 нагоре 1.00000 1.00000
7 hdd 0.27299 osd.7 активен 1.00000 1.00000
8 hdd 0.27299 osd.8 активен 1.00000 1.00000
9 hdd 0.27299 osd.9 активен 1.00000 1.00000
10 hdd 0.27299 osd.10 активен 1.00000 1.00000
11 hdd 0.27299 osd.11 активен 1.00000 1.00000
12 hdd 0.27299 osd.12 активен 1.00000 1.00000
13 hdd 0.27299 osd.13 активен 1.00000 1.00000
14 hdd 0.27299 osd.14 активен 1.00000 1.00000
15 hdd 0.27299 osd.15 активен 1.00000 1.00000
16 hdd 0.27299 osd.16 активен 1.00000 1.00000
17 hdd 0.27299 osd.17 активен 1.00000 1.00000
18 hdd 0.27299 osd.18 активен 1.00000 1.00000
19 hdd 0.27299 osd.19 активен 1.00000 1.00000
-5 5.45599 хост ceph02-q
20 ssd 0.27299 osd.20 активен 1.00000 1.00000
21 ssd 0.27299 osd.21 активен 1.00000 1.00000
22 ssd 0.27299 osd.22 активен 1.00000 1.00000
23 ssd 0.27299 osd.23 активен 1.00000 1.00000
24 hdd 0.27299 osd.24 активен 1.00000 1.00000
25 hdd 0.27299 osd.25 активен 1.00000 1.00000
26 hdd 0.27299 osd.26 активен 1.00000 1.00000
27 hdd 0.27299 osd.27 активен 1.00000 1.00000
28 hdd 0.27299 osd.28 активен 1.00000 1.00000
29 hdd 0.27299 osd.29 активен 1.00000 1.00000
30 hdd 0.27299 osd.30 активен 1.00000 1.00000
31 hdd 0.27299 osd.31 активен 1.00000 1.00000
32 hdd 0.27299 osd.32 активен 1.00000 1.00000
33 hdd 0.27299 osd.33 активен 1.00000 1.00000
34 hdd 0.27299 osd.34 активен 1.00000 1.00000
35 hdd 0.27299 osd.35 активен 1.00000 1.00000
36 hdd 0.27299 osd.36 активен 1.00000 1.00000
37 hdd 0.27299 osd.37 активен 1.00000 1.00000
38 hdd 0.27299 osd.38 активен 1.00000 1.00000
39 hdd 0.27299 osd.39 активен 1.00000 1.00000
-7 6.08690 хост ceph03-q
40 ssd 0.27299 osd.40 активен 1.00000 1.00000
41 ssd 0.27299 osd.41 активен 1.00000 1.00000
42 ssd 0.27299 осд.42 активен 1.00000 1.00000
43 ssd 0.27299 osd.43 активен 1.00000 1.00000
44 hdd 0.27299 osd.44 активен 1.00000 1.00000
45 hdd 0.27299 osd.45 активен 1.00000 1.00000
46 hdd 0.27299 osd.46 активен 1.00000 1.00000
47 hdd 0.27299 osd.47 активен 1.00000 1.00000
48 hdd 0.27299 osd.48 активен 1.00000 1.00000
49 hdd 0.27299 osd.49 активен 1.00000 1.00000
50 hdd 0.27299 osd.50 активен 1.00000 1.00000
51 hdd 0.27299 osd.51 активен 1.00000 1.00000
52 hdd 0.27299 osd.52 активен 1.00000 1.00000
53 hdd 0.27299 osd.53 активен 1.00000 1.00000
54 hdd 0.27299 osd.54 активен 1.00000 1.00000
55 hdd 0.27299 osd.55 активен 1.00000 1.00000
56 hdd 0.27299 osd.56 активен 1.00000 1.00000
57 hdd 0.27299 osd.57 активен 1.00000 1.00000
58 hdd 0.27299 osd.58 активен 1.00000 1.00000
59 hdd 0.89999 osd.59 активен 1.00000 1.00000
Нека създадем наши виртуални стелажи и сървъри с блекджек и каквото и да е:
root@ceph01-q:~#ceph osd crush add-bucket rack01 root #създадохме нов root
root@ceph01-q:~#ceph osd crush add-bucket ceph01-q host #създадохме нов хост
root@ceph01-q:~#ceph osd crush move ceph01-q root=rack01 #преместихме сървъра в друг стелаж
root@ceph01-q:~#osd crush add 28 1.0 host=ceph02-q # Добавихме ОСД в сървъра
# Ако е създаден неправилно, може да бъде изтрит
root@ceph01-q:~# ceph osd crush remove osd.4
root@ceph01-q:~# ceph osd crush remove rack01Проблемите, с които се срещнахме в боевия кластер, при опит да създадем нов хост и да го преместим в съществуващ стелаж — командата ceph osd crush move ceph01-host root=rack01 замръзваше, а мониторите започваха да падат по един. Прекратяването на командата с CTRL+C връщаше кластерът в света на живите.
Търсенето показа такъв проблем:
Решението беше да изdumpнеш crushmap и да изтриеш секцията rule replicated_ruleset
root@ceph01-prod:~#ceph osd getcrushmap -o crushmap.row #Извеждаме картата в суров вид
root@ceph01-prod:~#crushtool -d crushmap.row -o crushmap.txt #превеждаме в четим формат
root@ceph01-prod:~#vim crushmap.txt #редактираме, като изтриваме правилото replicated_ruleset
root@ceph01-prod:~#crushtool -c crushmap.txt -o new_crushmap.row #компилираме обратно
root@ceph01-prod:~#ceph osd setcrushmap -i new_crushmap.row #зареждаме в кластераВнимание: тази операция може да предизвика ребаланс на placement group между OSD. При нас това се случи, но много малко.
Странността, с която се сблъскахме в тестовия клъстер, е, че след перезареждане на сървъра OSD забравяха, че са преместени в нови сървъри и щандове и се връщаха в root default.
В резултат, след като събрахме окончателната схема, в която създадохме отделно root за ssd дискове и отделно за шпинделни, разположихме всички OSD по стендовете и просто изтрихме default root. След перезареждане OSD останаха на местата си.
След като поразсъждавахме в документацията, открихме параметър, който отговаря за това поведение. За него втората част.
Как направихме различни групи по типове дискове.
За начало създадохме две root-a — за ssd и за hdd.
root@ceph01-q:~#ceph osd crush add-bucket ssd-root root
root@ceph01-q:~#ceph osd crush add-bucket hdd-root rootТъй като физически сървърите са разположени в различни щандове — за удобство създадохме щандове и в тях поставихме сървърите.
# Стойки:
root@ceph01-q:~#ceph osd crush add-bucket ssd-rack01 rack
root@ceph01-q:~#ceph osd crush add-bucket ssd-rack02 rack
root@ceph01-q:~#ceph osd crush add-bucket ssd-rack03 rack
root@ceph01-q:~#ceph osd crush add-bucket hdd-rack01 rack
root@ceph01-q:~#ceph osd crush add-bucket hdd-rack01 rack
root@ceph01-q:~#ceph osd crush add-bucket hdd-rack01 rack
# Сервера
root@ceph01-q:~#ceph osd crush add-bucket ssd-ceph01-q host
root@ceph01-q:~#ceph osd crush add-bucket ssd-ceph02-q host
root@ceph01-q:~#ceph osd crush add-bucket ssd-ceph03-q host
root@ceph01-q:~#ceph osd crush add-bucket hdd-ceph01-q host
root@ceph01-q:~#ceph osd crush add-bucket hdd-ceph02-q host
root@ceph01-q:~#ceph osd crush add-bucket hdd-ceph02-q hostи разпределихме дисковете по техните типове в различни сървъри.
root@ceph01-q:~# Дисковете от 0 до 3 са SSD, намират се в ceph01-q, поставяме ги в сървера
root@ceph01-q:~# ssd-ceph01-q
root@ceph01-q:~#ceph osd crush add 0 1 host=ssd-ceph01-q
root@ceph01-q:~#ceph osd crush add 1 1 host=ssd-ceph01-q
root@ceph01-q:~#ceph osd crush add 2 1 host=ssd-ceph01-q
root@ceph01-q:~#ceph osd crush add 3 1 host=ssd-ceph01-q
root-ceph01-q:~# аналогично с другите сървъриРазпределяйки дисковете по рутовете ssd-root и hdd-root, оставихме root-default празен, така че можем да го изтрием.
root-ceph01-q:~#ceph osd crush remove defaultСлед това трябва да създадем правила за разпределение, които ще свържем със създаваните пула — в правилата ще укажем в кои root можем да поставим данните на нашия пул и нивото на уникалност на репликата — например репликите трябва да бъдат задължително на различни сървъри или в различни щандове (може дори в различни root, ако имаме такова разпределение).
Преди да изберем типа, е добре да прочетем документацията:
root-ceph01-q:~#ceph osd crush rule create-simple rule-ssd ssd-root host firstn
root-ceph01-q:~#ceph osd crush rule create-simple rule-hdd hdd-root host firstn
root-ceph01-q:~# Указахме две правила, при които данните се реплицират
root-ceph01-q:~# между хостовете - т.е. репликата трябва да бъде на друг хост,
root-ceph01-q:~# дори и да са в един и същи шкаф
root-ceph01-q:~# В продукцията, ако е възможно, е по-добре да се разпределят хостовете
root-ceph01-q:~# по шкафове и да се укаже разпределение на репликите по шкафове:
root-ceph01-q:~# ##ceph osd crush rule create-simple rule-ssd ssd-root rack firstnИ създаваме пулове, в които искаме в бъдеще да съхраняваме образи на дискове за нашата виртуализация — PROXMOX:
root-ceph01-q:~# #ceph osd pool create {NAME} {pg_num} {pgp_num}
root-ceph01-q:~# ceph osd pool create ssd_pool 1024 1024
root-ceph01-q:~# ceph osd pool create hdd_pool 1024 1024И казваме на тези пулове какви правила за разпределение да използват.
root-ceph01-q:~#ceph osd crush rule ls # преглеждаме списъка с правила
root-ceph01-q:~#ceph osd crush rule dump rule-ssd | grep rule_id #избираме нужния ID
root-ceph01-q:~#ceph osd pool set ssd_pool crush_rule 2
К избор на брой плейсмент групи трябва да се подхожда с предварително имеюща визия за своя кластер — колко ОСД ще има там, какво количество данни (в проценти от общото количество) ще има в пула, какво количество данни общо.
Общо е желателно да не се имат повече от 300 плейсмент групи на диск, и ще бъде по-лесно да се балансират малки серии плейсмент групи — т.е. ако целият ваш пул е 10 Tb и в него има 10 PG — ще бъде трудно да се балансира с преминаване на терабайтни тухли (pg) — да прехвърлите пясък с малък размер на зърната в бидони е по-лесно и по-равномерно.
Но трябва да се помни, че колкото повече са PG, толкова повече ресурси се консумират за изчисляване на тяхното местоположение — започва да се използва памет и ЦПУ.
Приблизително разбиране може , предоставен от разработчиците на документация CEPH.
Списък с материали:
Източник: habr.com
