大数据 第六章 zookeeper实现系统的高可用

zookeeper实现Hadoop的HA高可用

高可用的原理

hadoop中的namenode如果是单节点,那么就不满足高可用。实际设置为两个节点,其中一个为active状态,另一个为stand by,前者挂了,后者就把状态改为active,给客户端提供服务。那么两个节点之间需要有公共日志记录,stand by节点转变为active节点时,就把公共日志中的内容更新到数据中。那么公共服务日志中的节点也得是高可用的,就可以通过选举的方式来决定谁是leader。这就要引入zookeeper了。

zookeeper原理

1.可以创建节点,每个节点可以保存少量的数据。
2.如果节点发生了改变,能够通知到客户端。
基于这两点就可以为各种客户端实现高可用。

zookeeper本来就是高可用的,一般会部署奇数台机器,每个节点都是通过选举来寻找leader的。
5台机器为例,选举过程:3888端口用来选举通讯,每个节点都有自己的myid,刚开始第一台机器投自己myid1,第二台机器投自己myid2,这时候第一个节点会发现第二台机器的myid比自己大,所以会把自己的票给到第二台。第三台启动之后,会投自己,前两台的投票也会改成3 ,至此,3号机器的票数超过了半数,成为leader节点。4,5号机器发现有leader节点了,就不再投票了。其他节点自动变为follower节点。

zokeeper节点类型

zokeeper监听节点,可以监听数据的变化,还可以监听目录的变化
节点类型可分为,临时的和持久的,是否带序号。
临时的节点如果客户端断开了连接,那么创建的这个节点就删除了。
带序号的话,新增的节点后面会拼接00000001,序号是递增的。

利用zookeeper开发分布式应用系统

原理:生产者每次上线都在zk上注册一个带序号的临时节点,消费者每次启动都去zk上查询在线的生产者列表,并且对父节点注册监听,监听子节点的变化。每次生产者有上线或者下线的变化,消费者都能及时感知,重新去拉去生产者的列表。

代码展示

public class Consumer {

	// 定义一个list用于存放最新的在线服务器列表
	private volatile ArrayList<String> onlineServers = new ArrayList<>();

	// 构造zk连接对象
	ZooKeeper zk = null;

