Короткий ответ: Ceph не для этого был придуман.Заранее извинияюсь за сильное упрощение и прошу умных людей не сильно пинать меня за упущения.
Длинный ответ требует постановку задачи, для чего придумывали кластерные файловые системы:
Вот, например, у вас есть небольшой вычислительный кластер, скажем, узлов (серверов) на 200-300. Занимаетесь вы обработкой данных физических экспериментов или какой-нибудь сейсморазведкой. Т.е. у вас не модельные данные, а вполне себе зарегистрированные цифровые результаты каких-то физических процессов. Их тоже не очень много, ну, скажем, примерно петабайт. Из которых 4/5 - это результаты предыдущих обсчётов, а 200T - это тот датасет, с которым сейчас _активно_ работает кластер. Софт, с которым вы работаете, написан не вами, а какой-то другой группой разработчиков, которые собаку съели на физике и оптимизировали некие "решатели" под разные архитектуры CPU/GPU. Софт работает с обычной файловой структурой, создаёт кучу индексов, поддерживает собственный внутренний формат БД для работы с данными, читает данные, визуализирует их, пишет логи и результаты параллельно со всех серверов в одном дереве файлов. Данные терять нельзя, производительность _имеет значение_, как по задержкам, так и по пропускной способности. Дополнительное требование: в следующем году расширить систему хранения на 30%.
И вот, вооружившись собственным мозгом и интернетом, вы начинаете изучать вопрос: а как "большие дяди" решают такие задачки. На выбор: Lustre, BeeGFS, pNFS (Panasas или NetApp), вычёркиваете Intel DAOS, т.к. она блочная, вычёркиваете Exellero, по той же причиние, смотрите в сторону VAST Data и прикидываете в уме ценник на коробочное решения.
Если вы решите выбрать Ceph, то вам никто не может запретить, но между "бакетами ceph" и файловой структурой будет стоять RadosGW, после чего вам понадобится один или несколько NFS Ganesha, который работает в пространстве пользователя, со всеми вытекающими накладными расходами и вносимыми задержками.
Давайте, грубо, посмотрим на цепочку открытия некоторого файла с данными, в качестве примера:
В случае Ceph:
- Приложение хочет открыть некий файл (/distributed/data/path/to/file) и дёргает ядро.
- Ядро смотрит, что за этот кусок отвечает NFS клиент.
- NFS клиент в составе ядра обращается к одному из серверов NFS Ganesha
- Запрос пошёл по сети.
- ядро на NFS сервере (который Ganesha), перебросило данные из пространства ядра в процесс Ganesha.
- NFS Ganesha запрос получил.
- Дёрнул RadosGW (для простоты они на одной машине)
- RadosGW дёрнул сервер метаданных Ceph.
- В этот момент опять произошло переключение контекста.
- Запрос пошёл по сети.
- Сервер метаданных ответил какие бакеты Ceph надо забрать из OST, в которых будут метаданные файлов.
- RadosGW отправляет запрос/запросы по сети на полученные OST. Опять с переключением контекста.
- запросы пошли по сети, ждём приезда данных (бакеты фиксиорованно размера, какого, кстати?)
- Ждём, когда все данные приедут и мы отдадим их Ganesha. Ещё одно переключение контекста.
- Данные приехали и Ganesha мысленно поставил себе галочку, что с данным файлом работают. Проверяет какие у него права доступа, заблокирован ли он кем-то ещё и если всё в порядке, то возвращает клиенту некий дескриптор открытого файла.
- Клиент NFS радостно рапортует, что файл открыт.
Дальше мы хотим прочитать кусок данных из файла. Вся цепочка повторяется, но с удлиннением, вместо метаданных файла, мы будем получать некоторую кучку бакетов, которые потом будем через NFS передавать клиенту, запоминая по дороге, где находится текущий указатель на чтение.
Как это будет происходить в Luste/BeeGFS:
- Приложение хотет открыть файл и дёргает ядро.
- Ядро понимает, что за этот путь в виртуальной файловой системе отвечает клиент Lustre (который тоже в составе ядра) и сразу дёргает его.
- Клиент Lustre не покидая пространства ядра, делает запрос к серверу метаданных
- Запрос уходит по сети сразу из ядра.
- Получает ответ, что файл открыт, если права пользователей позволяют, т.к. сервер метаданных хранит не только карту блоков содержимого файлов, но и права доступа, владельца и все остальные атрибуты.
- Клиент Lustre сообщает ядру, что файл открыт.
- Ядро возвращает приложению: файл открыт.
В случае чтения какого-то блока из файла:
- Клиент просит сместиться внутри файла на 100Gb и прочитать блок данных размером 10M.
- Ядро дёргает клиента Lustre (который всё тот же модуль ядра).
- Клиент Lustre запрашивает у сервера метаданных какие сервера OST отвечают за этот диапазон.
- Запрос уходит в сеть из ядра (нет переключения контекста).
- Сервер метаданных проверяет блокировки этого диапазона и, если противопоказаний нет, то возвращает список и номера блоков.
- Клиент Lustre (не покидая пространства ядра) параллельно запрашивает нужные блоки у серверов OST.
- Запросы уходят по сети (кстати, это может быть Infiniband с RDMA, что ещё немного сокращает задержки)
- Получив данные он либо оставляет их в кэше и делает memory map для приложения, либо копирует данные в пространство приложения (тут происходит переключение контекста), в зависимости от того, как именно приложение просило открыть себе файл и как читает данные.
Ну и напоследок. Наступает новый финансовый год. Планов - громадьё. Руководство, в своей бесконечной мудрости, решает, что надо бы расширить кластер и увеличить объём хранения данных процентов эдак на 30%. Закупает железо. А все проекты идут и активно работают. Как ребалансировка Ceph повлияет на производительность? Вы готовы ждать пока она закончится?