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

Задачата беше проста — имаше CEPH, който не работеше особено добре. Трябваше да направим „добре“.
Кластерът, който ми попадна, беше хетерогенен, настроен набързо и практически не тюнингован. Състоеше се от две групи различни нодове, с една обща мрежа, изпълняваща ролята както на кластерна, така и на публична мрежа. Нодовете бяха натъпкани с четири вида дискове — два типа SSD, събрани в две отделни правила за разположение и два типа HDD с различни размери, събрани в трета група. Проблемът с различните размери беше решен с различни тегла OSD.
Настройката беше разделена на две части — оптимизация на операционната система и оптимизация на самия CEPH и неговите настройки.
Оптимизиране на ОС
Мрежа
Високата латентност се отразяваше както при запис, така и при балансировка. При запис — защото клиентът не получава отговор за успешен запис, докато репликите на данните в други плейсмент групи не потвърдят успеха. Тъй като правилата за разпределение на репликите в CRUSH картата бяха по една реплика на хост, мрежата се използваше винаги.
Поради това, първо реших да направя леки настройки на текущата мрежа, като едновременно се опитвах да убедя да преминем на отделни мрежи.
За начало промених настройките на мрежовите карти. Започнах с настройка на опашките:
какво беше:
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 Мини: 0
RX Джumbo: 0
TX: 4096
Настройки на текущото оборудване:
RX: 256
RX Мини: 0
RX Джumbo: 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
# Увеличаване на максималния общ буфер, който може да бъде заделен
# измерва се в единици страници (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
# Съответно деактивиране на форвардинга. Ние не сме шлюз, докер на машините не е стартиран,
# не е необходимо.
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 пакета. В нашия случай е плацебо, просто
# изглежда красиво)Смрежа luster беше отделена на отделни 10Gbps мрежови интерфейси в отделна плоска мрежа. На всяка машина бяха поставени мрежови дводпортови карти mellanox 10/25 Gbps, включени в два отделни 10Gbps суича. Агрегацията беше осъществена с помощта на OSPF, тъй като бондингът с lacp по неизвестна причина показа максимална пропускателна способност от 16 Gbps, докато ospf успешно оползотвори напълно и двете десеторки на всяка машина. В бъдеще планирахме да използваме ROCE на тези mellanox, за да намалим латентността. Как настроихме тази част от мрежата:
- Тъй като самите машини имат външни айпишници на BGP, така че ни е необходим софтуер — (а по-точно, в момента на написването на статията това беше ) вече инсталирано.
- Общо на машините имаше две мрежови с по два интерфейса — общо 4 порта. Една мрежова карта с два порта гледаше към фабриката и на нея бе настроен BGP, а втората — с два порта гледаше в два различни свича и на нея бе насочен OSPF.
Повече за настройката на OSPF: Основната задача — агрегираните два линка и наличие на fault tolerance.
два мрежови интерфейса са настроени в две прости плоски мрежи — 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 daemon.
(Желаещите да се задълбочат в планировчика на входно-изходните операции могат да прочетат за него тук:
Предпочитащите да четат на български: )
В препоръките по настройката на линукса също се съветва да се увеличи nr_request
nr_requests
Стойността на nr_requests определя какъв брой I/O заявки ще се буферират, преди I/O планировчикът да изпрати/приеме данни към/от блоковото устройство. Ако използвате RAID карта/блоково устройство, което може да обработва по-голямо опашване от това, за което е настроен I/O планировчикът, увеличаването на стойността на nr_requests може да помогне за подобряване на производителността и да намали натоварването на сървъра при голямо количество I/O операции. Ако използвате Deadline или CFQ като планировчик, предлага се стойността на nr_requests да се зададе на 2 пъти стойността на дълбочината на опашката.
НО! Самите граждани-разработчици на CEPH ни убеждават, че системата им за приоритети работи по-добре.