	// 构造zk客户端连接
	public void connectZK() throws Exception {

		zk = new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged) {

					try {
						// 事件回调逻辑中,再次查询zk上的在线服务器节点即可,查询逻辑中又再次注册了子节点变化事件监听
						getOnlineServers();
					} catch (Exception e) {
						e.printStackTrace();
					}

				}

			}
		});

	}

	// 查询在线服务器列表
	public void getOnlineServers() throws Exception {

		List<String> children = zk.getChildren("/servers", true);
		ArrayList<String> servers = new ArrayList<>();

		for (String child : children) {
			byte[] data = zk.getData("/servers/" + child, false, null);

			String serverInfo = new String(data);

			servers.add(serverInfo);
		}

		onlineServers = servers;
		System.out.println("查询了一次zk,当前在线的服务器有:" + servers);

	}

	public void sendRequest() throws Exception {
		Random random = new Random();
		while (true) {
			try {
				// 挑选一台当前在线的服务器
				int nextInt = random.nextInt(onlineServers.size());
				String server = onlineServers.get(nextInt);
				String hostname = server.split(":")[0];
				int port = Integer.parseInt(server.split(":")[1]);

				System.out.println("本次请求挑选的服务器为:" + server);

				Socket socket = new Socket(hostname, port);
				OutputStream out = socket.getOutputStream();
				InputStream in = socket.getInputStream();

				out.write("haha".getBytes());
				out.flush();

				byte[] buf = new byte[256];
				int read = in.read(buf);
				System.out.println("服务器响应的时间为:" + new String(buf, 0, read));

				out.close();
				in.close();
				socket.close();

				Thread.sleep(2000);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}

	public static void main(String[] args) throws Exception {

		Consumer consumer = new Consumer();
		// 构造zk连接对象
		consumer.connectZK();

		// 查询在线服务器列表
		consumer.getOnlineServers();

		// 处理业务(向一台服务器发送时间查询请求)
		consumer.sendRequest();

	}

}

public class TimeQueryServer {
	ZooKeeper zk = null;
	
	// 构造zk客户端连接
	public void connectZK() throws Exception{
		
		zk = new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, null);
		
		
	}
	
	
	
	// 注册服务器信息
	public void registerServerInfo(String hostname,String port) throws Exception{
		
		/**
		 * 先判断注册节点的父节点是否存在,如果不存在,则创建
		 */
		Stat stat = zk.exists("/servers", false);
		if(stat==null){
			zk.create("/servers", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		}
		
		// 注册服务器数据到zk的约定注册节点下
		String create = zk.create("/servers/server", (hostname+":"+port).getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
		
		System.out.println(hostname+" 服务器向zk注册信息成功,注册的节点为:" + create);
		
	}
	
	
	
	public static void main(String[] args) throws Exception {
		
		TimeQueryServer timeQueryServer = new TimeQueryServer();
		
		// 构造zk客户端连接
		timeQueryServer.connectZK();
		
		// 注册服务器信息
		timeQueryServer.registerServerInfo(args[0], args[1]);
		
		// 启动业务线程开始处理业务
		new TimeQueryService(Integer.parseInt(args[1])).start();
		
	}
	

}

public class Consumer {

	// 定义一个list用于存放最新的在线服务器列表
	private volatile ArrayList<String> onlineServers = new ArrayList<>();

	// 构造zk连接对象
	ZooKeeper zk = null;

	// 构造zk客户端连接
	public void connectZK() throws Exception {

		zk = new ZooKeeper("hdp-01:2181,hdp-02:2181,hdp-03:2181", 2000, new Watcher() {

			@Override
			public void process(WatchedEvent event) {
				if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeChildrenChanged) {

					try {
						// 事件回调逻辑中,再次查询zk上的在线服务器节点即可,查询逻辑中又再次注册了子节点变化事件监听
						getOnlineServers();
					} catch (Exception e) {
						e.printStackTrace();
					}

				}

			}
		});

	}

	// 查询在线服务器列表
	public void getOnlineServers() throws Exception {

		List<String> children = zk.getChildren("/servers", true);
		ArrayList<String> servers = new ArrayList<>();

		for (String child : children) {
			byte[] data = zk.getData("/servers/" + child, false, null);

			String serverInfo = new String(data);

			servers.add(serverInfo);
		}

		onlineServers = servers;
		System.out.println("查询了一次zk,当前在线的服务器有:" + servers);

	}

	public void sendRequest() throws Exception {
		Random random = new Random();
		while (true) {
			try {
				// 挑选一台当前在线的服务器
				int nextInt = random.nextInt(onlineServers.size());
				String server = onlineServers.get(nextInt);
				String hostname = server.split(":")[0];
				int port = Integer.parseInt(server.split(":")[1]);

				System.out.println("本次请求挑选的服务器为:" + server);

				Socket socket = new Socket(hostname, port);
				OutputStream out = socket.getOutputStream();
				InputStream in = socket.getInputStream();

				out.write("haha".getBytes());
				out.flush();

				byte[] buf = new byte[256];
				int read = in.read(buf);
				System.out.println("服务器响应的时间为:" + new String(buf, 0, read));

				out.close();
				in.close();
				socket.close();

				Thread.sleep(2000);
			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}

	public static void main(String[] args) throws Exception {

		Consumer consumer = new Consumer();
		// 构造zk连接对象
		consumer.connectZK();

		// 查询在线服务器列表
		consumer.getOnlineServers();

		// 处理业务(向一台服务器发送时间查询请求)
		consumer.sendRequest();

	}

}

hadoop利用zk实现高可用

在这里插入图片描述
在节点从stand by状态改为active状态时,为防止脑裂的发生,即acvive节点并不是真正地挂了,会发送ssh kill命令,如果没响应再发送ssh脚本,强行让原节点停止,之后才会安心地转为active节点。
yarn的节点转化会简单一些,因为不存在数据的同步问题。
Paxos协议可以参考:https://blog.csdn.net/asmfeng2/article/details/132851195

hadoop高可用系统搭建

搭建过程略过
在HA环境下使用hdfs时,需要将hadoop集群的配置信息放到系统classpath中,这样才能正常使用集群版。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值