hadoop集群启动过程模拟

hadoop启动会进过一个安全模式,安全模式有如下几个特点:

安全模式下namenode收集各个datanode的报告,当数据块达到最小副本数(复制因子)以上时,会被认为是“安全”的 。

在一定比例(可设置)的数据块被确定为“安全”后,再过若干时间,安全模式结束。

当检测到副本数不足的数据块时,该块会被复制直到达到最小副本数 。

程序使用Data类模拟数据块,Namenode类作为namenode节点,Datanode类作为datanode数据节点。程序如下:

Data类

public class Data {
	private int id;
	private String msg;

	public Data(int id, String msg) {
		this.id = id;
		this.msg = msg;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}

Datanode类

import java.util.ArrayList;
import java.util.List;

public class Datanode {
	private Namenode namenode;
	private String name;
	private List<Data> datas = new ArrayList<Data>();

	public Datanode(Namenode namenode, String name) {
		this.namenode = namenode;
		this.name = name;
	}

	public Namenode getNamenode() {
		return namenode;
	}

	public void setNamenode(Namenode namenode) {
		this.namenode = namenode;
	}

	public List<Data> getDatas() {
		return datas;
	}

	public void setDatas(List<Data> datas) {
		this.datas = datas;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Namenode类

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

public class Namenode {
	private int replicaion = 3; // 复制因子
	private double safeRatio = 0.6; // 安全数据块的比例,大于此值可以启动集群
	private List<Integer> metaData = new ArrayList<Integer>(); // 存放元数据
	private List<Datanode> datanodes = new ArrayList<Datanode>();

	public void putMetaData(int id) {
		if (!metaData.contains(id)) {
			metaData.add(id);
		}
	}

	public static void main(String[] args) {
		Namenode namenode = new Namenode();
		System.out.println("*********启动后看下各个节点中的数据块情况*********");
		for (int i = 0; i < namenode.getDatanodes().size(); i++) {
			System.out.println(namenode.getDatanodes().get(i).getName() + ":");
			for (int j = 0; j < namenode.getDatanodes().get(i).getDatas()
					.size(); j++) {
				System.out.print(namenode.getDatanodes().get(i).getDatas()
						.get(j).getMsg()
						+ "  ");
			}
			System.out.println();
		}
	}

	private void init() {
		Datanode datanode1 = new Datanode(this, "datanode1");
		Datanode datanode2 = new Datanode(this, "datanode2");
		Data data1 = new Data(1, "data1");
		Data data2 = new Data(2, "data2");
		Data data3 = new Data(3, "data3");
		Data data4 = new Data(4, "data4");
		datanode1.getDatas().add(data1);
		datanode1.getDatas().add(data2);
		datanode1.getDatas().add(data3);
		datanode1.getDatas().add(data4);

		//让datanode2故意少几个数据块,看最后是否被复制了
		datanode2.getDatas().add(data1);	
		datanode2.getDatas().add(data3);

		datanodes.add(datanode1);
		datanodes.add(datanode2);
		initMetaData();
	}

	private void initMetaData() {
		for (int i = 0; i < datanodes.size(); i++) {
			for (int j = 0; j < datanodes.get(i).getDatas().size(); j++) {
				int id = datanodes.get(i).getDatas().get(j).getId();
				datanodes.get(i).getNamenode().putMetaData(id);
			}
		}
	}

	public Namenode() {
		init();
		safeMode(); // 先进入安全模式,然后启动
		start();
	}

	private void start() {
		System.out.println("hadoop started successfully...");
	}

	// 检查数据是否安全,有两个条件:
	// 1.数据块在集群中的个数不小于replication的值,这时是安全的数据块
	// 2.安全数据块的比例不小于safeRatio,则集群是安全的
	private void safeMode() {
		System.out.println("enter safe mode...");
		System.out.println("check data safe...");

		// 拿到数据数量的map,然后输出
		Map<Integer, Integer> dataFrequency = dataFre();
		for (Integer keys : dataFrequency.keySet()) {
			System.out.println("keys: " + keys + " frequency: "
					+ dataFrequency.get(keys));
		}

		// 将不安全的数据块记录到栈中
		Stack<Integer> unsafeData = new Stack<Integer>();
		for (Integer keys : dataFrequency.keySet()) {
			if (dataFrequency.get(keys) < replicaion) {
				System.out.println("the data" + keys + " is not safe");
				unsafeData.push(keys);
			}
		}

		// 只要数据块安全的比例小于safeRatio,就不停的复制
		while ((1 - (double) unsafeData.size() / dataFrequency.size()) < safeRatio
				&& unsafeData.size() >= 0) {
			System.out.println("copying data" + unsafeData.peek());
			while (dataFrequency.get(unsafeData.peek()) < replicaion) {
				// 将数据块尽量复制到不同的节点,若所有节点节点都有这个数据块,还是达不到
				// 复制因子的要求,就将它复制到datanodes中第一个节点上
				if (destinaton(unsafeData.peek()) != null) {
					destinaton(unsafeData.peek()).getDatas().add(
							new Data(unsafeData.peek(), message(unsafeData
									.peek())));
					int fre = dataFrequency.get(unsafeData.peek()) + 1;
					dataFrequency.put(unsafeData.peek(), fre);
				} else {
					datanodes
							.get(0)
							.getDatas()
							.add(new Data(unsafeData.peek(), message(unsafeData
									.peek())));
					int fre = dataFrequency.get(unsafeData.peek()) + 1;
					dataFrequency.put(unsafeData.peek(), fre);
				}
			}

			System.out.println("data" + unsafeData.pop()
					+ " has copyed successfully");
		}
		System.out.println("the cluster is safe");
		System.out.println("leave safe mode");

	}

	/**
	 * 获得一个id数据的msg信息
	 * 
	 * @param peek
	 *            数据块的id
	 * @return 返回它的msg信息
	 */
	private String message(Integer peek) {
		for (int i = 0; i < datanodes.size(); i++) {
			for (int j = 0; j < datanodes.get(i).getDatas().size(); j++) {
				if (peek == datanodes.get(i).getDatas().get(j).getId()) {
					return datanodes.get(i).getDatas().get(j).getMsg();
				}
			}
		}
		return null;
	}

	/**
	 * 决定数据块复制的目的地
	 * 
	 * @param peek
	 *            数据块的id
	 * @return 返回目的地
	 */
	private Datanode destinaton(Integer peek) {
		for (int i = 0; i < datanodes.size(); i++) {
			if (!isInNode(datanodes.get(i), peek)) {
				return datanodes.get(i);
			}
		}
		return null;
	}

	private boolean isInNode(Datanode datanode, Integer peek) {
		for (int i = 0; i < datanode.getDatas().size(); i++) {
			if (peek == datanode.getDatas().get(i).getId()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 计算每个数据块的在集群中的数量
	 * 
	 * @return 返回map的键为数据块的id,值为它的数量
	 */
	public Map<Integer, Integer> dataFre() {
		Map<Integer, Integer> dataFrequency = new HashMap<Integer, Integer>();
		for (int i = 0; i < metaData.size(); i++) {
			for (int j = 0; j < datanodes.size(); j++) {
				for (int k = 0; k < datanodes.get(j).getDatas().size(); k++) {
					if (metaData.get(i) == datanodes.get(j).getDatas().get(k)
							.getId()) {
						if (!dataFrequency.containsKey(metaData.get(i))) {
							dataFrequency.put(metaData.get(i), 1);
						} else {
							int fre = dataFrequency.get(metaData.get(i)) + 1;
							dataFrequency.put(metaData.get(i), fre);
						}
					}
				}
			}
		}
		return dataFrequency;
	}

	public List<Integer> getMetaData() {
		return metaData;
	}

	public void setMetaData(List<Integer> metaData) {
		this.metaData = metaData;
	}

	public List<Datanode> getDatanodes() {
		return datanodes;
	}

	public void setDatanodes(List<Datanode> datanodes) {
		this.datanodes = datanodes;
	}
}

在最小复制副本数为 2,安全的比例为0.8的情况下,运行截图如下,可以看到启动后datanode2节点中缺少的数据被复制了


若改最小副本数量为3,安全比例为0.8的情况下,根据程序会先将数据块复制到没有该数据块的节点上,若每个节点都有这个数据块还是达不到复制因子的要求时,会复制到datanodes中第一个节点中(这里是datanode1),因为这里的安全比例为0.8,四个数据块必须都是安全的,每个数据块的最小副本数量都应该不小于3,运行的截图如下:


若把最小副本数3保持不变,安全数据块的比例降到0.7,那么四个数据块中只要有三个是安全的就可以了。运行的截图如下,可以看到这里只复制了三个数据块,data1数据还是不安全的,但是不影响集群启动。




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值