WBThrottle и/или nr_requests
WBThrottle и/или nr_requests
Файловото хранилище използва буферирани операции за записи на I/O; това предоставя редица предимства, ако журналът на файловото хранилище е на по-бързо устройство. Клиентските заявки получават известия веднага щом данните бъдат записани в журнала, а след това се изхвърлят на самия диск с данни по-късно, използвайки стандартната функционалност на Linux. Това прави възможно за OSD шпинделни дискове да предлагат латентност на запис, подобна на SSD при малки пакетни записи. Тази отложена записна функция позволява самото ядро да реорганизира заявките за операции на I/O към диска, с надеждата или да ги консолидира, или да позволи на съществуващите глави на дисковете да изберат по-оптимален маршрут над своите пластини. Краен ефект на това е, че можете да извлечете леко повече операции за I/O от всеки диск, отколкото би било възможно при директни или синхронни операции за I/O.
Обаче, възниква определен проблем, ако обемът на идващите записи в този клъстер Ceph започне да надвишава възможностите на основните дискове. В такъв сценарий общият брой на операциите за I/O, чакащи запис на диска, може неконтролируемо да расте, което да доведе до опашки от заявки, запълващи целия диск и опашките на 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 определя максималния брой допустими
# едновременни заявки.
vm.min_free_kbytes=1048576
# Минималният размер на свободната памет, който трябва да се поддържа.
# Настроен е на 1GB, което е напълно достатъчно за работа на операционната система,
# и позволява да се избегне OOM Killer за процесите OSD. Въпреки че паметта
# е както на глупак хартия, запасът никога не е излишен.
vm.swappiness=10
# Казваме да се използва своп, ако остава свободни 10% от паметта.
# На машини с 128G оперативна памет и 10% е 12 GB. Повече от достатъчно за работа.
# Стандартният параметър от 60% караше системата да забавя,
# навлизайки в своп, когато има още много свободна памет.
vm.vfs_cache_pressure=1000
# Увеличаваме от стандартните 100. Караме ядрото да освобождава
# неизползваните страници памет от кеша по-активно.
vm.zone_reclaim_mode=0
# Позволява настройка на по-агресивен или по-малко агресивен
# подход за възстановяване на паметта, когато в зоната свършва паметта.
# Ако е настроен на нула, не се извършва възстановяване на зоната.
# За файлови сървъри или натоварвания,
# е печелившо, ако данните им са кеширани, zone_reclaim_mode
# е добре да остане изключен, тъй като ефектът от кеширането
# вероятно ще е по-важен от местоположението на данните.
vm.dirty_ratio=20
# Процент оперативна памет, който може да се запълни с "мръсни" страници.
# Изчислено от приблизителен разчет:
# В системата има 128 GB памет.
# Приблизително по 20 SSD диска, които в настройките на CEPH
# са указани да заделят по 3 GB оперативна памет за кеширане.
# Приблизително по 40 HDD диска, за които този параметър е 1 GB.
# 20% от 128 е 25.6 GB. В общи линии, при максимална натовареност на паметта,
# за системата ще останат 2.4 GB памет. Трябва да е достатъчно, за да оцелее и да изчака
# пристигането на кавалерия - тоест на DevOps, който ще оправи всичко.
vm.dirty_background_ratio=3
# Процент системна памет, която може да се запълни с мръсни страници, преди
# фоновите процеси 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
# Даже се опитахме да разкрием под това
# NVMe
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'
# голям обем RAM позволява
# да се съхраняват достатъчно големи обеми
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 дисковете пространството за тяхното
# журнала е същото устройство, което е и за ОСД
# решихме, че 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 отворен получен: (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 CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 14.54799 root default
-3 9.09200 host ceph01-q
0 ssd 1.00000 osd.0 up 1.00000 1.00000
1 ssd 1.00000 osd.1 up 1.00000 1.00000
2 ssd 1.00000 osd.2 up 1.00000 1.00000
3 ssd 1.00000 osd.3 up 1.00000 1.00000
4 hdd 1.00000 osd.4 up 1.00000 1.00000
5 hdd 0.27299 osd.5 up 1.00000 1.00000
6 hdd 0.27299 osd.6 up 1.00000 1.00000
7 hdd 0.27299 osd.7 up 1.00000 1.00000
8 hdd 0.27299 osd.8 up 1.00000 1.00000
9 hdd 0.27299 osd.9 up 1.00000 1.00000
10 hdd 0.27299 osd.10 up 1.00000 1.00000
11 hdd 0.27299 osd.11 up 1.00000 1.00000
12 hdd 0.27299 osd.12 up 1.00000 1.00000
13 hdd 0.27299 osd.13 up 1.00000 1.00000
14 hdd 0.27299 osd.14 up 1.00000 1.00000
15 hdd 0.27299 osd.15 up 1.00000 1.00000
16 hdd 0.27299 osd.16 up 1.00000 1.00000
17 hdd 0.27299 osd.17 up 1.00000 1.00000
18 hdd 0.27299 osd.18 up 1.00000 1.00000
19 hdd 0.27299 osd.19 up 1.00000 1.00000
-5 5.45599 host ceph02-q
20 ssd 0.27299 osd.20 up 1.00000 1.00000
21 ssd 0.27299 osd.21 up 1.00000 1.00000
22 ssd 0.27299 osd.22 up 1.00000 1.00000
23 ssd 0.27299 osd.23 up 1.00000 1.00000
24 hdd 0.27299 osd.24 up 1.00000 1.00000
25 hdd 0.27299 osd.25 up 1.00000 1.00000
26 hdd 0.27299 osd.26 up 1.00000 1.00000
27 hdd 0.27299 osd.27 up 1.00000 1.00000
28 hdd 0.27299 osd.28 up 1.00000 1.00000
29 hdd 0.27299 osd.29 up 1.00000 1.00000
30 hdd 0.27299 osd.30 up 1.00000 1.00000
31 hdd 0.27299 osd.31 up 1.00000 1.00000
32 hdd 0.27299 osd.32 up 1.00000 1.00000
33 hdd 0.27299 osd.33 up 1.00000 1.00000
34 hdd 0.27299 osd.34 up 1.00000 1.00000
35 hdd 0.27299 osd.35 up 1.00000 1.00000
36 hdd 0.27299 osd.36 up 1.00000 1.00000
37 hdd 0.27299 osd.37 up 1.00000 1.00000
38 hdd 0.27299 osd.38 up 1.00000 1.00000
39 hdd 0.27299 osd.39 up 1.00000 1.00000
-7 6.08690 host ceph03-q
40 ssd 0.27299 osd.40 up 1.00000 1.00000
41 ssd 0.27299 osd.41 up 1.00000 1.00000
42 ssd 0.27299 osd.42 up 1.00000 1.00000
43 ssd 0.27299 osd.43 up 1.00000 1.00000
44 hdd 0.27299 osd.44 up 1.00000 1.00000
45 hdd 0.27299 osd.45 up 1.00000 1.00000
46 hdd 0.27299 osd.46 up 1.00000 1.00000
47 hdd 0.27299 osd.47 up 1.00000 1.00000
48 hdd 0.27299 osd.48 up 1.00000 1.00000
49 hdd 0.27299 osd.49 up 1.00000 1.00000
50 hdd 0.27299 osd.50 up 1.00000 1.00000
51 hdd 0.27299 osd.51 up 1.00000 1.00000
52 hdd 0.27299 osd.52 up 1.00000 1.00000
53 hdd 0.27299 osd.53 up 1.00000 1.00000
54 hdd 0.27299 osd.54 up 1.00000 1.00000
55 hdd 0.27299 osd.55 up 1.00000 1.00000
56 hdd 0.27299 osd.56 up 1.00000 1.00000
57 hdd 0.27299 osd.57 up 1.00000 1.00000
58 hdd 0.27299 osd.58 up 1.00000 1.00000
59 hdd 0.89999 osd.59 up 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 възвръщаше клъстера в света на живите.
Търсенето показа такъв проблем:
Решението беше да се създаде дъмп на 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 #редактираме, като премахваме rule 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-а — за 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:~# аналогично с другите сървъри.Разпределяйки дисковете по root-овете 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
