предисловие
Поскольку у всех разные способы чтения исходного кода, процесс чтения здесь представляет собой не передовую практику, а просто воспроизведение собственного процесса чтения. Поэтому, если есть какие-то недостающие моменты, вы также можете указать на них в комментариях. Есть также много мелких партнеров, которые выдвинули некоторые из моих ошибок или улучшений, я хотел бы выразить свою сердечную благодарность здесь.
Затем по предыдущему распорядку мы предлагаем две задачи, и вся статья проводится для завершения проверки следующих задач:
1,Инициализация DataNode: когда мы обычно строим кластер, мы можем видеть службы DataNode через команду jps, поэтому DataNode должен быть сервером RPC.
2,Регистрация DataNode: HDFS — это архитектура master-slave, NameNode — главный узел, а DataNode — подчиненный узел, поэтому DataNode необходимо зарегистрировать в NameNode при запуске..
3.Механизм сердцебиения: подчиненный узел должен отправить сердцебиение, чтобы сообщить главному узлу о выживании подчиненного узла.
4.Как NameNode управляет метаданными и принцип реализации решения высокой доступности HA
(Дополнительный) Принцип решения высокой доступности Hadoop HA
Давайте сначала возьмем простой, потому что очень утомительно переходить непосредственно к исходному коду.
В Hadoop1.x у нас было только по одному NameNode и DataNode, NameNode отвечал за управление метаданными, а DataNode использовался для хранения данных.Для обеспечения безопасности данных каждая копия должна была иметь три резервных копии, а каждый блок занимал размер 64М
Таким образом, NameNode будет иметь проблему с единой точкой отказа, поэтому команда hadoop начала решать эту проблему в это время, потому что NameNode управляет метаданными кластера, который является службой с отслеживанием состояния, а это означает, что он не может, если служба останавливается случайно, так как проблема в том, что есть только один NameNode, с которым непросто работать, почему бы не увеличить количество NameNodes? Но добавление NameNode без причины, как они могут обеспечить согласованность метаданных?
Чтобы решить эту одноточечную проблему, во-первых, как два NameNode обеспечивают согласованность метаданных. В настоящее время существует три решения.
① Используйте каталог общего хранилища Linux
Эта практика на самом деле предназначена для того, чтобы метаданные нашего кластера не сохранялись в Namenode.
Вместо этого он помещается в разделяемое хранилище, что было рекомендовано официальным лицом Apache в то время, но никто его не ест. Так точно больше никто не делает
② Использовать кластер zookeeper
Это тоже очень просто, то есть один из наших NameNode идет к кластеру zookeeper для записи метаданных, а затем другой идет к zookeeper для их чтения.Некоторые компании действительно принимают это решение.
③ Cloudera QJM
Третья программа фактически осуществляется компанией Cloudera, которая завершена кластером журнала «Эта вещь и зоофир» не сильно разные, а логика в основном похоже.
И это тоже сам кластер.Основой работоспособности является то, что выживает более половины узлов.Например,если один из 3-х узлов на моей картинке выйдет из строя, то есть 2/3>0,5.В это время кластер признан здоровым.
Вы спросите, а почему вы так поспешно решили, что первый NameNode будет писать метаданные, а второй — синхронизировать метаданные? Потому что у них обоих есть свои государственные проблемы
В это время NameNode в активном состоянии отвечает за запись в кластер, а резервный читает из кластера.
Конечно, наша проблема сейчас решена?На самом деле нет.Если NameNode(active) вдруг выйдет из строя ранним утром одного дня, то я включу компьютер рано утром,подключу к сервису компании,и буду пользоваться команда принудительного перехода в режим ожидания.Узел NameNode устанавливается в активный кластер, прежде чем он возобновит нормальную работу?
Так как же теперь обеспечить автоматическое переключение состояния NameNode?
④ Реализовать переключение состояния NameNode
На этот раз мы представили старого друга zookeeper, который действительно повсюду. Создайте каталог блокировки в zookeeper, а затем, когда NameNode запустится, он захватит блокировку. Два NameNode, которые захватят его первыми, будут в активном состоянии.
Кроме того, на каждом NameNode есть служба ZKFC, которая постоянно отслеживает состояние работоспособности NameNode.Если есть проблема с активным NameNode, ZKFC сообщит об этом зоокиперу, а затем зоокипер назначит блокировку резервному ИмяУзел. заставить его автоматически переключаться в активное состояние
1. Инициализация DataNode (фрагмент исходного кода основан на Hadoop2.7.0)
Мы непосредственно находим основной метод DataNode, который похож на NameNode.После оценки параметра он выходит, если он не удовлетворен. В дополнение к этому предложению осталось только одно secureMain(args,null), и основной код — это вот этот
Нажмите и найдите creataDataNode, так что мне нравится такое прямое наименование, затем щелкните creataDataNode.
Сначала скопируйте комментарий и вставьте его в Baidu.
Затем мы увидели примеры английского языка, это не тот экземпляр. Ну, так что не думайте слишком много, укажите, что он хочет пойти, что, если следующее также очень просто, потому что, когда это создается успешно, DataNode не является нулевым, тогда это пение DataNode запускается, это так просто, на самом деле это куча запуска потока
При просмотре исходного кода у вас должна быть цель, иначе его заберут какие-то другие коды.Если у вас есть попытка, посмотрите на попытку, и если вы посмотрите на последнее слово в большой цепочке слов, чтобы судить о его Функция, такая как предыдущая, if, Configuration — это конфигурация Да, args — это набор параметров, нас это не волнует. Мы хотим знать, как вы создаете его экземпляр сейчас, так что просто смотрите на этот экземпляр.
Точно так же нас не волнуют предыдущие разрешения, средство проверки, и мы видим, что в конце возвращается DataNode. Тогда мы закажем это
Что бросается в глаза, так это конфигурация кучи параметров, пофиг, тянем на ту позицию, которую хотим видеть, будет проба вокруг строки 465, давайте посмотрим
StartDataNode прошел через несколько процессов
Посмотрите код для запуска DataNode, так что это то, что мы хотим увидеть
① (Дополнительно) DataXceiver
Дополнение: грубо дотянут до строки 1182, этот initDataXceiver(conf) предназначен для инициализации нашего DataXceiver, для чего это нужно, нажмите
Мы знаем, что NameNode отвечает только за управление метаданными в кластере, а реальные данные хранятся на DataNode, фактически DataNode получает загруженные данные через эту службу DataXceiver.
Вокруг строки 974 находится фрагмент кода, который устанавливается в качестве фонового потока. Это фактически означает, что поток и основной поток сосуществуют и умирают. Если основной поток завершается, поток также останавливается.
② (Дополнительно) startInfoServer
Вернитесь к этой позиции StartDataNode
Я полагаю, у вас все еще должно быть впечатление, оно в нашемИсходный код Hadoop --- Процесс запуска NameNode1.4.1 Разбирая процесс запуска NameNode, также есть похожий startHttpServer, В то время этот startHttpServer был связан со многими сервлетами для улучшения своих собственных функций. И наш DataNode такой же, он привяжет сервлет для улучшения самого себя
Внимательные друзья наверняка видели какие-то знакомые термины.Не является ли контрольная сумма контрольной суммой, которую мы используем для проверки целостности данных, а это означает, что функция получения контрольной суммы также является связанным сервлетом
③ Инициализировать службу RPC
Снова вернитесь на позицию StartDataNode и посмотрите initIpcServer
initIpcServer используется службами, запускающими RPC.
Мы снова знакомы с этим кодом, который совпадает сИсходный код Hadoop --- Процесс запуска NameNode1.6.2 Процесс проверки наличия заданного параметра снова очень похож. И после того, как такое же создание сервера завершено, он также привязан ко многим протоколам, таким как interDatanodeProtocolXlator для связи между DataNode и DataNode, и эти протоколы также имеют уникальный идентификатор версии.
④ Создать BlockPoolManager
Роль blockManager была дана в комментариях, давайте нажмем на refreshNamenodes, чтобы увидеть
Когда вы увидите do, продолжайте нажимать. Эта штука имеет более 100 строк кода.Это нужно объяснить по пунктам, но объясняются только два самых важных пункта.
Определить, сколько существует различных фрагментов метаданных
Переведите комментарий, что примерно означает, что он будет определять, является ли каждая новая служба имен обновлением существующих служб имен или совершенно новой службой имен.
Кластер HDFS, который мы обычно строим, представляет собой архитектуру высокой доступности HA, то есть NameNode разделен на два активных и резервных, и метаданные, которыми управляют эти два, одинаковы, поэтому они управляют одними и теми же службами имен (как здесь понимается, службы имен — это A каталог, в котором хранятся метаданные). Что касается федерации, каждая федерация будет управлять частью метаданных, и, естественно, для двух федераций будет две разные части метаданных.
Федеральный обход
Создайте BPOfferService для каждой федерации и создайте BPServiceActor для каждого NameNode (фактически 2) в федерации.
На этом этапы инициализации завершены. Чувствуете, что запутались? Все в порядке, впереди еще процесс регистрации.
Во-вторых, процесс регистрации DataNode
Сейчас в конце позиции есть startAll(), это основная логика регистрации, нажмите
Здесь вы можете видеть, что он пересекает федерацию, а затем мы нажимаем на метод start()
Соединение должно сначала пройти федерацию, затем пройти NameNode в федерации, затем зарегистрировать DataNodes в пройденном NameNode соответственно и продолжить нажимать кнопку «Пуск».
Вызов метода запуска потока на самом деле вызывает метод запуска, о чем должен знать каждый.
Здесь connectToNNAndHandshake() — это основной код регистрации, а дословный перевод — рукопожатие с NameNode. Здесь используется бесконечный цикл, чтобы гарантировать, что регистрация может быть выполнена.Если возникает исключение, верните его в спящий режим на 5 секунд и повторите попытку. Если выполнение успешно, перерыв.. В любом случае, я здесь мертв, и я должен убедиться, что вы выполните его успешно.
2.1 connectToNNAndHandshake()
Поскольку я без колебаний использовал бесконечный цикл для успешного выполнения connectToNNAndHandshake(), затем щелкните и посмотрите.
На данном этапе наша главная цель — вызвать метод NameNode для регистрации DataNode, который на самом деле должен хранить информацию DataNode в NameNode. Здесь мы получаем прокси NameNode, зачем нам использовать прокси?
Роль прокси-объекта содержит ссылку на реальный объект внутри, чтобы можно было манипулировать реальным объектом, а прокси-объект предоставляет тот же интерфейс, что и реальный объект, чтобы он мог заменить реальный объект в любое время. В то же время прокси-объект может добавлять другие операции при выполнении операций над реальным объектом, что эквивалентно инкапсуляции реального объекта.
Итак, на данный момент мы получаем прокси-объект bpNameNode, а затем регистрируем его с помощью register().
2.2 Регистрационная информация DataNode createRegistration
Спускаясь вниз, вы можете увидеть атрибутивные поля класса DatanodeRegistration, если вам интересно, вы можете узнать о нем.
И мы также можем обнаружить, что в этом процессе имя нашего хоста, номер порта и т. д. были отправлены вместе.
registerDatanode после получения информации DataNode
вернуться к регистрации()
Поскольку код для регистрации в NameNode также очень важен, используется та же процедура бесконечного цикла, что и сейчас, чтобы убедиться, что процесс регистрации в середине должен быть выполнен. он попытается снова после задержки в одну секунду.
На данный момент мы видим, что метод registerDatanode вызывается через объект bpNameNode, который, очевидно, вызывает одноименный метод в NamenodeRpcServer. Если вы нам не верите, щелкните, откройте NamenodeRpcServer, а затем нажмите Ctrl+F для этого узла registerDatanode.
Продолжайте нажимать здесь
Там попробуй посмотреть попробуй, тут явно DataNodeManager для решения проблемы DataNode, продолжай щелкать в регистре
Код внутри относительно длинный, мы растянули его примерно до 995 строк, мы можем видеть addDataNode
addDatanode(nodeDescr)
Параметр nodeDescr — это регистрационная информация упакованного DataNode, только что упомянутого в createRegistration.
На самом деле способ регистрации информации заключается в заполнении этих структур данных, таких как эта datanodeMap, нажмите на нее, чтобы увидеть
Очевидно, что первый параметр — это уникальный идентификатор этого DataNode, а описание второго параметра DataNode — однозначно регистрационная информация этого DataNode, и эта информация хранится в разных структурах данных.
addDatanode(nodeDescr)
Здесь параметры nodeDescr и выше одинаковые, вся регистрационная информация DataNode
Преимущество заключается в том, что если вы будете проходить информацию о пульсе в будущем, вы можете напрямую пройти через структуру данных DatanodeDescriptor вместо того, чтобы сначала проходить DataNode, а затем получать их информацию о пульсе одну за другой.
В общем, регистрация — это фактически сохранение информации в каждой структуре данных.После завершения записи регистрация завершается.
3. Начните отправлять сердцебиения
Вернитесь к 2.1 connectToNNAndHandshake() и посмотрите вниз, что составляет около 890 строк класса BPServiceActor. Если connectToNNAndHandshake прошел успешно, разорвите его и начните отправлять пульсации
Этот цикл на самом деле является бесконечным циклом, в нем нет перерыва, и исключение будет только повторяться, поэтому давайте нажмем и посмотрим
Интервал пульса DataNode и NameNode
В if (startTime - lastHeartbeat >= dnConf.heartBeatInterval) оценивается, что если текущее время - время последнего сердцебиения больше, чем dnConf.heartBeatInterval, оно будет выполнено, так что давайте посмотрим, какова длина этого heartBeatInterval, нажмите Это
Взгляните на это значение DFS_HEARTBEAT_INTERVAL_DEFAULT по умолчанию — 3.
Так что мы узнаем позже,Сердцебиение DataNode и NameNode на самом деле каждые 3 секунды..
Затем есть предложение HeartbeatResponse resp = sendHeartBeat(), где HeartbeatResponse является инструкцией, выдаваемой NameNode узлу DataNode, нажмите sendHeartBeat()
Я обнаружил, что на самом деле некоторая информация DataNode будет прикреплена к пульсу, например, первый отчет - это смысл отчета, щелкните его, чтобы увидеть
Видите ли, на самом деле это объем памяти, использование памяти и т. д.
отправить сердцебиение отправитьсердцебиение
Вызов пульса через прокси-объект bpNamenode узла NameNode фактически вызывает метод sendHeartbeat узла NameNode напрямую.
Эти параметры тоже внесены, продолжим
Команды здесь — это инструкции, которые NameNode хочет, чтобы DataNode работал, и они будут инкапсулированы как параметр в объект HeartbeatResponse и возвращены в DataNode.
Давайте попробуем посмотреть, как обрабатывается сердцебиение
ручка сердцебиения ручкасердцебиение
Глядя на это, я на самом деле чувствую, что смотрю на повторяющийся код, но чтение исходного кода — такой запутанный процесс.
Первый getDatanode должен получить соответствующий DataNode в соответствии с уникальным идентификационным номером каждого DataNode.
Метод updateHeartbeat был переведен на метод обновления статуса сердцебиения.
Здесь, поскольку наш DataNode всегда работает, он должен обновлять свое собственное состояние, и тогда очень важно, чтобы онВремя последнего сердцебиения должно быть изменено, потому что мы его только что видели, мы передаем текущее время - время последнего сердцебиения = 3 с, сердцебиение будет отправлено снова, поэтому этот шаг очень важен. А еще нам нужно использовать индикатор сердцебиения, чтобы определить, жив ли узел DataNode, потому что, если сердцебиение не установлено через определенное время (это значение настраивается само), NameNode определит, что узел не работает, и тогда он позволит другим Блок копирует более одной копии данных.
На данный момент DataNode почти такой же.