Учебное пособие по HDFS: Archiтектура, чтение и запись Operaпроизводство

⚡ Умное резюме

HDFS — это распределенный уровень хранения данных в Hadoop, который разделяет очень большие файлы на реплицированные блоки на обычных машинах, так что для работы одного NameNode tracметаданные ks, в то время как многие DataNodes надежно обрабатывают запросы на чтение и запись.

  • 🔘 Archiтекстура: NameNode хранит образ пространства имен и журнал изменений, а DataNodes — фактические реплики блоков.
  • ☑️ Размер блока: В Hadoop 1.x по умолчанию использовались блоки размером 64 МБ; в Hadoop 2.x и 3.x вместо этого используются блоки размером 128 МБ.
  • Репликация: По умолчанию используется три реплики на блок, распределенные по стойкам, чтобы при сбоях оборудования данные никогда не терялись.
  • 🧪 Путь чтения: Функции FSDataInputStream и DFSInputStream получают координаты блоков от NameNode, а затем передают байты напрямую от DataNodes.
  • 🇧🇷 Введите путь: DFSOutputStream ставит пакеты в очередь, DataStreamer создает конвейер обработки данных в DataNode, а очередь подтверждений (Ack Queue) защищает от потери пакетов.
  • 🧭 Варианты доступа: org.apache.hadoop.fs Java API и оболочка hdfs dfs охватывают операции открытия, чтения, записи и закрытия.

Учебное пособие по HDFS

Что такое HDFS?

HDFS — это распределенная файловая система для хранения очень больших файлов данных, работающая на кластерах из стандартного оборудования. Она отказоустойчива, масштабируема и чрезвычайно проста в расширении. Hadoop поставляется в комплекте с HDFS (Hadoop Distributed File System).

Когда данные превышают емкость хранилища на одной физической машине, становится необходимым разделить их на несколько отдельных машин. Файловая система, которая управляет конкретными операциями хранилища в сети компьютеров, называется распределенной файловой системой. HDFS — одно из таких программ.

HDFS Archiтекстура

Кластер HDFS в основном состоит из Имя Узел которая управляет метаданными файловой системы и Узлы данных которые хранят сами данные.

  • Имя Узел: NameNode можно считать главным устройством системы. Он поддерживает дерево файловой системы и метаданные для всех файлов и каталогов, присутствующих в системе. Для хранения метаданных используются два файла: «образ пространства имен» и «журнал изменений». NameNode знает обо всех DataNode, содержащих блоки данных для данного файла, однако он не хранит информацию о местоположении блоков постоянно. Эта информация восстанавливается каждый раз из DataNode при запуске системы.
  • Узел данных: DataNodes — это подчиненные узлы, которые находятся на каждой машине в кластере и обеспечивают фактическое хранение данных. Они отвечают за обработку запросов на чтение и запись от клиентов.

Поскольку отдельный NameNode представлял бы собой единую точку отказа, в современных кластерах активный NameNode работает параллельно с резервным NameNode, который обменивается журналом изменений через кворум JournalNodes, обеспечивая автоматическое переключение между ними в случае отказа.

Операции чтения и записи в HDFS выполняются на уровне блоков. Файлы данных в HDFS разбиваются на блоки размером с один блок, которые хранятся как независимые единицы. Размер блока по умолчанию составляет 64 МБ в Hadoop 1.x. Начиная с Hadoop 2.x, размер блока по умолчанию составляет 64 МБ. dfs.blocksize составляет 128 МБ.

HDFS работает на основе концепции репликации данных, при которой создаются множественные реплики блоков данных, распределяемые по узлам кластера для обеспечения высокой доступности данных в случае отказа узла. Коэффициент репликации по умолчанию равен трем.dfs.replication), и когда DataNode перестает отправлять сигналы подтверждения активности, NameNode автоматически реплицирует свои блоки в другое место.

Знаете ли вы? Файл в HDFS, размер которого меньше одного блока, не занимает всю память блока.

Читать Operaция в HDFS

Запрос на чтение данных обрабатывается HDFS, NameNode и DataNodes. Назовем читателя «клиентом». На диаграмме ниже показана операция чтения файла в Hadoop.

