Zookeeper实现软负载均衡轮询和故障转移

使用Zookeeper实现负载均衡原理

思路

使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点。客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器。当其中一台服务宕机后,本地监听节点变化,实现故障转移。

 

创建项目工程

Maven依赖

   <dependencies>

            <dependency>

                  <groupId>com.101tec</groupId>

                  <artifactId>zkclient</artifactId>

                  <version>0.8</version>

            </dependency>

      </dependencies>

 

创建Server服务端

ZkServerScoekt服务

package com.test.zookeeper.loadbalancing;



import org.I0Itec.zkclient.ZkClient;



import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.ServerSocket;

import java.net.Socket;



//##ServerScoekt服务端

public class ZkServerScoekt implements Runnable {

    private int port;



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

   /* ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);

      zkClient.createPersistent("/member");*/

      int port = 18081;

      ZkServerScoekt server = new ZkServerScoekt(port);

      Thread thread = new Thread(server);

      thread.start();

   }



   public ZkServerScoekt(int port) {

      this.port = port;

   }



   // 将服务信息注册到注册中心上去

   public void regServer() {

      ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);

      String path = "/member/server-" + port;

      if (zkClient.exists(path)) {

         zkClient.delete(path);

      }

      String value="127.0.0.1:" + port;

      zkClient.createEphemeral(path, "127.0.0.1:" + port);



      System.out.println("##服务注册成功###"+value);

   }

   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) {



         }

      }

   }



}

 

ZkServerScoekt1服务

 

package com.test.zookeeper.loadbalancing;



import org.I0Itec.zkclient.ZkClient;



import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;



//##ServerScoekt服务端

public class ZkServerScoekt1 implements Runnable {

    private int port=18082;



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

   /* ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);

      zkClient.createPersistent("/member");*/

        ZkServerScoekt1 server = new ZkServerScoekt1();

        Thread thread = new Thread(server);

        thread.start();

    }







    // 将服务信息注册到注册中心上去

    public void regServer() {

        ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);

        String path = "/member/server-" + port;

        if (zkClient.exists(path)) {

            zkClient.delete(path);

        }

        String value="127.0.0.1:" + port;

        zkClient.createEphemeral(path, "127.0.0.1:" + port);

        System.out.println("##服务注册成功###"+value);

    }

    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) {



            }

        }

    }



}

 

 

ServerHandler

 

package com.test.zookeeper.loadbalancing;



import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.PrintWriter;

import java.net.Socket;



//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;

         }

      }

   }

}

 

客户端

ZkServerClient

package com.test.zookeeper.loadbalancing;



import org.I0Itec.zkclient.IZkChildListener;

import org.I0Itec.zkclient.ZkClient;



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();

      // 从zk获取最新获取的注册服务连接

      final String memberServerPath = "/member";

      final ZkClient zkClient = new ZkClient("127.0.0.1:2181", 6000, 1000);

      // 获当前下子节点

      List<String> children = zkClient.getChildren(memberServerPath);

      listServer.clear();

      for (String p : children) {

         // 读取子节点value值

         listServer.add((String) zkClient.readData(memberServerPath + "/" + p));

      }

      System.out.println("最新服务信息listServer:" + listServer.toString());

      // 订阅子节点事件

      zkClient.subscribeChildChanges(memberServerPath, new IZkChildListener() {



         @Override

         public void handleChildChange(String s, List<String> childrens) throws Exception {

            listServer.clear();

            for (String subP : childrens) {

               // 读取子节点value值

               listServer.add((String) zkClient.readData(memberServerPath + "/" + subP));

            }

            System.out.println("节点更改后最新服务信息listServer:" + listServer.toString());

         }

      });

   }



    private static int count=0;



   // 获取当前server信息

   public static String getServer() {

      int serverSize=listServer.size();

      ++count;

      //取模

      return listServer.get(count%serverSize);

   }

   

   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();

            }

         }

      }

   }

}

启动两个服务端和客户端

效果:

负载均衡轮询策略

两个服务端注册到注册中心,客户端通过注册中心获取到服务端

 

通过我们写的代码在下方输入 数据 都会通过取模算法 发送给其中一台服务器,实现了类似nginx轮询的负载均衡策略

客户端发送数据

 

第一台服务端接收到数据

 

再次发送数据

 

第二台服务端接收到数据

 

宕机故障转移

当服务端其中一台宕机后(停止ZkServerScoekt),客户端监听到获取到的节点发送改变,再次发送消息会发给ZkServerScoekt1也就是18082,完成了故障转移

 

 

猜你喜欢

转载自blog.csdn.net/wota5037/article/details/112281105