Детектив в 1 части.
Эта история произошла в октябре.

Есть Ceph версии 0.94 (Hammer). 6 стораджей, 8 мониторов, по 6-8 osd на каждом сторадже, SSD диски объемом от 1 ТБ до 4 ТБ. Реплика — 2, минимум 1.

Как-то раз случилось такое: вечером прошел некий шторм по всему кластеру и самопроизвольно перезапустилось множество osd. В логах osd были видны стандартные для ceph ошибки вида no reply from osd.X. Немного slow requests и самопроизвольные рестарты, что для ceph не критическое событие и довольно частое. В общем, такое бывает. Но, к сожалению, не все перезапустившиеся osd смогли подняться. А именно пала героем osd.45 на storage6.

Мы решили, что это нестрашно, ведь это всего 1 из 50 osd, и пробовали запустить ее разными способами. Ну, знаете, umount/mount директории, flush и пересоздание журнала, вот это всё. В итоге, как обычно в таких ситуациях поступает любой админ, дело кончилось перезапуском всей ноды, так как из опыта известно, что systemd иногда немножко сходит с ума и не хочет корректно запускать нужные процессы. Или у osd перестает что-то работать, и без перезапуска сервера она не хочет запускаться.

И после перезапуска мы уже имели 4 мертвых osd, т.е. все на этом сторадже. Ошибки такие же, как и на первичной osd:

017-10-12 12:10:01.756562 7f02459af880  0 ceph version 0.94.10 (b1e0532418e4631af01acbc0cedd426f1905f4af), process ceph-osd, pid 2343
2017-10-12 12:10:01.767719 7f02459af880  0 filestore(/var/lib/ceph/osd/ceph-45) backend xfs (magic 0x58465342)
2017-10-12 12:10:01.769302 7f02459af880  0 genericfilestorebackend(/var/lib/ceph/osd/ceph-45) detect_features: FIEMAP ioctl is supported and appears to work
2017-10-12 12:10:01.769310 7f02459af880  0 genericfilestorebackend(/var/lib/ceph/osd/ceph-45) detect_features: FIEMAP ioctl is disabled via 'filestore fiemap' config option
2017-10-12 12:10:01.785177 7f02459af880  0 genericfilestorebackend(/var/lib/ceph/osd/ceph-45) detect_features: syncfs(2) syscall fully supported (by glibc and kernel)
2017-10-12 12:10:01.785229 7f02459af880  0 xfsfilestorebackend(/var/lib/ceph/osd/ceph-45) detect_feature: extsize is disabled by conf
2017-10-12 12:10:01.788289 7f02459af880  0 filestore(/var/lib/ceph/osd/ceph-45) mount: enabling WRITEAHEAD journal mode: checkpoint is not enabled
2017-10-12 12:10:01.790182 7f02459af880 -1 journal FileJournal::_open: disabling aio for non-block journal.  Use journal_force_aio to force use of aio anyway
2017-10-12 12:10:01.790184 7f02459af880  1 journal _open /var/lib/ceph/osd/ceph-45/journal fd 19: 10485760000 bytes, block size 4096 bytes, directio = 1, aio = 0
2017-10-12 12:10:01.790428 7f02459af880  1 journal _open /var/lib/ceph/osd/ceph-45/journal fd 19: 10485760000 bytes, block size 4096 bytes, directio = 1, aio = 0
2017-10-12 12:10:01.790923 7f02459af880  0 <cls> cls/hello/cls_hello.cc:271: loading cls_hello
2017-10-12 12:10:01.796251 7f02459af880  0 osd.45 19681 crush map has features 1107558400, adjusting msgr requires for clients
2017-10-12 12:10:01.796260 7f02459af880  0 osd.45 19681 crush map has features 1107558400 was 8705, adjusting msgr requires for mons
2017-10-12 12:10:01.796263 7f02459af880  0 osd.45 19681 crush map has features 1107558400, adjusting msgr requires for osds
2017-10-12 12:10:01.796273 7f02459af880  0 osd.45 19681 load_pgs
2017-10-12 12:10:01.850570 7f02459af880 -1 *** Caught signal (Aborted) **
 in thread 7f02459af880
 
 ceph version 0.94.10 (b1e0532418e4631af01acbc0cedd426f1905f4af)
 1: /usr/bin/ceph-osd() [0xb35f7d]
 2: (()+0x11390) [0x7f0244897390]
 3: (gsignal()+0x38) [0x7f0242c8f428]
 4: (abort()+0x16a) [0x7f0242c9102a]
 5: (__gnu_cxx::__verbose_terminate_handler()+0x16d) [0x7f02435d284d]
 6: (()+0x8d6b6) [0x7f02435d06b6]
 7: (()+0x8d701) [0x7f02435d0701]
 8: (()+0x8d919) [0x7f02435d0919]
 9: (object_info_t::decode(ceph::buffer::list::iterator&)+0xb7a) [0x7b47ba]
 10: (object_info_t::object_info_t(ceph::buffer::list&)+0x1b7) [0x78cd07]
 11: (PGLog::read_log(ObjectStore*, coll_t, coll_t, ghobject_t, pg_info_t const&, std::map<eversion_t, hobject_t, std::less<eversion_t>, std::allocator<std::pair<eversion_t const, hobject_t> > >&, PGLog::IndexedLog&, pg_missing_t&, std::__cxx11::basic_ostringstream<char, std::char_traits<char>, std::allocator<char> >&, std::set<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*)+0xf52) [0x784c82]
 12: (PG::read_state(ObjectStore*, ceph::buffer::list&)+0x24e) [0x81791e]
 13: (OSD::load_pgs()+0xbb6) [0x6b9eb6]
 14: (OSD::init()+0x137f) [0x6bdddf]
 15: (main()+0x2c20) [0x646310]
 16: (__libc_start_main()+0xf0) [0x7f0242c7a830]
 17: (_start()+0x29) [0x65c779]
 NOTE: a copy of the executable, or `objdump -rdS <executable>` is needed to interpret this.