Поток данных об операциях чтения HDFS между клиентом, NameNode и DataNode.

  1. Клиент инициирует запрос на чтение, вызывая метод `open()` объекта `FileSystem`; это объект типа `DistributedFileSystem`.
  2. Этот объект подключается к NameNode с помощью RPC и получает метаданные, такие как адреса блоков файла. Обратите внимание, что эти адреса относятся к первым нескольким блокам файла.
  3. В ответ на этот запрос метаданных возвращаются адреса узлов данных, имеющих копию данного блока.
  4. После получения адресов DataNodes клиенту возвращается объект типа FSDataInputStream. FSDataInputStream содержит DFSInputStream, который отвечает за взаимодействие с DataNode и NameNode. На шаге 4, показанном на приведенной выше диаграмме, клиент вызывает метод 'read()', который заставляет DFSInputStream установить соединение с первым DataNode, содержащим первый блок файла.
  5. Данные считываются в виде потоков, при этом клиент многократно вызывает метод `read()`. Этот процесс операции `read()` продолжается до тех пор, пока не будет достигнут конец блока.
  6. Как только достигается конец блока, DFSInputStream закрывает соединение и переходит к поиску следующего DataNode для следующего блока.
  7. После завершения чтения клиент вызывает метод close().

Написать Operaция в HDFS

В этом разделе мы разберемся, как данные записываются в HDFS через файлы. Диаграмма приведена ниже. traces, которые записывают путь.

Конвейер операций записи в HDFS с использованием DataQueue, DataStreamer и Ack Queue.

  1. Клиент инициирует операцию записи, вызывая метод `create()` объекта `DistributedFileSystem`, который создает новый файл — шаг № 1 на приведенной выше диаграмме.
  2. Объект DistributedFileSystem подключается к NameNode с помощью вызова RPC и инициирует создание нового файла. Однако эта операция создания файла не связывает с файлом никакие блоки. Задача NameNode — проверить, не существует ли уже создаваемый файл и имеет ли клиент необходимые права для создания нового файла. Если файл уже существует или у клиента недостаточно прав для создания нового файла, клиенту выбрасывается исключение IOException. В противном случае операция завершается успешно, и NameNode создает новую запись для файла.
  3. После создания новой записи в NameNode клиенту возвращается объект типа FSDataOutputStream. Клиент использует его для записи данных в HDFS. Вызывается метод записи данных (шаг 3 на диаграмме).
  4. Объект FSDataOutputStream содержит объект DFSOutputStream, который обеспечивает связь с узлами данных (DataNodes) и узлами имен (NameNode). Пока клиент продолжает записывать данные, DFSOutputStream продолжает создавать пакеты с этими данными. Эти пакеты помещаются в очередь, которая называется DataQueue.
  5. Существует еще один компонент, называемый DataStreamer, который потребляет данные из этой очереди. DataStreamer также запрашивает у NameNode выделение новых блоков, выбирая таким образом подходящие DataNode для репликации.
  6. Теперь процесс репликации начинается с создания конвейера с использованием DataNodes. В нашем случае мы выбрали уровень репликации 3, и, следовательно, в конвейере есть 3 узла данных.
  7. DataStreamer передает пакеты в первый DataNode в конвейере.
  8. Каждый DataNode в конвейере сохраняет полученный им пакет и пересылает его второму DataNode в конвейере.
  9. Еще одна очередь, «очередь подтверждений» (Ack Queue), поддерживается модулем DFSOutputStream для хранения пакетов, ожидающих подтверждения от узлов данных.
  10. Как только подтверждение приема пакета в очереди получено от всех узлов данных в конвейере, он удаляется из «Очереди подтверждений». В случае сбоя DataNode пакеты из этой очереди используются для повторного запуска операции.
  11. После завершения записи данных клиент вызывает метод close() (шаг 9 на диаграмме). Вызов метода close() приводит к отправке оставшихся пакетов данных в конвейер, после чего следует ожидание подтверждения.
  12. После получения окончательного подтверждения NameNode получает сообщение о завершении операции записи в файл.

Доступ к HDFS с помощью Java API

В этом разделе мы попытаемся понять Java интерфейс, используемый для доступа к файловой системе Hadoop.

Для программного взаимодействия с файловой системой Hadoop Hadoop предоставляет несколько Java Классы. Пакет org.apache.hadoop.fs содержит классы, полезные для работы с файлами в файловой системе Hadoop. Эти операции включают открытие, чтение, запись и закрытие. API файлов Hadoop является универсальным и может быть расширен для взаимодействия с файловыми системами, отличными от HDFS.

Чтение файла из HDFS программно

Объект java.net.URL используется для чтения содержимого файла. Для начала нам нужно сделать Java распознать HDFS Hadoop URL схема. Это делается путем вызова набора.URLМетод StreamHandlerFactory в URL и передавая ему экземпляр FsUrlStreamHandlerFactory. Этот метод необходимо выполнить только один раз за JVM, следовательно, он заключен в статический блок.

Пример кода:

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

Этот код открывает и считывает содержимое файла. Путь к этому файлу в HDFS передается программе в качестве аргумента командной строки.

Доступ к HDFS через интерфейс командной строки

