使用zookeeper实现集群和负载均衡

package com.bubble.cluster;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-10
 */
public class Client extends ClusterClient {
	private static String appServer;
	private static String zkServer = "127.0.0.1:2181";
	private static ClientBootstrap bootstrap;
	private static Client client;

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

		ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
		bootstrap = new ClientBootstrap(factory);
		bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
			public ChannelPipeline getPipeline() {
				ChannelPipeline pipeline = Channels.pipeline();
				pipeline.addLast("encode", new StringEncoder());
				pipeline.addLast("decode", new StringDecoder());
				pipeline.addLast("handler", new DemoHandler());
				return pipeline;
			}
		});
		bootstrap.setOption("tcpNoDelay", true);
		bootstrap.setOption("keepAlive", true);
	    client=new Client();
	    ZkClient zkClient = new ZkClient(zkServer);
		client.connect(zkClient);
		
		client.failOver();
	}

	@Override
	public void connect(ZkClient zkClient) {
		while (true) {
			try {
				RoundRobinLoadBalance loadBlance = new RoundRobinLoadBalance();
				//loadBlance.SetClient("127.0.0.1:"+new Random().nextInt(1000));
				String server = loadBlance.select(zkServer);
				if (server != null) {
					String ip = server.split(":")[0];
					int port = Integer.parseInt(server.split(":")[1]);
					appServer = server;
					System.out.println(server);
					bootstrap.connect(new InetSocketAddress(ip, port));
					
					client.setZkClient(zkClient);
					client.join( "127.0.0.1:"+new Random().nextInt(5000));
					ZookeeperConnStatistic.incrementConn(zkServer, appServer);
					break;
				}
				Thread.sleep(1000);

			} catch (Exception e) {
				e.printStackTrace();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {

				}
				connect(zkClient);
			}
		}

	}
package com.bubble.cluster;

import java.util.List;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public abstract class ClusterClient {
	public abstract void connect(ZkClient zkClient);
	public abstract String getAPPServer();
	public void setZkClient(ZkClient zkClient){
		this.zkClient=zkClient;
	}
    private ZkClient zkClient;

	public void failOver() {
		zkClient.subscribeChildChanges(Constant.root, new IZkChildListener() {
			@Override
			public void handleChildChange(String parentPath, List currentChilds) throws Exception {
				boolean has = false;
				for (int i = 0; i < currentChilds.size(); i++) {
					if (getAPPServer().equals(currentChilds.get(i))) {
						has = true;
						break;
					}
				}
				if (!has) {
					connect(zkClient);
				}
			}
		});
	}
	
	public void join(String client){
		if(!zkClient.exists(Constant.client)){
			zkClient.createPersistent(Constant.client);
		}
		if(!zkClient.exists(Constant.client+"/"+client)){
			zkClient.createEphemeral(Constant.client+"/"+client);
		}
	}
	
	public void leave(String client){		
		if(zkClient.exists(Constant.client+"/"+client)){
			zkClient.delete(Constant.client+"/"+client);
		}
		zkClient.close();
	}
}

package com.bubble.cluster;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class ConsistentHashLoadBalance implements LoadBlance {
	private String client;
	
	public void SetClient(String client){
		this.client=client;
	}
	
	@Override
	public String select(String zkServer) {
		ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);
		ConsistentHashSelector selector=new ConsistentHashSelector(client,serverList);
		return selector.select();
		
	}
	
	 private static final class ConsistentHashSelector {
		 	public ConsistentHashSelector(String client,List<String> appServer){
		 		this.client=client;
		 		this.appServer=appServer;
		 	}
		 
		 	private String client;
		 	private List<String> appServer;
		 	
	        public String select() {
	            String key =client ;
	            byte[] digest = md5(key);
	            String server =appServer.get((int) hash(digest, 0));
	            return server;
	        }

	        private long hash(byte[] digest, int number) {
	            return (((long) (digest[3 + number * 4] & 0xFF) << 24)
	                    | ((long) (digest[2 + number * 4] & 0xFF) << 16)
	                    | ((long) (digest[1 + number * 4] & 0xFF) << 8) 
	                    | (digest[0 + number * 4] & 0xFF)) 
	                    & 0xFFFFFFFFL;
	        }

	        private byte[] md5(String value) {
	            MessageDigest md5;
	            try {
	                md5 = MessageDigest.getInstance("MD5");
	            } catch (NoSuchAlgorithmException e) {
	                throw new IllegalStateException(e.getMessage(), e);
	            }
	            md5.reset();
	            byte[] bytes = null;
	            try {
	                bytes = value.getBytes("UTF-8");
	            } catch (UnsupportedEncodingException e) {
	                throw new IllegalStateException(e.getMessage(), e);
	            }
	            md5.update(bytes);
	            return md5.digest();
	        }

	    }

}

package com.bubble.cluster;
/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class Constant {
	public static final String root="/cluster";
	public static final String round="/round";
	public static final String client="/client";
	public static final String route="/route";
}

package com.bubble.cluster;

import java.util.Date;

import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-10
 */
public class DemoHandler extends SimpleChannelUpstreamHandler {

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
		Thread.sleep(5000);
		System.out.println(e.getMessage());
		ctx.getChannel().write("bbb");
	}
	@Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
        e.getChannel().write("abcd");
    }


}

package com.bubble.cluster;

import java.util.List;

import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class LeastActiveLoadBalance implements LoadBlance {

	@Override
	public String select(String zkServer) {
		ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);

		String tempServer = null;
		int tempConn = -1;
		for (int i = 0; i < serverList.size(); i++) {
			String server = serverList.get(i);
			if (zkClient.readData(Constant.root + "/" + server) != null) {
				int connNum = zkClient.readData(Constant.root + "/" + server);
				if (tempConn == -1) {
					tempServer = server;
					tempConn = connNum;
				}
				if (connNum < tempConn) {
					tempServer = server;
					tempConn = connNum;
				}
			}else{
				zkClient.close();
				return server;
			}
		}
		zkClient.close();
		if (tempServer != null && !tempServer.equals("")) {
			return tempServer;
		}

		return null;
	}

}

package com.bubble.cluster;

import java.util.List;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public interface LoadBlance {
	String select(String zkServer);
}

package com.bubble.cluster;

import java.util.List;
import java.util.Random;

import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class RandomLoadBalance implements LoadBlance {

	@Override
	public String select(String zkServer) {
	    ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);
		zkClient.close();
		Random r=new Random();
		if(serverList.size()>=1){
			String server=serverList.get(r.nextInt(serverList.size()));
			return server;
		}else{
			return null;
		}
		
	}

}

package com.bubble.cluster;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class RoundRobinLoadBalance implements LoadBlance {
	
	@Override
	public String select(String zkServer) {
		ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);
		int round=0;
		if(!zkClient.exists(Constant.round)){
			zkClient.createPersistent(Constant.round);
			zkClient.writeData(Constant.round, 0);
		}else{
			round=(Integer)zkClient.readData(Constant.round);
			zkClient.writeData(Constant.round, ++round);
		}
		zkClient.close();
		if (serverList != null && serverList.size() > 0) {
			return serverList.get(round % serverList.size());
		} else {
			return null;
		}

	}

}

package com.bubble.cluster;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-10
 */
public class Server {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ChannelFactory factory = new NioServerSocketChannelFactory(
	            Executors.newCachedThreadPool(),
	            Executors.newCachedThreadPool());
	        ServerBootstrap bootstrap = new ServerBootstrap (factory);
	        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
	            public ChannelPipeline getPipeline() {
	                 ChannelPipeline pipeline = Channels.pipeline();
	                pipeline.addLast("encode",new StringEncoder());
	                pipeline.addLast("decode",new StringDecoder());
	                pipeline.addLast("handler",new DemoHandler());
	                return pipeline;
	            }
	        });
	        bootstrap.setOption("child.tcpNoDelay", true);
	        bootstrap.setOption("child.keepAlive", true);
	        bootstrap.bind(new InetSocketAddress(8081));
	        
	        ClusterServer.join("127.0.0.1:8081", "127.0.0.1:2181");
	}

}

package com.bubble.cluster;

import java.util.List;

import org.I0Itec.zkclient.ZkClient;

/**
 * @author hxpwangyi@163.com
 * @date 2013-2-11
 */
public class ZookeeperConnStatistic {
	public static void incrementConn(String zkServer,String appServer){
		ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);
		for(int i=0;i<serverList.size();i++){
			String server=serverList.get(i);
			if(server.equals(appServer)){
				if(zkClient.readData(Constant.root+"/"+appServer)==null){
					zkClient.writeData(Constant.root+"/"+appServer, 1);	
				}else{
					int conn=zkClient.readData(Constant.root+"/"+appServer);
					zkClient.writeData(Constant.root+"/"+appServer, ++conn);
				}
				break;
			}
		}
		zkClient.close();
	}
	
	public static int getNodeConn(String zkServer,String appServer){
		ZkClient zkClient = new ZkClient(zkServer);
		List<String> serverList = zkClient.getChildren(Constant.root);
		for(int i=0;i<serverList.size();i++){
			String server=serverList.get(i);
			if(server.equals(appServer)){
				int conn=zkClient.readData(Constant.root+"/"+appServer);
				zkClient.close();
				return conn;
			}
		}
		zkClient.close();
		return 0;
	}
}

@Overridepublic String getAPPServer() {return appServer;}}


什么是Zookeeper Zookeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以单机模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。 1、Zookeeper是为别的分布式程序服务的 2、Zookeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务) 3、Zookeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统> 一名称服务等 4、虽然说可以提供各种服务,但是zookeeper在底层其实只提供了两个功能: 管理(存储,读取)用户程序提交的数据(类似namenode中存放的metadata);  并为用户程序提供数据节点监听服务; Zookeeper集群机制 Zookeeper集群的角色: Leader 和 follower  只要集群中有半数以上节点存活,集群就能提供服务 Zookeeper特性 1、Zookeeper:一个leader,多个follower组成的集群 2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的 3、分布式读写,更新请求转发,由leader实施 4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行 5、数据更新原子性,一次数据更新要么成功,要么失败 6、实时性,在一定时间范围内,client能读到最新数据 Zookeeper数据结构 1、层次化的目录结构,命名符合常规文件系统规范(类似文件系统)    2、每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识  3、节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点) 节点类型  a、Znode有两种类型: 短暂(ephemeral)(create -e /app1/test1 “test1” 客户端断开连接zk删除ephemeral类型节点)  持久(persistent) (create -s /app1/test2 “test2” 客户端断开连接zk不删除persistent类型节点) b、Znode有四种形式的目录节点(默认是persistent ) PERSISTENT  PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )  EPHEMERAL  EPHEMERAL_SEQUENTIAL c、创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护          d、在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序 Zookeeper应用场景 数据发布与订阅(配置中心) 发布与订阅模型,即所谓的配置中心,顾名思义就是发布者将数据发布到ZK节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新。例如全局的配置信息,服务式服务框架的服务地址列表等就非常适合使用负载均衡 这里说的负载均衡是指软负载均衡。在分布式环境中,为了保证高可用性,通常同一个应用或同一个服务的提供方都会部署多份,达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑,其中比较典型的是消息中间件中的生产者,消费者负载均衡。 消息中间件中发布者和订阅者的负载均衡,linkedin开源的KafkaMQ和阿里开源的 metaq都是通过zookeeper来做到生产者、消费者的负载均衡。这里以metaq为例如讲下: 生产者负载均衡:metaq发送消息的时候,生产者在发送消息的时候必须选择一台broker上的一个分区来发送消息,因此metaq在运行过程中,会把所有broker和对应的分区信息全部注册到ZK指定节点上,默认的策略是一个依次轮询的过程,生产者在通过ZK获取分区列表之后,会按照brokerId和partition的顺序排列组织成一个有序的分区列表,发送的时候按照从头到尾循环往复的方式选择一个分区来发送消息。 消费负载均衡: 在消费过程中,一个消费者会消费一个或多个分区
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hxpjava1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值