Zookeeper实现负载均衡原理
先玩个正常的,好玩的socket编程:
服务端:
首先公共的这个Handler:
package com.toov5.zkDubbo; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket; 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;
}
}
}
}
package com.toov5.zkDubbo; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; import org.I0Itec.zkclient.ZkClient; //##ServerScoekt服务端
public class ZkServerScoekt implements Runnable {
private static int port = 18080; //socket 服务启动后的所使用的 端口号 public static void main(String[] args) throws IOException {
ZkServerScoekt server = new ZkServerScoekt(port); //构造函数传入port
// regServer(); //去zk注册
Thread thread = new Thread(server);
thread.start();
} public ZkServerScoekt(int port) {
this.port = port;
}
// //注册服务
// public static void regServer(){
// //1、建立zk连接
// ZkClient zkClient = new ZkClient("192.168.91.5",5000,10000);
// //2.先创建父节点
// String root = "/toov5";
// if (!zkClient.exists(root)) {
// //如果父节点不存,直接创建父节点
// zkClient.createPersistent(root); //持久节点
// }
// //3、创建子节点
// String nodeName = root+"/service_"+port;
// String nodeValue="127.0.0.1:"+port;
// if (zkClient.exists(nodeName)) { //如果存在 直接删除掉
// zkClient.delete(nodeName);
// }
// zkClient.createEphemeral(nodeName); //字节的 临时节点 如果服务宕机了 找不到了就
// System.out.println("服务注册成功"+nodeName);
//
// }
//
// 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) { }
}
} }
客户端:
package com.toov5.zkDubbo; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; 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"); //连接服务 放到list中 存放集群地址 做负载均衡用的
} // 获取当前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();
}
}
}
}
}
运行结果:

引申思路
使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点。客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器。

1、会员服务 项目启动时候 会在zk上面创建临时节点 /toov5 对应的value是127.0.0.1
如果是集群 /toov5 下面会会以 节点形式存储 节点名字就是IP+端口 value 分别也是 IP+端口 有些是没有用到value的哦
2、订单直接去使用 /toov5 查询下面的子节点信息,获取到之后。在本地使用负载均衡算法实现调用,决定使用哪个。
127.0.0.1:8080
127.0.0.1:8081
PS: 任何服务的底层都是 socke 技术
socket客户端 ( 客户端去获取注册信息) socket服务器端
废话不多说,项目:
<dependencies>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.8</version>
</dependency>
</dependencies>
这个不是Apache的哦注意
服务端代码:
package com.toov5.zkDubbo; import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket; import org.I0Itec.zkclient.ZkClient; //##ServerScoekt服务端
public class ZkServerScoekt implements Runnable {
private static int port = 18081; //socket 服务启动后的所使用的 端口号 public static void main(String[] args) throws IOException {
ZkServerScoekt server = new ZkServerScoekt(port); //构造函数传入port
regServer(); //去zk注册
Thread thread = new Thread(server);
thread.start();
} public ZkServerScoekt(int port) {
this.port = port;
}
//注册服务
public static void regServer(){
//1、建立zk连接
ZkClient zkClient = new ZkClient("192.168.91.5",5000,10000);
//2.先创建父节点
String root = "/toov5";
if (!zkClient.exists(root)) {
//如果父节点不存,直接创建父节点
zkClient.createPersistent(root); //持久节点
}
//3、创建子节点
String nodeName = root+"/service_"+port;
String nodeValue="127.0.0.1:"+port;
if (zkClient.exists(nodeName)) { //如果存在 直接删除掉
zkClient.delete(nodeName);
}
zkClient.createEphemeral(nodeName); //字节的 临时节点 如果服务宕机了 找不到了就
System.out.println("服务注册成功"+nodeName); } 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) { }
}
} }
客户端代码:
package com.toov5.zkDubbo; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; 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"); //连接服务 放到list中 存放集群地址 做负载均衡用的
} // 获取当前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();
}
}
}
}
}