Это один из самых простых способов взаимодействия с HDFS. Интерфейс командной строки поддерживает операции с файловой системой, такие как чтение файла, создание каталогов, перемещение файлов, удаление данных и вывод списка каталогов.

Мы можем бежать '$HADOOP_HOME/bin/hdfs dfs -help' Чтобы получить подробную справку по каждой команде. Здесь 'dfs' — это команда оболочки HDFS, которая поддерживает множество подкоманд. В текущих версиях Hadoop hdfs dfs является предпочтительной формой, в то время как более старая Hadoop fs Эта команда выполняет одну и ту же работу для любой поддерживаемой файловой системы.

Некоторые из широко используемых команд перечислены ниже вместе с некоторыми подробностями о каждой из них.

1. Скопируйте файл из локальной файловой системы в HDFS.

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

Эта команда копирует файл temp.txt из локальной файловой системы в HDFS, как показано в приведенном ниже выводе.

Команда hdfs dfs -copyFromLocal копирует файл temp.txt в HDFS.

2. Мы можем вывести список файлов, находящихся в каталоге, с помощью параметра -ls.

$HADOOP_HOME/bin/hdfs dfs -ls /

В приведенном ниже списке мы видим файл 'temp.txt' (скопированный ранее) в каталоге '/'.

Команда `hdfs dfs -ls` выводит список файлов temp.txt в корневом каталоге HDFS.

3. Команда копирования файла в локальную файловую систему из HDFS.

$HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

Эта команда аналогична команде -get и принимает в качестве второго аргумента явный локальный путь назначения. В приведенном ниже выводе показано, как файл temp.txt копируется в локальную файловую систему.

Вывод команды hdfs dfs -copyToLocal показывает, что файл temp.txt скопирован в локальную файловую систему.

4. Команда создания нового каталога

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

Команда выполняется без каких-либо сообщений об ошибке, как показывает приведенная ниже подсказка.

Команда `hdfs dfs -mkdir` создает папку `/mydirectory` в HDFS.

Проверьте, создана ли директория. Теперь вы знаете, как это сделать 😉

Часто задаваемые вопросы (FAQ)

Большие блоки позволяют хранить метаданные NameNode в небольшом объеме и дают мапперу возможность считывать длинный последовательный ряд байтов перед повторным поиском. Таким образом, время поиска на диске становится ничтожно малым по сравнению со временем передачи, что и обеспечивает высокую скорость сканирования полных файлов.

NameNode прекращает получать сигналы подтверждения, помечает узел как неработающий и планирует повторную репликацию каждого блока, коэффициент репликации которого упал ниже допустимого значения, на работоспособные DataNode. Записи, находящиеся в процессе передачи, восстанавливаются из очереди подтверждений, поэтому клиент не теряет пакеты.

В кластере с неправильной конфигурацией это не так. В системе высокой доступности HDFS активный и резервный NameNode совместно используют изменения через JournalNodes, а контроллеры отказоустойчивости ZooKeeper автоматически повышают статус резервного узла, когда активный узел перестает отвечать.

Оба варианта загружают данные в HDFS. Опция -copyFromLocal ограничивает источник локальной файловой системой, тогда как -put принимает любой поддерживаемый источник, включая другой путь HDFS или стандартный ввод. В остальном поведение идентично, поэтому -copyFromLocal просто описывает намерение.

Каждый файл, каталог и блок занимают память в NameNode, поэтому миллионы крошечных файлов занимают место в куче задолго до того, как заполнятся диски. Объединение их в последовательные файлы, архивы Avro, ORC, Parquet или HAR позволяют управлять метаданными.

Репликация сохраняет три полные копии, что приводит к увеличению объема хранилища на 200 процентов. Кодирование с исправлением ошибок, добавленное в Hadoop 3, вместо этого хранит ячейки четности и обеспечивает аналогичную надежность при примерно 50-процентном увеличении накладных расходов, при этом более дешевое хранилище обходится дороже, чем затраты на ЦП и сеть при восстановлении.

Модели машинного обучения, обученные на основе журналов аудита NameNode и метрик DataNode, могут прогнозировать исчерпание емкости, выявлять «горячие» блоки и обнаруживать неисправные диски до того, как они выйдут из строя. Обнаружение аномалий в шаблонах доступа также позволяет выявлять неконтролируемые задачи на ранней стадии.

Copilot быстро завершает обработку привычного шаблонного кода org.apache.hadoop.fs, такого как FileSystem.get, циклы FSDataInputStream и вызовы IOUtils.copyBytes. Всегда проверяйте сгенерированный код на соответствие используемой версии Hadoop, поскольку имена API и устаревшие методы заметно различаются между Hadoop 2.x и 3.x.

Подведем итог этой публикации следующим образом: