Глубокое погружение в реализацию хранилища метаданных
21 мая 2022 г.В этой статье рассказывается о дизайне и реализации хранилища метаданных в Alluxio Master как в куче, так и вне кучи (на основе RocksDB).
Фон
Alluxio — первая в мире платформа оркестрации данных с открытым исходным кодом для аналитики и искусственного интеллекта в облаке. Alluxio устраняет разрыв между приложениями, управляемыми данными, и системами хранения. Это приближает данные с уровня хранения к приложениям, управляемым данными, и делает их легко доступными, позволяя приложениям подключаться к многочисленным системам хранения через общий интерфейс. Архитектура Alluxio обеспечивает доступ к данным на несколько порядков быстрее, чем существующие решения.
В качестве распределенной системы Alluxio использует архитектуру Master-Worker. Кластер Alluxio состоит из одного или нескольких главных узлов и нескольких рабочих узлов. Alluxio Master обслуживает все пользовательские запросы и регистрирует изменения метаданных файловой системы. Работники Alluxio несут ответственность за управление настраиваемыми пользователем локальными ресурсами, выделенными для Alluxio (например, памятью, твердотельными и жесткими дисками). Рабочие процессы Alluxio хранят данные в виде блоков и обслуживают запросы клиентов, которые читают или записывают данные, читая или создавая новые блоки в своих локальных ресурсах.
В этой статье рассказывается, как Alluxio реализует хранилище метаданных в Alluxio Master.
Два способа хранения метаданных в Alluxio
Внутри мастера Alluxio каждый файл или каталог представлен структурой данных, называемой inode, которая содержит атрибуты, такие как права доступа к файлам, и другие метаданные, такие как расположение блоков. Alluxio master хранит метаданные всей файловой системы в виде дерева инодов, аналогично HDFS и другим файловым системам на базе UNIX.
Alluxio предоставляет два способа хранения метаданных:
- ROCKS: хранилище метаданных на основе RocksDB на диске.
- HEAP: хранилище метаданных в куче
По умолчанию это камни.
Исходный код Alluxio предоставляет два интерфейса, InodeStore и BlockStore, в каталоге /core/server/master/src/main/java/alluxio/master/metastore. Метаданные, управляемые InodeStore, включают отдельные индексные дескрипторы и отношения родитель-потомок между различными индексными дескрипторами. BlockStore отвечает за управление размером блока и расположением блоков файловых данных. cachingInodeStore реализует настраиваемый кеш в куче Java перед RocksDB для повышения производительности. В HEAP эти интерфейсы реализованы через HeapInodeStore и HeapBlockStore. Общие отношения зависимости следующие.
Во время AlluxioMasterProcess две фабрики генерируются для соответствующих хранилищ, а в фабриках генерируются разные InodeStore и BlockStore на основе конфигураций.
РОКС Метастор
RocksDB — это встроенная база данных типа «ключ-значение». Пользователи могут добиться эффективного хранения данных KV и доступа к ним, вызвав интерфейс API.
Интерфейс BlockStore реализуется RocksBlockStore со следующим процессом.
- Фабрика добавляется в mContext в AlluxioMasterProcess.
- MasterUtils.createMasters() создаст все основные потоки по порядку. При создании DefaultBlockMaster он вызывает BlockStore.Factory для создания экземпляра RocksBlockStore.
- RocksDB.loadLibrary() будет вызываться при запуске RocksBlockStore для загрузки зависимых библиотек, а затем создания экземпляра класса RocksStore в соответствии с файлом конфигурации. RocksStore используется для работы с базой данных RocksDB, включая инициализацию базы данных, резервное копирование и восстановление базы данных и т. д.
- При создании RocksStore экземпляр класса RocksDB создается путем вызова метода RocksDB.open() в методе create().
- DefaultBlockMaster читает и записывает в базу данных RocksDB, используя этот класс RocksDB.
RocksBlockStore использует следующие основные методы:
- getBlock(длинный идентификатор)
- putBlock (длинный идентификатор, метаданные BlockMeta)
- removeBlock(длинный идентификатор)
- getLocations (длинный идентификатор)
- addLocation (длинный идентификатор, местоположение BlockLocation)
- removeLocation (длинный идентификатор блока, длинный рабочий идентификатор)
Давайте возьмем getBlock() в качестве примера. getBlock() используется для получения метаданных соответствующего блока по blockId следующим образом.
@Override
public Optional
байт [] мета;
пытаться {
meta = db().get(mBlockMetaColumn.get(), Longs.toByteArray(id));
} поймать (RocksDBException e) {
бросить новое исключение RuntimeException(e);
если (мета == ноль) {
вернуть необязательный.пустой();
пытаться {
return Optional.of(BlockMeta.parseFrom(meta));
} поймать (Исключение e) {
бросить новое исключение RuntimeException(e);
Ниже приведено взаимодействие с RocksDB:
meta = db().get(mBlockMetaColumn.get(), Longs.toByteArray(id));
Метод db() в приведенном выше коде вернет ранее созданный класс RocksDB, а затем вызовет метод RocksDB.get(). Метод get() требует два параметра: первый — ColumnFamilyHandle, а второй — blockId.
Каждая пара K-V в RocksDB соответствует ColumnFamily, а ColumnFamily эквивалентна логическому разделу в RocksDB. Когда нам нужно запросить данные в ColumnFamily, нам нужно управлять базовой базой данных через ColumnFamilyHandle, который создается при создании экземпляра RocksDB.
Данные K-V, хранящиеся в RocksDB, хранятся в виде строк байтов, поэтому нам нужно преобразовать blockId в byte[] и преобразовать значение, возвращенное из RocksDB, обратно в объект BlockMeta Java с использованием буферов протокола Google.
Интерфейс InodeStore в методе ROCKS реализуется CachingInodeStore и RocksInodeStore. CachingInodeStore использует память для хранения кеша метаданных, а RocksInodeStore — это хранилище метаданных, реализованное RocksDB в качестве резервного хранилища CachingInodeStore.
Когда метаданные кластера Alluxio могут быть полностью сохранены в CachingInodeStore, Alluxio не взаимодействует с RocksInodeStore, а вместо этого использует CachingInodeStore для повышения производительности. Когда емкость хранилища CachingInodeStore достигает порогового значения, Alluxio автоматически переносит метаданные из CachingInodeStore в RocksInodeStore. На данный момент производительность доступа к метаданным зависит от скорости попадания в кэш CachingInodeStore и производительности RocksDB.
Процесс создания и использования RocksInodeStore аналогичен процессу RocksBlockStore. Если для параметра MASTER_METASTORE_INODE_CACHE_MAX_SIZE установлено значение 0, используется RocksInodeStore. если он не равен 0, то необходимо создать как CachingInodeStore, так и RocksInodeStore.
кейс РОКС:
Конфигурация экземпляра = ServerConfiguration.global();
если (conf.getInt(PropertyKey.MASTER_METASTORE_INODE_CACHE_MAX_SIZE) == 0) {
вернуть lockManager -> новый RocksInodeStore (baseDir);
} еще {
return lockManager -> new CachingInodeStore (new RocksInodeStore (baseDir), lockManager);
Хранилище метаданных кучи
Alluxio использует динамическую память в качестве хранилища в методе Heap. При создании AlluxioMasterProcess создаются HeapInodeStore и HeapBlockStore для реализации интерфейсов InodeStore и BlockStore.
При создании HeapInodeStore создается ConcurrentHashMap с именем mInodes для хранения информации Inode файлов и папок. В то же время будет создан TwoKeyConcurrentMap с именем mEdges для хранения отношений родитель-потомок различных узлов.
private final Map<Long, MutableInode<?>> mInodes = new ConcurrentHashMap<>();
// Сопоставление идентификатора инода с идентификаторами дочерних элементов этого инода. Внутренние карты упорядочены по имени ребенка.
private final TwoKeyConcurrentMap
новый TwoKeyConcurrentMap<>(() -> новый ConcurrentHashMap<>(4));
TwoKeyConcurrentMap — это класс, определенный в Alluxio, который реализует ConcurrentMap, поддерживающий два ключа со следующей логической структурой:
Каждый ключ в структуре данных mEdges сопоставляет идентификатор Inode с картой его дочерних элементов, которая затем сопоставляет имя каждого дочернего элемента с его идентификатором Inode.
В HeapBlockStore создается ConcurrentHashMap с именем mBlocks для хранения метаданных каждого блока, а TwoKeyConcurrentMap с именем mBlockLocations создается для хранения местоположения блока в рабочем потоке.
// Сопоставление идентификатора блока с метаданными блока.
public final Map
// Сопоставление идентификатора блока с расположением блоков.
открытый финал TwoKeyConcurrentMap
mBlockLocations = new TwoKeyConcurrentMap<>(() -> new HashMap<>(4));
Два ключа в mBlockLocations — это blockId и workerId, а значение — это конкретные места в рабочем потоке, где хранится блок. BlockId можно использовать для получения местоположения блока, хранящегося в рабочем потоке.
Резюме
Alluxio предоставляет два способа хранения метаданных: ROCKS и HEAP, а хранилище по умолчанию — ROCKS. Для ROCKS, помимо использования RocksDB, Alluxio предоставляет кеш в памяти для повышения производительности чтения и записи метаданных. В результате мы можем получить высокую производительность при ограничении размера хранилища метаданных. С RocksDB мы можем хранить метаданные на жестком диске, чтобы получить больше места для хранения.
В общем, мы должны использовать RocksDB для хранения метаданных в Alluxio Master. Если вам нужно хранить только небольшой объем метаданных, требующих очень высокой производительности чтения и записи метаданных, вы также можете рассмотреть возможность использования метода HEAP.
Об авторе
Чаншэн Гу, инженер по работе с большими данными в China Mobile.
Гу работает в China Mobile Cloud Center, разрабатывая облачное озеро данных с упором на HDFS и Alluxio.
Оригинал