启动服务端后的结果:
可以看到 去zk注册了信息。服务的名字 和子节点
其中子节点是 临时节点 相当于如果服务宕机了 就查不到了哦

启动三次服务端后:

然后 去zk读取节点信息:
客户端 负载均衡轮训算法
请求次数 % 服务端数 = 服务器端口号的奇数偶数
客户端:
package com.toov5.zkDubbo; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List; import org.I0Itec.zkclient.ZkClient; 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"); //连接服务 放到list中 存放集群地址 做负载均衡用的
//建立zk连接
ZkClient zkClient = new ZkClient("192.168.91.5",5000,10000);
//读取父节点信息
String root = "/toov5";
List<String> children=zkClient.getChildren(root);
for(String pString : children){
//父+子 =完整的路径
String path = root+"/"+pString;
String nodeValue =zkClient.readData(path);
//把值放到集合中去
listServer.add(nodeValue);
}
//服务发现成功
System.out.println("服务发现:"+listServer.toString());
//然后给 serverCount赋值
serverCount=listServer.size(); } //请求总数
private static int reqCount = 1;
//服务个数
private static int serverCount = 0; //初始值是0 // 获取当前server信息
public static String getServer() {
// return listServer.get(0); 不能写死 本地负载均衡轮询算法
String serverName = listServer.get(reqCount%serverCount );
System.out.println("客户端请求次数:"+reqCount+"对应服务器"+serverName);
reqCount++;
return serverName;
} 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实现负载均衡原理的更多相关文章
- 使用Zookeeper实现负载均衡原理
思路 使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点.客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器. 创建项目工程 M ...
- 【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资源管理器 ...
随机推荐
- HDU 4081 Qin Shi Huang's National Road System 最小生成树+倍增求LCA
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 Qin Shi Huang's National Road System Time Limit: ...
- Usaco_Contest_2013_Open_Bovine Problem 1. Bovine Ballet
Problem 1: Bovine Ballet [Brian Dean, 2013] In an attempt to challenge the stereotypical perception ...
- open-falcon的邮件报警
mail-provider提供http邮件服务,和邮件服务器打通 falcon-sender 负责收集falcon的邮件,然后通过mail-provider发送出去 mail-provider 把sm ...
- Activiti 流程部署方式 activi 动态部署(高级源代码篇)
Activiti的流程 部署方式有非常多种方式,我们能够依据activit工作流引擎提供的ap方式进行部署. 当然了实际需求决定你要使用哪一种api操作,后面的总结具体介绍了使用场景. 以下看一下部署 ...
- ActiveX控件打包成Cab置于网页中自动下载安装 [转]
http://blog.sina.com.cn/s/blog_520c32270100nopj.html 做过ActiveX控件的朋友都知道,要想把自己做的ActiveX控件功能放在自己的网页上使用, ...
- 解题报告 之 HDU5288 OO' s Sequence
解题报告 之 HDU5288 OO' s Sequence Description OO has got a array A of size n ,defined a function f(l,r) ...
- 教你使用 Reflexil 反编译.NET
简介 反编译的方式有很多种,其实最靠谱的还是IL反编译. 如果不懂IL可以尝试我这边文章入门:http://www.wxzzz.com/278.html 不过我下面要说的不是IL这种底层的代码反编译, ...
- 网页编程-Django(一)
业内: GET:获取数据 POST:提交数据 上传单个数据: request.POST.get(‘’name名‘’) 上传多选数据: request.POST.getlist('name名') 上传文 ...
- gdb调试段错误及使用
在编程调试中,经常出现段错误,此时可用gdb调试.具体方法为注册段错误信号处理函数,在处理函数中启动gdb.具体代码如下: void segv_handler(int no) { ]; ]; FILE ...
- 第 1 章 第 2 题 空间敏感排序问题 位向量实现( bitset位向量 )
问题分析 在上篇文章中,给出了使用C语言中经典位运算符来实现位向量的方法.而本文,将介绍使用C++中的bitset容器来实现位向量的方法. 实现 // 请包含bitset头文件 #include &l ...