使用Zookeeper实现负载均衡原理
思路
使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点。客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器。
创建项目工程
Maven依赖
- <dependencies>
- <dependency>
- <groupId>com.101tec</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.8</version>
- </dependency>
- </dependencies>
创建Server服务端
ZkServerScoekt服务
- //##ServerScoekt服务端
- public class ZkServerScoekt implements Runnable {
- private int port = 18080;
- public static void main(String[] args) throws IOException {
- int port = 18080;
- ZkServerScoekt server = new ZkServerScoekt(port);
- Thread thread = new Thread(server);
- thread.start();
- }
- public ZkServerScoekt(int port) {
- this.port = port;
- }
- public void run() {
- ServerSocket serverSocket = null;
- try {
- serverSocket = new ServerSocket(port);
- System.out.println("Server start port:" + port);
- Socket socket = null;
- while (true) {
- socket = serverSocket.accept();
- new Thread(new ServerHandler(socket)).start();
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- if (serverSocket != null) {
- serverSocket.close();
- }
- } catch (Exception e2) {
- }
- }
- }
- }
ZkServerClient
- public class ZkServerClient {
- public static List<String> listServer = new ArrayList<String>();
- public static void main(String[] args) {
- initServer();
- ZkServerClient client= new ZkServerClient();
- BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
- while (true) {
- String name;
- try {
- name = console.readLine();
- if ("exit".equals(name)) {
- System.exit(0);
- }
- client.send(name);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- // 注册所有server
- public static void initServer() {
- listServer.clear();
- listServer.add("127.0.0.1:18080");
- }
- // 获取当前server信息
- public static String getServer() {
- return listServer.get(0);
- }
- public void send(String name) {
- String server = ZkServerClient.getServer();
- String[] cfg = server.split(":");
- Socket socket = null;
- BufferedReader in = null;
- PrintWriter out = null;
- try {
- socket = new Socket(cfg[0], Integer.parseInt(cfg[1]));
- in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- out = new PrintWriter(socket.getOutputStream(), true);
- out.println(name);
- while (true) {
- String resp = in.readLine();
- if (resp == null)
- break;
- else if (resp.length() > 0) {
- System.out.println("Receive : " + resp);
- break;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
ServerHandler
- public class ServerHandler implements Runnable {
- private Socket socket;
- public ServerHandler(Socket socket) {
- this.socket = socket;
- }
- public void run() {
- BufferedReader in = null;
- PrintWriter out = null;
- try {
- in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
- out = new PrintWriter(this.socket.getOutputStream(), true);
- String body = null;
- while (true) {
- body = in.readLine();
- if (body == null)
- break;
- System.out.println("Receive : " + body);
- out.println("Hello, " + body);
- }
- } catch (Exception e) {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- if (out != null) {
- out.close();
- }
- if (this.socket != null) {
- try {
- this.socket.close();
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- this.socket = null;
- }
- }
- }
- }
改造ZkServerScoekt
- public class ZkServerScoekt implements Runnable {
- private static int port = 18081;
- public static void main(String[] args) throws IOException {
- ZkServerScoekt server = new ZkServerScoekt(port);
- Thread thread = new Thread(server);
- thread.start();
- }
- public ZkServerScoekt(int port) {
- this.port = port;
- }
- public void regServer() {
- // 向ZooKeeper注册当前服务器
- ZkClient client = new ZkClient("127.0.0.1:2181", 60000, 1000);
- String path = "/test/server" + port;
- if (client.exists(path))
- client.delete(path);
- client.createEphemeral(path, "127.0.0.1:" + port);
- }
- public void run() {
- ServerSocket serverSocket = null;
- try {
- serverSocket = new ServerSocket(port);
- regServer();
- System.out.println("Server start port:" + port);
- Socket socket = null;
- while (true) {
- socket = serverSocket.accept();
- new Thread(new ServerHandler(socket)).start();
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- if (serverSocket != null) {
- serverSocket.close();
- }
- } catch (Exception e2) {
- }
- }
- }
- }
改造ZkServerClientScoekt
- public class ZkServerClient {
- public static List<String> listServer = new ArrayList<String>();
- public static void main(String[] args) {
- initServer();
- ZkServerClient client = new ZkServerClient();
- BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
- while (true) {
- String name;
- try {
- name = console.readLine();
- if ("exit".equals(name)) {
- System.exit(0);
- }
- client.send(name);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- // 注册所有server
- public static void initServer() {
- String path = "/test";
- final ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);
- List<String> children = zkClient.getChildren(path);
- for (String ipServer : children) {
- listServer.add((String) zkClient.readData(path + "/" + ipServer));
- }
- System.out.println("####从注册中心获取服务信息####listServer:" + listServer.toString());
- // 监听事件
- zkClient.subscribeChildChanges(path, new IZkChildListener() {
- public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
- listServer.clear();
- for (String ctPath : currentChilds) {
- listServer.add(zkClient.readData(parentPath) + "/" + ctPath);
- }
- System.out.println("####节点事件监听发生变化### listServer:" + listServer.toString());
- }
- });
- // listServer.clear();
- // listServer.add("127.0.0.1:8080");
- }
- private static int reqestCount = 1;
- // 获取当前server信息
- public static String getServer() {
- int serverCount = listServer.size();
- String serverHost = listServer.get(reqestCount / serverCount);
- reqestCount++;
- return serverHost;
- }
- public void send(String name) {
- String server = ZkServerClient.getServer();
- String[] cfg = server.split(":");
- Socket socket = null;
- BufferedReader in = null;
- PrintWriter out = null;
- try {
- socket = new Socket(cfg[0], Integer.parseInt(cfg[1]));
- in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- out = new PrintWriter(socket.getOutputStream(), true);
- out.println(name);
- while (true) {
- String resp = in.readLine();
- if (resp == null)
- break;
- else if (resp.length() > 0) {
- System.out.println("Receive : " + resp);
- break;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (out != null) {
- out.close();
- }
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (socket != null) {
- try {
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
使用Zookeeper实现选举策略
场景
有一个向外提供的服务,服务必须7*24小时提供服务,不能有单点故障。所以采用集群的方式,采用master、slave的结构。一台主机多台备机。主机向外提供服务,备机负责监听主机的状态,一旦主机宕机,备机要迅速接代主机继续向外提供服务。从备机选择一台作为主机,就是master选举。
原理分析
右边三台主机会尝试创建master节点,谁创建成功了,就是master,向外提供。其他两台就是slave。
所有slave必须关注master的删除事件(临时节点,如果服务器宕机了,Zookeeper会自动把master节点删除)。如果master宕机了,会进行新一轮的master选举。本次我们主要关注master选举,服务注册、发现先不讨论。
使用Zookeeper原理
» 领导者(leader),负责进行投票的发起和决议,更新系统状态
» 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
» Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
» 客户端(client),请求发起方
• Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协
议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者
崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后
,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
• 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(
proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识
leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的
统治时期。低32位用于递增计数。
• 每个Server在工作过程中有三种状态:
LOOKING:当前Server不知道leader是谁,正在搜寻
LEADING:当前Server即为选举出来的leader
FOLLOWING:leader已经选举出来,当前Server与之同步
使用Zookeeper实现负载均衡原理的更多相关文章
- Zookeeper实现负载均衡原理
先玩个正常的,好玩的socket编程: 服务端: 首先公共的这个Handler: package com.toov5.zkDubbo; import java.io.BufferedReader; i ...
- 【Zookeeper】实现负载均衡原理
一.思路 使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点.客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器. 服务端启动的 ...
- 六大Web负载均衡原理与实现
还有个姊妹篇也可以参考这个文章:LVS(Linus Virtual Server):三种负载均衡方式比较+另三种负载均衡方式, LVS 实现了负载均衡,NAT,DR,TUN zookeeper使用ZA ...
- Nginx 负载均衡原理简介与负载均衡配置详解
Nginx负载均衡原理简介与负载均衡配置详解 by:授客 QQ:1033553122 测试环境 nginx-1.10.0 负载均衡原理 客户端向反向代理发送请求,接着反向代理根据某种负载机制 ...
- 搞懂分布式技术9:Nginx负载均衡原理与实践
搞懂分布式技术9:Nginx负载均衡原理与实践 本篇摘自<亿级流量网站架构核心技术>第二章 Nginx负载均衡与反向代理 部分内容. 当我们的应用单实例不能支撑用户请求时,此时就需要扩容, ...
- (转)使用LVS实现负载均衡原理及安装配置详解
使用LVS实现负载均衡原理及安装配置详解 原文:https://www.cnblogs.com/liwei0526vip/p/6370103.html
- LVS实现负载均衡原理及安装配置
LVS实现负载均衡原理及安装配置 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F ...
- LVS实现负载均衡原理及安装配置 负载均衡
LVS实现负载均衡原理及安装配置 负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F ...
- 使用ZooKeeper实现软负载均衡(原理)
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,提供的功能包括配置维护.名字服务.分布式同步.组服务等. ZooKeeper会维护一个树形的数据结构,类似于Windows资源管理器 ...
随机推荐
- 【C/C++开发】C++11的模板类型判断——std::is_same和std::decay
C++11的模板类型判断--std::is_same和std::decay 问题提出:有一个模板函数,函数在处理int型和double型时需要进行特殊的处理,那么怎么在编译期知道传入的参数的数据类型是 ...
- Windows Server 2008 R2 IIS7.5配置FTP图文教程
本文为大家分享了IIS 配置FTP 网站的具体过程,供大家参考,具体内容如下 说明:服务器环境是Windows Server 2008 R2,IIS7.5. 1. 在 服务器管理器的Web服务器(II ...
- POJ 2386 DFS深搜入门
题目链接 Time Limit: 1000MS Memory Limit: 65536K Description Due to recent rains, water has pooled in va ...
- 使用IDEA的maven工程导入ojdbc14 jar包失败
原因:ojdbc是要收费的所以maven无法通过中央仓库下载. 一开始以为是我网络不好,导致下载一直失败,可是我怎么想都不对劲,因为我自己使用了阿里云的镜像,网络不可能有问题吧,于是又使用外网,重新导 ...
- 【数据结构】11.java源码关于TreeMap
目录 1.TreehMap的内部结构 2.TreehMap构造函数 3.元素新增策略 4.元素删除 5.元素修改和查找 6.特殊操作 7.扩容 8.总结 1.TreeMap的内部结构 首先确认一点,t ...
- 怎么删除json 键值对
var obj = { 'id': 1, 'name': 2 } delete obj.id delete obj['id'] console.log(obj) //{ 'name': 2 }
- Java 函数式编程和Lambda表达式
1.Java 8最重要的新特性 Lambda表达式.接口改进(默认方法)和批数据处理. 2.函数式编程 本质上来说,编程关注两个维度:数据和数据上的操作. 面向对象的编程泛型强调让操作围绕数据,这样可 ...
- JavaScript 的 深拷贝和浅拷贝
深拷贝和浅拷贝都是针对的引用类型, JS中的变量类型分为值类型(基本类型)和引用类型: 对值类型进行复制操作会对值进行一份拷贝,而对引用类型赋值,则会对地址进行拷贝,最终两个变量指向同一份数据 一.先 ...
- mPass多租户系统微服务开发平台
目录 项目总体架构图 基于SpringBoot2.x.SpringCloud并采用前后端分离的企业级微服务,多租户系统架构微服务开发平台 mPaaS(Microservice PaaS)为租户业务开发 ...
- Java字节码扩展
异常表 代码一: public class Test03 { public void test() { try { InputStream is = new FileInputStream(" ...