Если стартовать osd напрямую через бинарь, а не через upstart или systemctl, то можно увидеть выбрасываемое исключение и немного побольше инфы (бинарь по дефолту пишет STDERR и STDOUT в консоль):

root@storage6:~# /usr/bin/ceph-osd -f --cluster ceph --id 45
starting osd.45 at :/0 osd_data /var/lib/ceph/osd/ceph-45 /var/lib/ceph/osd/ceph-45/journal
2017-10-12 15:13:45.288995 7fc5b1b06880 -1 osd.45 22551 log_to_monitors {default=true}
terminate called after throwing an instance of 'ceph::buffer::malformed_input'
  what():  buffer::malformed_input: __PRETTY_FUNCTION__ decode past end of struct encoding
*** Caught signal (Aborted) **
 in thread 7fc58e699700
terminate called recursively
Aborted (core dumped)

Здесь мы видим, что демон ругается на какие-то неправильные входные данные (malformed_input). Но что это за данные, пока непонятно. Ситуация осложняется тем, что в кластере появились unfound объекты:

recovery 3/3102030 unfound (0.000%)

Эти 4 незапускающиеся osd через таймаут были помечены мониторами как out. Началось восстановление и репликация данных, и в кластере появилось ни с того ни с сего 100 непроходящих slow requests. Так как Ceph используется Openstack'ом в качестве storage backend'а (не prod, но dev окружение) клиенты (команды разработки) это очень почувствовали и вся работа заметно замедлилась, так как виртуалки сильно тормозили.

