flyingeagle

Hadoop-hdfs架构

一. Hadoop简介

1.Hadoop简介

  Hadoop到目前为止发展已经有10余年,版本经过了无数次的更新迭代,目前业内大家把Hadoop大的版本分为Hadoop1,hadoop2,Hadoop3三个版本。

2.Hadoop1简介

  Hadoop1版本刚出来的时候是为了解决两个问题:一个是海量数据如何存储的问题,一个是海量数据如何计算的问题。Hadoop1的核心设计就是HDFS和Mapreduce。HDFS解决了海量数据如何存储的问题,Mapreduce解决了海量数据如何计算的问题。

  HDFS的全称:Hadoop Distributed File System

 

二.传统数据的存储

 

 

三.大数据技术的处理

 

1.主节点

2.HDFS

 

二.Hadoop1架构

1.HDFS1架构

  HDFS1是一个主从式的架构,主节点只有一个叫NameNode。从节点有多个叫DataNode

2.NameNode

  管理元数据:文件与Block块,Block块与DataNode主机的关系

  NameNode为了快速响应用户的操作请求,所以把元数据加载到了内存里面

3.DataNode

  存储数据,把上传的数据划分成为固定大小的文件块(Hadoop1,默认是64M)

  为了保证数据安全,每个文件块默认都有三个副本

 

4.HDFS1遇到的架构问题

a.单点故障问题

b.内存受限问题

 

  但是NameNode是有状态的主节点,里面存储的元数据。

5.单点故障问题架构方案

  a.共享目录

 

  共享目录这个方案很少有人用。

  b.zookeeper集群

 

   c.QJM方案

 

   完善journalnode集群

  a.如何让journalnode集群完成自动切换?

 

   NameNode三个不更好吗?

 

6.内存受限方案解决

 

 

 

   联邦

 

 

  实际上吧HDFS的问题解决完成之后就是HDFS2。

 

7.HDFS2

  a.HA方案(High Available)

    解决HDFS1 Namenode单点故障问题

  b.联邦方案

    解决了HDFS1 内存受限问题

8.HDFS3

  a.hadoop3没有特别大的架构变化 更多的是做了优化的操作!
  b.HDFS2只能支持2个互为HA 但是Namenode能支持多个互为HA
  c.引入纠删码技术 为了解决副本冗余的问题 ,磁盘资源浪费的问题

 

三.HDFS支持亿级流量秘密

  因为NameNode管理了元数据,用户所有的操作请求都要操作Namenode,大一点的平台一天需要运行几十万,上百万的任务。一个任务就会有很多个请求,这些所有的请求都打到NameNode这儿,对于Namenode来说这就是亿级的流量,Namenode是如何支撑亿级流量的呢?

1.HDFS如何管理元数据

2.分段加锁和双缓冲方案

  代码实现:

package com.bijian;

import java.nio.DoubleBuffer;
import java.util.LinkedList;

public class FSEditLog {

    public static void main(String[] args) {

        FSEditLog fsEditLoglog = new FSEditLog();
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 100; j++) {
                        fsEditLoglog.writeLog(Thread.currentThread().getName());
                    }
                }


            }).start();
        }
    }

    public long taxid = 0;
    //分段加锁的代码
    public DoubleBuffer doubleBuffer = new DoubleBuffer();
    //当前是否有线程在刷写磁盘
    public boolean isRunning = false;
    public long maxTaxid = 0;
    public ThreadLocal<Long> threadLocalTaxid = new ThreadLocal<Long>();
    public boolean isWait = false;
    
    public void writeLog(String log) {
        //taxid 1 currentBuffer:1 2 3 4 5多条数据
        synchronized (this) {
            taxid++;
            //构建日志对象
            EditLog editLog = new EditLog(taxid, log);
            //写内存
            doubleBuffer.writeLog(editLog);
            threadLocalTaxid.set(taxid);

        }//分段 释放锁
        flushLog();
    }

    private void flushLog() {
        synchronized (this) {
            long localTaxid = threadLocalTaxid.get();
            if (localTaxid < maxTaxid) {//当前有线程在同步磁盘

                return;
            }
            if (isWait) {
                return;
            }
            isWait = true;
            while (isRunning) {
                try {
                    this.wait(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            isWait = false;
            //交换内存
            doubleBuffer.exchange();
            isRunning = true;
            if (doubleBuffer.syncBuffer.size() != 0) {
                maxTaxid = doubleBuffer.getMaxTzxid();
            }
        }//把内存里面的数据加到磁盘
        doubleBuffer.flush();
        synchronized (this) {
            isRunning = false;
        }
    }


    public class DoubleBuffer {

        //消息队列
        //用来写日志
        public LinkedList<EditLog> currentBuffer = new LinkedList<EditLog>();

        //用来把内存里面的元数据同步到磁盘
        public LinkedList<EditLog> syncBuffer = new LinkedList<EditLog>();

        /**
         * 写日志
         *
         * @param editLog
         */
        public void writeLog(EditLog editLog) {
            currentBuffer.add(editLog);
        }

        public void flush() {
            for (EditLog editLog : syncBuffer) {
                //把数据写到磁盘上面
                System.out.println(editLog);
            }
            syncBuffer.clear();
        }

        //交换内存
        public void exchange() {
            LinkedList<EditLog> tmp = currentBuffer;
            currentBuffer = syncBuffer;
            syncBuffer = tmp;
        }

        public long getMaxTzxid() {
            return syncBuffer.getLast().taxid;
        }
    }

    //面向对象的思想,把每一条数据信息,都看成一个对象
    public class EditLog {
        //事务的ID号
        public long taxid;
        //元数据的类型
        public String log;
        //生成一个构造函数

        //生成一个构造函数
        public EditLog(long taxid, String log) {
            this.taxid = taxid;
            this.log = log;
        }

        @Override
        public String toString() {
            return "EditLog{" +
                    "taxid=" + taxid +
                    ", log=\'" + log + \'\\'\' +
                    \'}\';
        }
    }
}

 

分类:

技术点:

相关文章: