Привет, Хабр! У этой статьи два автора – Василий Меньшаков и Алексей Кузнецов. Мы системные архитекторы развития платформы больших данных в X5 Tech. Решили поделиться своим опытом построения нового хранилища резервных копий для Greenplum. Какие были проблемы у предыдущего решения? Почему мы выбрали Ceph? Какой способ интеграции лучше? С какими проблемами мы сталкивались при внедрении этого инструмента? Что мы настраивали? Читайте подробности в нашей статье.
В инфраструктуре X5 Tech есть несколько кластеров Greenplum, среди которых и проект, представляющий собой корпоративное хранилище данных. В нём хранится свыше 220ТБ данных в 50+ тысячах таблиц, к которым ежедневно обращаются сотни пользователей (аналитики, менеджеры, разработчики и т. д.). Такая большая и важная система нуждается в регулярном обслуживании и резервном копировании для обеспечения заявленных показателей доступности.
Именно здесь мы столкнулись с тем, что имеющееся резервное копирование в HDFS (так исторически сложилось) всё меньше подходит для решения такой задачи (в определённое время мы достигли ситуации, когда стабильность решения стала недопустимо низкой). Размещая такие массивы данных в HDFS, приходилось встречать следующие проблемы:
большое число файлов в бэкапах негативно сказываются на производительности нейм-ноды, приходилось подкручивать размер Heap, но это не особо помогало;
желая сократить число файлов, была внедрена асинхронная .har-архивация старых резервных копий. И если процесс архивации просто долгий (часы), то процесс разархивации был очень долгим (сутки). Это делало процесс извлечения объектов из старых резервных копий слишком долгим (например, когда приходит задача восстановить удалённую на прошлой неделе таблицу);
падение бэкапов при переключении неймноды (особенность Hadoop-2 без федерации);
дата-ноды в кластере Hadoop могли входить в состояние stale как от самого процесса резервного копирования Greenplum, так и от других задач на кластере, что также периодически приводило к сбоям процессов резервного копирования;
для интеграции с HDFS используется коннектор hadoop-hdfs-fuse, который трудно дебажить (можно сказать, что бесполезно). Поэтому, когда зависали/падали бэкапы, точную причину проблемы назвать было практически невозможно (input-output error и всё на этом);
усложнение скриптов резервного копирования, чтобы они включали в себя монтирование, проверки корректности монтирования и последующее отмонтирование HDFS;
время снятия большой резервной копии было очень долгим (10-12 часов), что не только ограничивало работу пользователей (доступ закрывается на время бэкапа), но также и снижает саму вероятность успеха процесса резервного копирования;
мешали задачам Hadoop-кластера, ровно как и пользовательские расчёты на кластере Hadoop могли мешать бэкапам.
Так и родилась задача по поиску и внедрению нового инструмента для хранения резервных копий. Мы не рассчитывали на энтерпрайз-хранилища, также нам уже нужно было уйти от HDFS в пользу чего-то другого. И наш выбор пал на Ceph.
Почему Ceph?
Вначале нужно было определиться с направлением, в котором будем дальше двигаться:
Строить ещё один HDFS только для бэкапов;
Пойти в сторону энтерпрайз-хранилищ данных;
Развивать имеющийся небольшой кластер Ceph;
Внедрить какую-то другую распределённую файловую систему.
Строить ещё один HDFS не имело смысла, так как это не решало обозначенных выше проблем технологии HDFS + FUSE. Поэтому мы сразу отмели этот вариант. Бюджетная оценка использования СХД от Dell или HP выходила слишком высокой, при этом такие решения имеют ограничения по масштабированию: можно проводить вертикальное масштабирование, но если упереться в пропускную способность, то быстрее работать не станет.
Можно было пойти и в сторону внедрения какой-то новой для нас распределённой файловой системы, но было решено дать шанс технологии Ceph, ведь у нас уже имелся Ceph S3 в качестве хранилища для пользователей, поэтому был некоторый опыт работы с этим решением, и оно уже приличное время эксплуатировалось в компании. С этого момента можно отсчитывать историю появления Ceph в компании как хранилища для резервных копий Greenplum (и не только).
Важное достоинство – отсутствие проблем при хранении большого числа объектов (и чем больше сегментов в кластере, тем больше и число объектов в бэкапе из-за распределения данных по всем сегментам кластера), фигурировало с самого начала как основная фишка данной технологии. К тому же, хотелось избегать в будущем хранилище бэкапов и других проблем, которые касались HDFS, а Ceph "на берегу" выглядел гораздо более подходящим для решения данной задачи решением.
Забегая вперёд, скажем, что так оно и вышло – большинство проблем были устранены просто заменой технологии. Также ещё одним плюсом во внедрении Ceph является возможность использовать S3 и RBD – и мы этим активно пользуемся. Помимо этого, очень полезно иметь возможность разграничивать нагрузку во время резервного копирования. И в Ceph это реализуется посредством CRUSH Maps (подробнее об этом будет позже).
Полезным свойством технологии также является возможность включения Erasure Coding, которое позволяет снизить стоимость хранения информации (кстати, эта функциональность есть и в HDFS 3.x). А это очень актуально при больших объёмах данных. Про то, почему мы используем Erasure Coding, будет рассказано далее.
Как внедряли
Подкрепить идею было решено путём практических экспериментов. Для пилотирования технологии был создан первый отдельный кластер Ceph, который состоял всего из трёх нод (ноды с OSD находились на одном сервере вместе с Monitor, MDS и т. д.). На этом этапе мы просто тестировали Ceph в нашей инфраструктуре как технологию, учились его разворачивать и провели первые опыты по резервному копированию в CephFS.
В качестве кластера Greenplum выступал свежесобранный стенд с ADB 6.9.1 без нагрузки на 20 сегмент-нод (4 primary на ноду) с SAS SSD на борту (RAID 10 из 20 дисков), сеть в bond 2x10 Gbps, то есть пропускная способность довольно высокая. И первые же результаты нас поразили: скорость резервного копирования такого решения на БД размером 1,2 ТБ оказалось сопоставимой с HDFS! А на тот момент в кластере HDFS было 225 дата-нод, а в Ceph – всего 3. Поняв, что узким местом при работе с Ceph является сеть, было решено уменьшить размер резервной копии путём её сжатия, что дало во время пилотного запуска следующие результаты:
![](https://habrastorage.org/getpro/habr/upload_files/186/e22/8ea/186e228ea2742f261825b4c4f329b7d6.png)
Таких впечатляющих результатов уже было достаточно для того, чтобы убедиться в верности выбранного пути и продолжить исследования. На тот момент мы ещё не вдавались в подробности различных способов интеграции с Greenplum и использовали mount.ceph. А как оказалось, способов несколько.
Выбираем способ интеграции
Итак, был собран первый кластер Ceph (тот самый, из трёх нод). Теперь нужно было принять решение, а каким именно образом обеспечивать его интеграцию с Greenplum. Существуют три способа это сделать:
На первый взгляд, первый способ кажется самым предпочтительным, так как для его настройки нужно всего лишь разместить один конфигурационный файл на мастер-ноде и запустить процесс резервного копирования командой вида (сам плагин уже есть в поставке ADB):
gpbackup --dbname test --plugin-config /home/gpadmin/s3-test-config.yaml
Второй способ (монтирование на уровне ядра) считается нативным для интеграции с Ceph, но требует установки дополнительного ПО на каждый из хостов кластера Greenplum, а также управления монтированием (которое доступно только привилегированному пользователю операционной системы). Третий способ является альтернативой второму, но изначально считается менее производительным. И мы проверили все из них.
Начали с тестирования между mount.ceph и ceph-fuse, чтобы сразу выбрать оптимальный вариант из этой пары. Здесь из рассмотрения был исключён коннектор ceph-fuse, так как он: во-первых, не захотел корректно монтироваться без прав суперпользователя, как это делает hdfs-fuse (что не добавляет ему очков по сравнению с mount.ceph), а во-вторых, работает медленнее конкурента. К моменту проведения испытаний у нас уже не было в доступе исходного 20-нодового кластера, вместо этого мы проводили тестирование на dev-стенде ADB 6.13 (8 сегмент-нод, по 3 primary на ноду, диски SAS HDD 10К RAID 10 из 20 дисков) и мы получили следующие результаты при резервировании БД размером 1,3 ТБ (~4,5 тысячи объектов):
![](https://habrastorage.org/getpro/habr/upload_files/799/641/391/799641391ded14fa46d0a187a05ceaf2.png)
Сам gpbackup запускался командой вида:
gpbackup --dbname test_db --backup-dir /catalog1/ceph/gp_backup/test_db --jobs 10 --compression-level=5 --leaf-partition-data
Собственно, из-за разницы в скорости почти в два раза вариант использования ceph-fuse дальше и не рассматривался.
Параллельно шли попытки запустить резервное копирование через S3 (здесь и далее будет идти речь про реализацию S3 в Ceph). Нам пришлось снизить число jobs до 4, backup_max_concurrent_requests до 500 и backup_multipart_chunksize_mb до 10, чтобы перестать ловить ошибки и получить положительный результат: эта же БД снялась за 1:27:46. Это и стало отправной точкой появления сомнений в производительности S3-решения, которое тогда решили "положить на полку". Тем более, что сразу был виден масштаб предстоящих доработок:
В S3 нет классических каталогов файловой системы, там бакеты. А это потребует переделывания скриптов ротации резервных копий;
Подобрать подходящее значение jobs под S3 для обеспечения стабильной работы (это число будет ниже, чем при работе с HDFS или mount.ceph).
Тем временем, у нас строился новый кластер (5 сегмент-нод, по 16 primary на ноду, диски SAS HDD 10К RAID 10 из 20 дисков) под отдельный проект и там сразу планировалось применять решение с резервным копированием в Ceph. На нём мы ещё раз протестировали коннектор к S3 и mount.ceph. Полученные замеры показали (таблицы 1 и 2), что скорость второго решения заметно выше и его стабильность не зависит от размера резервной копии.
Начали с небольшой БД в стандартные 10 потоков:
gpbackup --dbname db1 --backup-dir /catalog1/ceph/gp_backup/db1 --jobs 10 --compression-level=5 --leaf-partition-data
Таблица 1. Время снятия резервной копии db1 (2.3 TB, ~5000 объектов)
Технология | Время |
HDFS | 1:15:00 |
S3 | 1:15:00 |
Mount | 0:59:00 |
С большой БД число потоков уже было увеличено до 15:
gpbackup --dbname db2 --backup-dir /catalog1/ceph/gp_backup/db2 --jobs 15 --compression-level=5 --leaf-partition-data
Таблица 2. Время снятия резервной копии db2 (9.8 TB, ~800 объектов)
Технология | Время |
HDFS | 3:58:00 |
S3 | Ни разу не снялось |
Mount | 4:21:00 |
Таким образом, скорость работы через gpbackup_s3_plugin не была быстрее mount.ceph, к тому же на БД "побольше" мы так и не получили успешных результатов (процесс gpbackup падал даже при заниженных значениях jobs). На этом было решено закончить пытаться настроить интеграцию Greenplum с CephS3, поскольку решение с монтированием работало и быстрее, и стабильнее.
Сравнивая эти реализации уже на практике, были получены такие выводы:
У монтирования раздела (CephFS) следующие преимущества по сравнению с HDFS:
Решается "проблема" с Kerberos (у нас керберизованный кластер Hadoop, поэтому для работы с HDFS нужно использовать keytab, который нужно регулярно обновлять: если не делать этого, то спустя 8 часов работы полученное разрешение на доступ станет невалидным и процесс бэкапирования упадёт с ошибкой Permission Denied);
Разгружается кластер Hadoop;
Есть возможность отказаться от технологии FUSE при монтировании;
Более удобное администрирование данных внутри CephFS (нативные команды операционной системы вместо использования клиента hdfs dfs).
У монтирования раздела (CephFS) следующие преимущества, по сравнению с S3:
Не нужны дополнительные балансировщики и шлюзы (Rados Gateway);
Не будет происходить OOM gpbackup-процесса, если понадобится увеличить количество исполняемых заданий или уровень сжатия архивов;
Более плавное использование сетевых интерфейсов, без просадок (так как каждый сегмент Greenplum при использовании CephFS соединяется напрямую с отдельными OSD, а не через шлюзы Rados Gateway). Схематично это выглядит так:
Легче администрировать и искать ошибки;
Более удобное администрирование данных внутри CephFS (нативные команды операционной системы вместо использования клиента s3cmd);
Легче масштабируется (увеличение количества OSD повышает производительность решения).
Таким образом, было решено использовать mount.ceph в качестве способа соединения с CephFS. Но, в целом, S3-плагин (после настройки) неплохо работает для резервного копирования БД небольших размеров, так что его тоже можно использовать, если объёмы данных не слишком большие.
Внедрение решения и его настройка
Так как у нас уже был кластер Ceph (3 ноды), мы решили не создавать новый производственный кластер, а переделать существующий. Что мы и сделали: вынесли на отдельные физические сервера мониторы и MDS, а RGW перенесли на vm и настроили через наш балансировщик (он у нас как отдельный сервис), MGR также перенесли на vm. По железу получилось следующее:
3 сервера Monitor – железные сервера;
2 сервере MDS – железные сервера;
3 сервера RGW – vm;
2 сервера MGR – vm;
21 сервер OSD – железные сервера с 10 или 12 OSD.
Ввиду того, что во время настройки и самых первых испытаний мы полагались на положительный опыт, который получили как на тестовых наборах данных, так и на не очень больших базах (1-2Тб), то ожидалось, что простая смена технологии не должна была заметно ухудшить имеющиеся показатели скорости. Однако, на деле всё оказалось не так просто.
Первые прогоны сценария резервного копирования на корпоративном хранилище данных показали не самые выдающиеся результаты (см. таблицу 3), однако решение показало себя стабильным, чего мы и добивались в первую очередь. Отметим, что так как система Greenplum находится в производственной эксплуатации, то и размер данных в ней постоянно варьируется. Но тем и интереснее полученные результаты, ведь среди них скрыт и ещё один важный момент на пути к успешному решению задачи – это командная работа, в том числе и со стороны разработчиков хранилища. Здесь это проявляется в том, что была проведена оптимизация, в рамках которой размер данных был сокращён на 8%.
Таблица 3. Первые опытные результаты
Хранилище | Размер резервной копии | Время бэкапирования |
HDFS | 232 Tb | 8:47:28 |
Ceph | 239 Tb | 15:12:45 |
Ceph | 243 Tb | 11:11:20 |
Ceph | 225 Tb | 10:15:42 |
Ceph | 226 Tb | 10:15:03 |
Получив самый первый результат в 15 часов (вместо ожидаемых хотя бы 9 часов), было понятно, что необходим тюнинг системы. Поэтому были сделаны следующие шаги:
Увеличение самого кластера Ceph, добавление нод с OSD.
Было добавлено 6 новых серверов с OSD, что ускорило процесс резервирования на 4 часа;
Разделение CRUSH Map (чтобы исключить влияние бэкапов для других пользователей).
Как говорилось ранее, кластер Ceph у нас используется не только для бэкапов, так что нам важно было разнести нагрузки, особенно после случая, когда запущенный нами бекап аффектил на другую нашу команду, которая пользовалась S3. Происходило это из-за того, что диски были полностью утилизированы бэкапом, а их пул жил на этих же дисках. Решение простое – это настраивать CRUSH Map. Но так как новые сервера (18 шт.) не одновременно вводились в кластер, то чаcть OSD от разных root была на одном сервере. Вот пример того, что у нас получилось:
-702 1478.79785 root backup
-300 50.93900 host <host>-01-backup
40 hdd 7.27699 osd.40 up 1.00000 1.00000
41 hdd 7.27699 osd.41 up 1.00000 1.00000
42 hdd 7.27699 osd.42 up 1.00000 1.00000
43 hdd 7.27699 osd.43 up 1.00000 1.00000
44 hdd 7.27699 osd.44 up 1.00000 1.00000
45 hdd 7.27699 osd.45 up 1.00000 1.00000
46 hdd 7.27699 osd.46 up 1.00000 1.00000
47 hdd 7.27699 osd.47 up 1.00000 1.00000
-304 58.21599 host <host>-02-backup
62 hdd 7.27699 osd.62 up 1.00000 1.00000
65 hdd 7.27699 osd.65 up 1.00000 1.00000
68 hdd 7.27699 osd.68 up 1.00000 1.00000
71 hdd 7.27699 osd.71 up 1.00000 1.00000
74 hdd 7.27699 osd.74 up 1.00000 1.00000
77 hdd 7.27699 osd.77 up 1.00000 1.00000
80 hdd 7.27699 osd.80 up 1.00000 1.00000
83 hdd 7.27699 osd.83 up 1.00000 1.00000
-306 58.21599 host <host>-03-backup
60 hdd 7.27699 osd.60 up 1.00000 1.00000
64 hdd 7.27699 osd.64 up 1.00000 1.00000
67 hdd 7.27699 osd.67 up 1.00000 1.00000
70 hdd 7.27699 osd.70 up 1.00000 1.00000
73 hdd 7.27699 osd.73 up 1.00000 1.00000
76 hdd 7.27699 osd.76 up 1.00000 1.00000
79 hdd 7.27699 osd.79 up 1.00000 1.00000
82 hdd 7.27699 osd.82 up 1.00000 1.00000
Настройка Erasure Coding
Чтобы было возможно использовать как можно больше места, мы решили использовать Erasure Coding. Плюс – это больше доступного места для хранения, а минусы – то, что после создания такого пула его уже не получится переместить на другой root в CRUSH Map, а также он более затратный для мощностей сервера и медленнее, чем реплика. И вот почему:
EC распределяет данные между нодами, поэтому чтение или запись данных приводят к повышенной сетевой нагрузке;
Блоки чётности генерируются при записи данных, что влияет на скорость записи. Это может быть медленнее, чем запись файла при факторе репликации = 1, но будет быстрее, чем при двух или более репликах;
Если данные утеряны или повреждены, то в процессе восстановления данных происходит чтение оставшихся данных и блоков чётности. Этот процесс требует ресурсов CPU и сети.
В нашем случае мы использовали следующие настройки:
root@<host>:~# ceph osd erasure-code-profile get backup-cephfs
crush-device-class=hdd
crush-failure-domain=host
crush-root=backup
jerasure-per-chunk-alignment=false
k=7
m=2
plugin=jerasure
technique=reed_sol_van
w=8
Коэффициент EC можно посмотреть командой:
ceph osd pool autoscale-status
Для нашего пула с данными он равен 1.2857142686843872:
POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE
cephfs_metadata 18007M 3.0 1723T 0.0000 4.0 32 on
cephfs_data 308.8T 1.2857142686843872 1723T 0.2304 1.0 4096 512 off
Тюнинг плейсмент групп (далее – PG) для более равномерного распределения данных внутри пула.
Для вашего пула с данными мы советуем сразу отключить autoscale pg. Дело в том, что если вы также его будете использовать для бекапа, то количество данных у вас будет постоянно меняться. А из-за этого он будет менять вам количество PG, что в свою очередь запустит ребаланс данных, чего вы точно не хотите делать, когда у вас вот-вот запустится следующий бэкап.
Для нашего пула у нас используется PG_NUM= 4096. Это нам нужно для того, чтобы в PG было меньше данных и было более ровное распределение их между нашими OSD, что в свою очередь сильно уменьшает возможность полностью занять место (как у нас это было при PG_NUM=512).
Чтобы понять, почему так может произойти, давайте разберёмся, как считается свободное место в pool:
pool_free_size = min_size_AVAIL * osd_count * full-ratio / replica_factor
где min_size_AVAIL – это наименьший доступный размер места в OSD из этого CRUSH Map. Число PG влияет на значение этого параметра;
osd_count – число OSD в CRUSH Map, которой принадлежит пул;
full_ratio – это коэффициент заполнения OSD (по умолчанию 0,95);
replica_factor – фактор репликации (либо коэффициент EC).
По этой формуле понятно, что чем лучше перераспределение, тем меньше будет перекашивать в меньшую сторону min_size_AVAIL, и тем больше доступно места в пуле.
Например, для нашего случая расчёт доступного места под размещение данных будет следующим:
root@<host>:~# ceph osd df backup | sort -k15,51 -n | head -n 4
ID CLASS WEIGHT REWEIGHT SIZE RAW USE DATA OMAP META AVAIL %USE VAR PGS STATUS
MIN/MAX VAR: 0.70/1.22 STDDEV: 2.55
TOTAL 1.5 PiB 462 TiB 435 TiB 387 MiB 1.5 TiB 1.0 PiB 30.59
181 hdd 7.42400 1.00000 7.4 TiB 2.8 TiB 2.6 TiB 63 KiB 8.8 GiB 4.6 TiB 37.45 1.22 223 up
root@<host>-01:~# ceph osd ls-tree backup | wc -l
204
pool_free_size = 4.6 TiB * 204 * 0,95 / 1.2857142686843872 = 693,3733425174 TiB
Интерконнект
Интерконнект нужен, когда у вас большие объёмы, это в разы ускоряет ребалансы, а также положительно влияет на доступность OSD в целом. Всегда делайте его в Ceph и будет хорошо;
Тюнинг OSD, а именно вынос Block.DB на SSD
После того, как у нас появился отдельный CRUSH Map для бэкапа, высокая нагрузка на диски OSD никуда не исчезла. Проблема была в том, ни Block.WAL, ни Block.DB не были вынесены на отдельные диски (хотя для этого на серверах была возможность). Для каждой OSD были созданы lv на SSD-дисках (которые объединены в RAID1).
Мы решили, что будем выносить только Block.DB, так как из документации следует, что Block.WAL будет совмещён с Block.DB автоматически.
Пример команд для миграции Block.DB:
# Останавливаем OSD и ждём завершения ребаланса (можно просто через ceph osd out, потом остановить)
service ceph-osd@154 stop
# Зачищаем OSD
ceph-volume lvm zap /dev/sdg
# Удаляем vg
vgremove ceph-60bec9ad-eaff-46f7-9314-7711e1c70e81
# Удаляем OSD из кластера
ceph osd destroy 154 --yes-i-really-mean-it
# Снова создаем OSD, указывая размещение для Block.DB (если не меняется osd-id, то она снова нормально заезжает и сразу в нужном нам root в CRUSH Map)
ceph-volume lvm create --bluestore --data /dev/sdg --block.db ceph-db/db-osd-7 --osd-id 154
Эта процедура долгая, так как обрабатывается по одной OSD, а их может быть много. После каждого ввода OSD нужно дожидаться ребаланса. Поэтому чтобы сэкономить время, мы просто стёрли CephFS (в котором жили только тестовые бекапы, и их тогда было немного). А уже на свободных OSD мы всё это сделали быстро и автоматизировано через Ansible. Если данные критичны, то нужно выводить OSD по одной и долго переделывать. Поэтому рекомендуем обратить на это внимание заранее.
Создание нескольких инстансов MDS на одном сервере, увеличение активного количества MDS и увеличение памяти.
Проведём краткий экскурс:
Для работы CephFS необходим MDS. Ceph MDS является сокращением от "сервера метаданных". Он требуется только для файловой системы Ceph (CephFS) и других методов хранения блоков. Хранение на основе объектов не требует служб MDS. Ceph MDS работает как демон, который позволяет клиентам монтировать файловую систему POSIX любого размера. MDS не предоставляет клиенту напрямую никаких данных; предоставление данных осуществляется OSD. MDS обеспечивает совместно используемую, согласованную файловую систему с интеллектуальным уровнем кэширования; следовательно, резко сокращая чтения и запись. MDS расширяет свои преимущества в направлении разделения динамичных поддеревьев и отдельных MDS для фрагментов метаданных. Он является динамичным по своей природе; демоны могут присоединяться и уходить, а также быстро поглощать отказавшие узлы.
И сейчас он стал у нас узким местом, но теперь в Ceph его можно масштабировать, что мы и сделали. Как говорилось ранее, у нас два железных сервера MDS, на которых не было никакой нагрузки. Было решено не плодить сервера, а запустить на каждом по несколько инстансов MDS (у нас по 5 инстансов на каждом сервере, итого 10):
mkdir /var/lib/ceph/mds/ceph-<host>/
ceph auth get-or-create mds.<host> mon 'profile mds' mgr 'profile mds' mds 'allow *' osd 'allow *' > /var/lib/ceph/mds/ceph-<host>/keyring
systemctl start ceph-mds@<host>.service
# Если один сервер ляжет все должны перехать на другой
ceph fs set <fs_name> max_mds 4
Вот как это у нас выглядит:
root@<host>:~# ceph fs status
cephfs - 18 clients
======
RANK STATE MDS ACTIVITY DNS INOS
0 active <host>-05-02 Reqs: 0 /s 14.1M 14.1M
1 active <host>-04-03 Reqs: 0 /s 4876k 4876k
2 active <host>-04-02 Reqs: 0 /s 3888k 3888k
3 active <host>-04-01 Reqs: 0 /s 1342k 1342k
4 active <host>-05-03 Reqs: 0 /s 1578k 1578k
POOL TYPE USED AVAIL
cephfs_metadata metadata 50.6G 4115G
cephfs_data data 429T 673T
STANDBY MDS
<host>-05
<host>-04-04
<host>-05-01
<host>-05-04
<host>-04
Также мы увеличили для всех инстансов mds_cache_memory_limit (рассчитали очень просто: mds_cache_memory_limit = общая память на сервере - 4 gb для системы / количество инстансов). Помимо этого, мы перенесли пул cephfs_metadata на отдельный CRUSH Map c SSD-дисками, что решило проблему с задержками доступа к этим данным.
А что на стороне Greenplum?
На стороне кластеров Greenplum были проведены следующие работы:
Перенос серверов самого большого кластера Greenplum в один VLAN с Ceph – это позволило оптимизировать нагрузку на сетевое оборудование, что принесло больше пользы не столько бэкапам, сколько остальной платформе: мощные бэкапы перестали "съедать" сетевой канал у других проектов;
Балансировка трафика внутри bond (layer2+3 в качестве xmit_hash_policy) позволила обеспечить равномерную загрузку обоих портов сетевой карты, что привело и к равномерной загрузке коммутаторов (в нашей топологии порты подключены к разным коммутаторам);
Управление монтированием отдано на откуп утилите autofs, которая раскатывается по всем хостам ролью Ansible – масштабирование проще некуда;
Внедрено сжатие данных алгоритмом zstd. Да, данный алгоритм можно использовать вне зависимости от используемого хранилища данных, но именно он внёс наибольший вклад именно в задачу ускорения резервного копирования. Проанализировав загрузку сетевых интерфейсов в поисках бутылочного горлышка системы, было видно, что во время снятия резервной копии сеть утилизируется по-максимуму, из чего был сделан вывод: "хотим быстрее решить задачу – нужно уменьшить число передаваемых по сети данных". Да, можно также проапрегрейдить и саму сеть, но мы решили пойти путём попроще и проверить на практике заявления о значительном превосходстве в скорости алгоритма zstd над классическим zlib.
Посмотрим, как влияет алгоритм сжатия на время резервного копирования и размер полученной копии (замеры на Ceph):
![](https://habrastorage.org/getpro/habr/upload_files/d2d/161/469/d2d1614695db2031ebfce7c2dbbdf1eb.png)
Пришлось переписать скрипты бэкапа, чтобы вынести из них ротацию и сбор статистики (с hdfs dfs-клиентом подсчёт размера резервной копии выполняется быстро, так как берутся метаданные из нейм-ноды, а удаление файлов выполняется асинхронно и тоже довольно быстро);
Также из-за однажды возникшей проблемы с зависшими клиентами CephFS на некоторых сегмент-нодах Greenplum были внедрены доработки, которые не позволяют запуститься процессу резервного копирования, если Ceph недоступен хоть на одной ноде (с отправкой алерта).
Результаты и выводы
По итогам проделанной работы можно с уверенностью сказать, что полученная конфигурация стала не только надёжнее, но и быстрее, а также удобнее в управлении. Путём простого добавления нод OSD в кластер Ceph происходит его горизонтальное масштабирование, повышая пропускную способность и ёмкость решения. В новое хранилище мы собираем как ежедневные бэкапы с небольших баз, так и раз в неделю полную копию нашего большого кластера Greenplum (плюс инкрементальные бэкапы).
Полученное решение эксплуатируется на постоянной основе уже более полугода, за которые было всего две проблемы: в первый раз переполнился Ceph (после чего перенастроили плейсмент группы), а во второй раз были зависшие клиенты CephFS(решается рестартом OSD). И обе проблемы были только с самым большим бэкапом, а БД поменьше (например, на 10-20 ТБ), вообще ни разу не привлекали к себе внимание. Для сравнения, конфигурация на HDFS не отличалась стабильностью даже на не очень больших базах данных. При этом мы больше не мешаем расчётам пользователей на кластере Hadoop и не расходуем в нём место. Таким образом, ещё и улучшилась бюджетная оценка решения.
Ключевым достижением оказалась и скорость. Фактически, за счёт комплекса мероприятий мы сократили время бэкапирования почти в полтора раза (на примере самого большого стенда):
![](https://habrastorage.org/getpro/habr/upload_files/c4a/75a/1c0/c4a75a1c0c05b2dc9f05c552d81b0ab6.png)
Основными локомотивами прироста скорости можно выделить следующие мероприятия:
добавление нод OSD в кластер Ceph;
исключение из бэкапа части объектов (чистка мусора, удаление дублирующихся сущностей, исключение sandbox из резервной копии);
переход на сжатие zstd уровня 3.
То есть это – коллективная работа, требующая слаженной работы нескольких команд.
Надеемся, что эта информация будет полезна для вас, поможет сэкономить массу времени и избежать ряд ошибок при проектировании подобной системы, с которыми мы столкнулись.