В Ceph у нас два пула. Один для непосредственно дисков виртуалок — rbd1, второй — для образов, из которых создаются эти диски. Unfound объекты в данном случае критичны для обоих пулов, так как могут стать следствием неконсистентности данных. Но если в первом случае — все анфаунды в rbd1 — мы будем иметь максимум 3 фарша, то во втором случае — все анфаунды в images — мы потенциально имеем целый магазинчик фарша в связи с особенностями работы Openstack. Поэтому, так как мы в принципе были готовы потерять три машины, потому что опенстек — это не продакшн, требовалось проверить, к какому пулу относятся эти ненайденные объекты:

root@volume1:~# ceph pg 2.67 list_missing
{
    "offset": {
        "oid": "",
        "key": "",
        "snapid": 0,
        "hash": 0,
        "max": 0,
        "pool": -1,
        "namespace": ""
    },
    "num_missing": 3,
    "num_unfound": 3,
    "objects": [
        {
            "oid": {
                "oid": "rbd_data.8e53d86b8b4567.0000000000000220",
                "key": "",
                "snapid": -2,
                "hash": 2391933031,
                "max": 0,
                "pool": 2,
                "namespace": ""
            },
            "need": "19232'24922826",
            "have": "19172'24922749",
            "locations": []
        },
        {
            "oid": {
                "oid": "rbd_data.42375f55c840f3.000000000000c6d3",
                "key": "",
                "snapid": -2,
                "hash": 1598576743,
                "max": 0,
                "pool": 2,
                "namespace": ""
            },
            "need": "19229'24922824",
            "have": "19110'24922274",
            "locations": []
        },
        {
            "oid": {
                "oid": "rbd_data.b4b7816b8b4567.0000000000000298",
                "key": "",
                "snapid": -2,
                "hash": 2351466599,
                "max": 0,
                "pool": 2,
                "namespace": ""
            },
            "need": "19229'24922823",
            "have": "19110'24921517",
            "locations": []
        }
    ],
    "more": 0
}

Они все были на одной osd, в одной pg и в пуле номер 2. И… это пул rbd1, так что выдохнули. Если что, мы теряем всего три виртуалки, это не так страшно.

Удаляем одну из проблемных osd из кластера с помощью `ceph osd rm osd.45`. Анфаундов становится 28. Да что ж такое! Это уже проблема. Нужно любым способом попытаться восстановить неработающие osd, или нас ждет полный ресетап всех виртуалок в Openstack, а это, во-первых, сложно, а во-вторых, ужасно стыдно. В общем, мы врубили режим лютого дебага.

Итак, что у нас есть в данный момент?

— по кластеру прошла какая-то аномалия, заставившая часть osd перезапуститься;
— одна из них не смогла запуститься;
— после рестарта ее ноды не смогли запуститься оставшиеся osd;
— в кластере есть заблокированные запросы, все на одной osd (8ая);
— кластере есть unfound объекты (28 штук), все на той же самой osd (8ая);
— видимо, удаление из кластера остальных osd опять увеличит количество анфаундов, значит делать это не стоит;
— клиенты страдают, recovery периодически останавливается и приходится его триггерить перезапуском любой из работающих osd (кластер ceph иногда может залипать и переставать восстанавливаться. тогда нужно стриггерить восстановление событием: osd up->osd down->osd up).

Стрейсим запуск osd.45:

pidof `start ceph-osd id=45` | xargs strace -p 2> 45-strace.log

Видим, что osd спотыкается на чтении одного из участка локальных данных, после чего выбрасывается знакомое уже нам исключение ceph::buffer::malformed_input:

stat("/var/lib/ceph/osd/ceph-45/current/2.c_head", {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C", {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0", {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0", {st_mode=S_IFDIR|0755, st_size=24576, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0/DIR_D", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0/DIR_D/DIR_B", 0x7ffcccfdf330) = -1 ENOENT (No such file or directory)
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0/DIR_D/rbd\\udata.e1bde639901b63.0000000000000000__head_852BD00C__2", {st_mode=S_IFREG|0644, st_size=8388608, ...}) = 0
stat("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0/DIR_D/rbd\\udata.e1bde639901b63.0000000000000000__head_852BD00C__2", {st_mode=S_IFREG|0644, st_size=8388608, ...}) = 0
open("/var/lib/ceph/osd/ceph-45/current/2.c_head/DIR_C/DIR_0/DIR_0/DIR_D/rbd\\udata.e1bde639901b63.0000000000000000__head_852BD00C__2", O_RDWR) = 22
fgetxattr(22, "user.ceph._", 0x7ffcccfdf7c0, 100) = -1 ERANGE (Numerical result out of range)
fgetxattr(22, "user.ceph._", NULL, 0)   = 250
fgetxattr(22, "user.ceph._", "\17\10\r\1\0\0\4\3I\0\0\0\0\0\0\0(\0\0\0rbd_data.e1bde639901b63.0000000000000000\376\377\377\377\377\377\377\377\f\320+\205\0\0\0\0\0\2\0\0\0\0\0\0\0\6\3\34\0\0\0\2\0\0\0\0\0\0\0\377\377\377\377\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\0\0\0\0M\311\274\2\0\0\0\0\34K\0\0L\311\274\2\0\0\0\0\34K\0\0\2\2\25\0\0\0\10h\361\374\0\0\0\0\0\341\244\v\0\0\0\0\0\0\0\0\0\0\0\200\0\0\0\0\0\265?\336Y\256\270N\5\2\2\25\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0M\311\274\2\0\0\0\0\0\0\0", 250) = 250
futex(0x7f963ba19680, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, "terminate called after throwing "..., 48) = 48
write(2, "ceph::buffer::malformed_input", 29) = 29
write(2, "'\n", 2)                      = 2
write(2, "  what():  ", 11)             = 11
write(2, "buffer::malformed_input: __PRETT"..., 79) = 79
write(2, "\n", 1)                       = 1
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
tgkill(23708, 23708, SIGABRT)           = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=23708, si_uid=0} ---
write(2, "*** Caught signal (Aborted) **\n "..., 55) = 55
futex(0x7f963b802110, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, " ceph version 0.94.10 (b1e053241"..., 1418) = 1418
futex(0x48d40b4, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x48d40b0, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1}) = 1
futex(0x48d4030, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x48d4058, FUTEX_WAIT_PRIVATE, 2, NULL) = 0

Возможно, битый, неконсистентый объект e1bde639901b63.0000000000000000__head_852BD00C__2? Так как по стрейсу четко видно, что исключение выбрасывается после попытки обработать данный объект. Что ж, ищем его реплику на других стораджах:

find /mnt/osd? -name *e1bde639901b63.0000000000000000__head_852BD00C*

Находим его на storage5 у osd.37. Сверяем md5-сумму. Одинаковая. Ну, может xattr`ы отличаются? Аккуратно копируем rsync'ом объект с storage5 на storage6 с сохранением всей мета-информации. Бэкапим оригинальный файл и заменяем его скопированным. Пробуем запустить, но безрезультатно — всё то же самое. Но ведь там osd работает! Как же так?

Углубляемся в изучение исходного кода демонов и ищем, из-за чего он может валиться. Тут на этом этапе нам уже помогает C++ разработчик Азат, который знал о ceph, но никогда с ним не работал.
Понятно, что проблема в данных, извлекаемых при boot-процессе osd. Пробуем запускать другие, здоровые osd и стрейсим их, чтобы понять, как же они должны по-нормальному работать. Запускаем заболевшие osd через gdb и пытаемся в дебаг. Сравниваем процесс запуска.

Через несколько часов разработчик говорит, что понимает, в чем разница старта osd, и на каком участке кода она валится, но непонятна первопричина такого поведения. Говорит, что 37ая osd (с которой мы скопировали «валидный» объект) тогда тоже не должна работать. Предлагает ее перезапустить, чтобы доказать гипотезу. Мы в отказ. Мол, и так все плохо, а там вообще другая нода, как бы хуже не было от этого. Разработчик же говорит логичную вещь, что это все равно не дело, что оно там работает на соплях и в любой момент может упасть и не подняться, а так мы хоть докажем теорию и продвинемся дальше. Согласны. Рестартуем — не поднимается. Разработчику — счастье, нам — траур, так как анфаундов стало больше, а количество slow requests увеличилось до 800. Но что поделать. Понятно, что если при 100 медленных запросов клиенты хоть как-то могли работать, то при 800 всё окончательно встает колом.

Теперь у нас есть потенциально два полных стораджа, osd на которых висят на волоске и оставшиеся 3 запущенных osd на storage5 перезапуска не выдержат.

Начинаем сравнивать файловые системы и структуры файлов на здоровых osd, так как видим разницу в старте. Находим, что дело как будто бы кроется в xattr'ах и работе с ними. Для уточнения стрейсим здоровую osd:

pidof `start ceph-osd id=8` | awk {'print $1'} | xargs strace -fe open,fsetxattr -p  2>8-osd-xattr.strace

Много, конечно, не дает, но видим, что в нормальной и сломанной osd по-разному происходят запросы при запуске. Одни с префиксами, другие без. Разработчик начал смотреть вообще все места, где xattr генерились и\или читались, и там было видно, что такие xattr и должны генериться, но почему-то при чтении была ошибка. Как раз этот момент, почему так, и был непонятен. А потом мы смотрим в git upstream и видим, что добавили это относительно недавно.

Вот этот патч, который должен помочь корректно пройти процесс запуска и чтения файловой системы. Разработчик предлагает обновить Ceph и попробовать запуститься на нем. И между делом он невзначай говорит скорее в шутку: "Слушайте, ребят, а вы случайно не ставили тут никогда 10-й ceph?" И смеется. И один админ отвечает: "Да, случайно ставили, потом паппет переустановил нужную версию". Секунда тишины. И все начинают ржать.

А дело было вот в чем: storage[56] наливались самыми последними, в момент их сетапа из отдельного окружения были некорректно указаны apt pins, из-за чего поставилась дефолтная версия Ceph из убунтовских реп. Паппет прикатил ее, накатил osd, запустил их, они начали работать. Спустя сутки админ заметил, что версия ceph неправильная, внес изменения, установил верную, перезапустил (!!!) osd (не переналивая) и ушел курить бамбук. Спустя две недели произошел непонятный катаклизм, описанный в самом начале, из-за чего произошло нечто, и одна osd не поднялась.

Разработчик еще в середине пути смотрел на файловые структуры и не понимал, почему они такие странные, и списывал на возможные коррапты данных. Оказалось, что ребята из Ceph в 10-й версии (Jewel) изменили способ хранения и представления xattr'ов. Дело в том, что они раньше хранили все значения xattr'ов inline, но это было неоптимально и имело ограничение по длине. Соответственно, в 10-й версии они изменили структуру хранения и стали хранить их блоками, разбив на несколько частей. Osd инициализировалась на 10-й версии и проработала так сутки, создав объекты «по-новому», потом ее даунгрейдили, и она так проработала еще 2 недели. Почему она запустилась после даунгрейда — непонятно. Возможно, никогда не доходила до этих данных. Но в нашем случае она натыкалась на эти xattr'ы и не могла их переварить, выбрасывая исключение malformed_input.

Мы, конечно же, тут же установили на storage[56] Jewel версии Ceph'а, и все osd как миленькие запустились. Анфаунды ушли, заблокированные запросы тоже исчезли. Ceph начал восстанавливаться. Мы уже были почти уверены, что потеряем весь опенстек. И вот как получилось затащить. Конечно, большое спасибо разработчику, он очень помог.

Такая вот история. Через пару часов после возникновения проблемы один админ сказал, что узнал исключение (mailformed input), выбрасываемое демоном, и пошел смотреть в код, а там всего (!) 23 места, где оно может быть выброшено. Я посмеялся и сказал, что это много и неправильный подход, так как мы все равно не будем пересобирать сeph. В тот момент для меня это было дико, а масштаб проблемы позволял спокойно копаться в ceph, пробуя различные варианты. Но когда в конце этого дня я понял, что лучшего выхода нет, это показалось мне неплохим шансом, который нужно было использовать.

И в итоге подход «а давайте смотреть в сырцы приложения, чтобы понимать, что происходит и что происходит не так» оказался очень эффективным, а я был не прав.

Комментарии (13)


  1. ildarz
    19.04.2018 16:43

    в итоге подход «а давайте смотреть в сырцы приложения, чтобы понимать, что происходит и что происходит не так» оказался очень эффективным, а я был не прав.

    Разве? По-моему, в итоге в данном случае эффективным оказался подход "а давайте-ка вспомним, что мы вообще с этой штукой делали". Вспомнили, что ставили другую версию, поняли, что изменения связаны именно с этим, обновили версию, всё взлетело. А вспомнили бы сразу (или документировали бы все работы, чтобы можно было посмотреть историю) — все эти приключения были бы не нужны.


    1. nikitashalnov Автор
      19.04.2018 17:09

      Дело в том, что именно такой подход и помог вспомнить. Конечно, пытались сначала проверить, что изменялось за последние N дней. И логи паппета смотрели, и dpkg.log, syslog и так далее. Что ставилась неправильная версия ceph, знал лишь один человек, который в этой ситуации не связал это падение с тем случаем и вспомнил, когда ему задали конкретный вопрос.

      Документировать все работы, наверное, возможно только если вы либо очень маленькая компания или очень большая, в которой это просто жизненная необходимость. В моем идеальном мире все документируется и каждый чих где-то записывается, но не мной :) Но вряд ли этот идеальный мир когда-то настанет


      1. Naves
        19.04.2018 17:48

        А разве нельзя просто записывать все команды операторов на серверах и отправлять их в центр?


        1. nikitashalnov Автор
          19.04.2018 18:00
          +1

          Можно, но это никак не покроет кейс тотального контроля, чтобы все документировать.
          Честно, я не вижу в этом необходимости в средней компании. Наверное, если у вас хостинг-компания с большим количеством инженеров без разграничений прав (что вряд ли), тогда в этом есть смысл (собирать все действия операторов с серверов), чтобы потом разбираться, кто что натворил. Да и то, чтобы не наказать, наверное, а чтобы научить и показать, как надо делать. Но это зависит уже от компании.


  1. ybonar
    19.04.2018 18:50
    +1

    Ой, как это у вас все сложно получилось…

    Меня убила Ваша фраза «В общем, такое бывает.» Я не знаю как ведут себя небольшие кластеры до 300 сотен OSD но в штатной работе на продуктивном кластере количество таких проблем как Вы описали стремится к 1-2 в год!

    Даже во время штатного расширения хранилища мы очень редко ловим такие проблемы все работает штатно как и положено.

    Работаем начиная с hammer сейчас у нас кластеры на jewel готовимся к миграции Luminous.

    А так спасибо конечно за то что поделились своим опытом)


    1. nikitashalnov Автор
      19.04.2018 19:29
      +1

      Блин, круто) Мне не приходилось работать с таким количестовм osd, максимум имел дело с около 100. Сейчас уже почти с ceph не работаю, но воспоминания еще достаточно свежи, что это чудо нужно постоянно дебажить и изучать, почему все идет не так, как надо. Я тогда работал с самым новым Jewel, и в кластере периодически происходило так, что osd выключались рандомно и перезапукались systemd. Чего только с ceph не происходило, я ловил множество непонятных ситуаций, когда приходилось придумывать какие-то воркэраунды или мириться с таким поведением и придумывать хитрости. Расскажу про пару вещей:
      — Стораджи с 20 osd на борту. Сервер завис, нужно рестартить. После рестарта поднимается лишь часть osd. Остальные юниты failed в systemd. Ну, наверное, что-то при загрузке не так пошло. Потом нужно по какой-то причине проверить, как рестартятся osd. Делаешь systemctl restart ceph-osd.target. Все osd выключаются, стартуют все, а в CRUSH показаны многие osd на ноде как down, хотя процессы запущены. Что за чудеса? В итоге выяснили экспериментальным путем, что при одновременном старте osd у этих самых osd начинается что-то типа race condition за то, чтобы занять порты из выделенных им диапазона, и дальше что-то идет не так, и некоторые osd некорректно регистрируются в кластере. Пришлось писать обвязку, которая стартовала osd с задержкой (sleep) на определенное количество времени в зависимости от их id.
      — Другой случай вообще классический. Я частично описал его в статье. В кластере появились slow requests. Анализируешь ситуацию, видишь, что все реквесты на одной osd. Смотришь ceph osd tree, все osd UP и IN. Идешь на ноду к этой osd, а она не запущена! Понятно, почему slow requests копятся. И непонятно, почему все osd рядом, которые должны ее пинговать, не зарепортили монитору, что она down, и он ее не пометил должным образом?
      — У ceph есть официальный ansible-playbook для создания кластера, деплоя мониторов, osd и т.д. Мы им пользовались для начальной наливки кластера и потом временами, когда надо было диск заменить в сервере и засетапить нового демона osd. Но было замечено, что часто, но не всегда, в кластере после прохождения по нему плейбуком образовывалось слишком много degraded и misplaced объектов, больше, чем нужно. Жить особо не мешало, просто увеличивало время recovery. Но периодичеcки появлялись slow requests, и это стало затрагивать прод. Оказалось, что этот плейбук проходился по папкам /var/lib/ceph/*, выуживал оттуда id osd и считал, что именно они и должны быть запущены на данной ноде. Но ведь, когда диск вылетает (или вылетело два диска на разных нодах), ты наливаешь osd на новый диск и он получает минимально возможный номер в кластере, т.е. вылетевший osd.17 на z ноде, может быть потом налит на x ноде, а на z ноде останется пустая папка под 17 osd, в которую раньше монтировался диск. Поэтому ceph наливал на неиспользованном диске osd (если мог) и запускал 17й osd снова на z ноде, из-за этого менялась crush map, на x ноде валидный osd.17 делал out из кластера, потому что новая регистрация пришла с z ноды и оверрайтнула предыдущую карту. Пришлось писать мониторинг пустых папок в этой директории и оперативно их удалять :) И хорошо, если диск нормальный, а если диск битый или готовый развалиться, а его не успели еще поменять. Вот тогда будет много слоу реквестов.
      В общем, приходилось много не спать, читать мануалы и немногочисленные, к сожалению, форумы и почтовую рассылку. Даже в багтрекер Ceph тикет когда-о создавал.
      Так что, на моей памяти ceph — отличный продукт и клевой идеей и реализацией, но очень нестабильный. Возможно, были еще какие-то факторы, влияющие на стабильность кластеров, или это просто моя корма и везение, кто знает)


  1. iPrime
    19.04.2018 21:59
    +1

    8 мониторов на 6 хостов? Не ошибка ли? И Реплика — 2, минимум 1 прям фейспалм…


    1. nikitashalnov Автор
      19.04.2018 22:55

      8 мониторов — так исторически сложилось, что мониторами являются несколько compute нод опенстека и несколько стораджей. Когда-то так сделали, ну и ладно с ним.
      Реплика 2 для dev окружения… что вам не нравится? Enterprise SSD диски с тройной репликой да не на проде — это больно уж круто. Диски надежные, пашут исправно, вылетают очень редко, а в подобной ситуации так я вообще не уверен, что реплика 3 вас спасла бы


  1. Naves
    19.04.2018 23:55

    4 года назад пытался запустить cephFS. Три старых сервера с ОЗУ 4Гб, разные диски объемом от 1Тб до 4Тб, в сумме чуть меньше 30Тб, реплика 2/1 для теста. После заливки 10Тб скорость записи упала до 100Кб/с. Начали расти slow requests, запись упала в ноль, после чего стали выпадать osd по 4Тб из-за нехватки оперативной памяти. Кластер начал перераспределять данные по оставшимся, которые так же стали останавливаться, в итоге все стало в каком-то режиме, где записанных данных было больше, чем емкость рабочих osd. Память (FB-DIMM DDR2) на тот момент докупить не могли, а диски уже были. Так красивая идея разбилась о суровую реальность.


    1. kataklysm
      20.04.2018 09:28

      4 года назад пытался запустить cephFS.

      Да он до сих пор не имеет статус production, хотя и stable :). Для CephFS узким местом в первую очередь является MDS.


  1. vasilisc
    20.04.2018 08:28

    Вам бы желательно выйти на нечётное количество мониторов… официальные рекомендации словно приказ, если хотите избегать каких-либо проблем.
    docs.ceph.com/docs/master/rados/operations/add-or-rm-mons


    1. nikitashalnov Автор
      20.04.2018 08:50

      Спасибо за совет, да, я видел эти рекомендации. Сейчас мониторов 5, но есть у меня предположение, что при числе мониторов, стремящихся от 0 к бесконечности, нечетность их количества не играет особой сути, и эта дока имеет ввиду: «Чуваки, не делайте 2 монитора, потому что это сплит брейн. 3 хорошо.»

      It is advisable to run an odd-number of monitors but not mandatory. An odd-number of monitors has a higher resiliency to failures than an even-number of monitors. For instance, on a 2 monitor deployment, no failures can be tolerated in order to maintain a quorum; with 3 monitors, one failure can be tolerated; in a 4 monitor deployment, one failure can be tolerated; with 5 monitors, two failures can be tolerated. This is why an odd-number is advisable.
      То есть в случае с 8 мониторами, 8й монитор ни к селу, ни к городу, так как не увеличивает resiliency кластера) Но это не критично


  1. kataklysm
    20.04.2018 09:25

    Есть Ceph версии 0.94 (Hammer). 6 стораджей, 8 мониторов, по 6-8 osd на каждом сторадже, SSD диски объемом от 1 ТБ до 4 ТБ. Реплика — 2, минимум 1.

    Зачем 8? Три монитора способны обрабатывать под 1к OSD без каких либо проблем.
    Две реплики для dev самое оно, для prod — это выстрел в ногу. И дело не только в количестве реплик и их данных, но и в консенсусе при сбоях/ошибках объектов в rados. Я уверен на 99 %, что при size=3, у вас бы не было данной проблемы.

    Немного slow requests и самопроизвольные рестарты, что для ceph не критическое событие и довольно частое.

    Для ceph нет, а для клиентов к сожалению бывает критично, т.к. вызывает блокировку блоков на VM клиента.

    вечером прошел некий шторм по всему кластеру и самопроизвольно перезапустилось множество osd

    Вам нужно крутить параметры памяти и лимиты в ОС

    В общем, такое бывает.

    Не должно быть!

    в таких ситуациях поступает любой админ, дело кончилось перезапуском всей ноды… Или у osd перестает что-то работать, и без перезапуска сервера она не хочет запускаться.

    Так делают только Windows-админы(без обид), с Linux'ами лучше проблемы решать до перезагрузки. 90% проблем решается с чтением логов и принятие необходимых решений.

    Спустя сутки админ заметил, что версия ceph неправильная, внес изменения, установил верную, перезапустил (!!!) osd (не переналивая) и ушел курить бамбук.

    facepalm :). Вообщем я дальше читать не стал :)

    P.S. А за опыт и его описание Спасибо, жаль что кармы нет плюсануть…