JAVA实现了一个简单的F5负载均衡功能。

F5负载均衡器非常昂贵,非常不适合小型的创业型公司,这里是一小段纯JAVA代码实现的一个HTTP服务器的负载均衡功能,具有基本的负载均衡功能,够日常使用。

ServerF5.java 

package F5Server;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ServerF5 {

    private int currentIndex = -1;// 最后选择的服务器
    private int currentWeight = 0;// 当前计划权重
    private int maxWeight = 0; // 最大权重
    private int gcdWeight = 0; //所有服务器权重的最大公约数
    private int serverCount = 0; //服务器数量
    private List<Server> serverList; //服务器集合列表
    private static ServerF5 context;


     /**
     * 初始化 F5 上下文
     */
    public static ServerF5 getContext() {
        if (context == null) {
            context = new ServerF5();
        }
        return ServerF5.context;
    }

    /**
     * 返回最大公约数
     */
    private static int gcd(int a, int b) {
        BigInteger b1 = new BigInteger(String.valueOf(a));
        BigInteger b2 = new BigInteger(String.valueOf(b));
        BigInteger gcd = b1.gcd(b2);
        return gcd.intValue();
    }

    /**
     * 返回所有服务器权重的最大公约数
     */
    private static int getGCDForServers(List<Server> serverList) {
        int w = 0;
        if (serverList.size() == 1) {
            w = gcd(w, serverList.get(0).weight);
        }
        for (int i = 0, len = serverList.size(); i < len - 1; i++) {
            if (w == 0) {
                w = gcd(serverList.get(i).weight, serverList.get(i + 1).weight);
            } else {
                w = gcd(w, serverList.get(i + 1).weight);
            }
        }
        return w;
    }

    /**
     * 返回所有服务器中最高的权重。
     */
    public static int getMaxWeightForServers(List<Server> serverList) {
        int w = 0;
        if (serverList.size() == 1) {
            w = Math.max(w, serverList.get(0).weight);
        }
        for (int i = 0, len = serverList.size(); i < len - 1; i++) {
            if (w == 0) {
                w = Math.max(serverList.get(i).weight, serverList.get(i + 1).weight);
            } else {
                w = Math.max(w, serverList.get(i + 1).weight);
            }
        }
        return w;
    }

    /**
     * 算法处理:
      * 假设我们有一组服务器。 S = {S0, S1, …, Sn-1}
      * 有对应的权重,变量currentIndex表示最后选择的服务器。
      * 权重currentWeight初始化为0,currentIndex初始化为-1,第一次返回权重最大的服务器,
      * 找一个合适的服务器返回,不断降低权重,直到轮询结束权重回到0。
     */
    public Server GetServer() {
        while (true) {
            currentIndex = (currentIndex + 1) % serverCount;
            if (currentIndex == 0) {
                currentWeight = currentWeight - gcdWeight;
                if (currentWeight <= 0) {
                    currentWeight = maxWeight;
                    if (currentWeight == 0)
                        return null;
                }
            }
            if (serverList.get(currentIndex).weight >= currentWeight) {
                return serverList.get(currentIndex);
            }
        }
    }

    /*
    * 初始化 URL 列表的 F5 属性。
    * */
    public void init(List list) {
        if (serverList != null) {
            serverList.clear();
        } else {
            serverList = new ArrayList<Server>();
        }
        for (int i = 0; i < list.size(); i++) {
            String url[] = list.get(i).toString().split(":");
            String ip = url[0];
            int port = Integer.parseInt(url[1]);
            Server server = new Server(ip, 1, port);
            serverList.add(server);
        }
        currentIndex = -1;
        currentWeight = 0;
        serverCount = serverList.size();
        maxWeight = getMaxWeightForServers(serverList);
        gcdWeight = getGCDForServers(serverList);
    }


    class Server {
        public String ip;
        public int weight;//当前服务器权重
        public int port;

        public Server(String ip, int weight, int port) {
            super();
            this.ip = ip;
            this.weight = weight;
            this.port = port;
        }

        public String getIp() {
            return ip;
        }

        public void setIp(String ip) {
            this.ip = ip;
        }

        public int getWeight() {
            return weight;
        }

        public void setWeight(int weight) {
            this.weight = weight;
        }

        public int getPort() {
            return port;
        }

        public void setPort(int port) {
            this.port = port;
        }
    }


    /*
    * 测试并查看结果
    * */
    public static void main(String[] args) {
        ServerF5 obj = new ServerF5();
        List list = new ArrayList();
        list.add("11.2.43.4:8080");
        list.add("11.2.43.5:8081");
        list.add("11.2.43.6:8082");
        obj.init(list);

        Map<String, Integer> countResult = new HashMap<String, Integer>();

        for (int i = 0; i < 100; i++) {
            Server s = obj.GetServer();
            String log = "ip:" + s.ip + ";weight:" + s.weight;
            if (countResult.containsKey(log)) {
                countResult.put(log, countResult.get(log) + 1);
            } else {
                countResult.put(log, 1);
            }
            System.out.println(log);
        }

        for (Map.Entry<String, Integer> map : countResult.entrySet()) {
            System.out.println("Server " + map.getKey() + " request count: " + map.getValue());
        }
    }
}

这是基本F5负载均衡算法的实现类,
我们来看看F5负载均衡的实际调用工具类。

//我们需要在这里导入它。
httpcore-4.1.4.jar
httpclient-4.1.3.jar


ServerF5Utils.java 

package F5Server;

import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionRequest;
import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;

import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class ServerF5Utils {

    private static ServerF5Utils context;
    private static List aliveUrlList;
    private Timer timer;
    private static ServerF5 serverF5;

    static {
        serverF5 = ServerF5.getContext();
    }

    public void updateAliveList(List urlLists) {
        try {
            //活动 URL 列表。
            aliveUrlList = new ArrayList();

            //客户端配置 URL 的列表。
            for (int i = 0; i < urlLists.size(); i++) {
                String[] urlport = urlLists.get(i).toString().split(":");

                String ipaddr = urlport[0];
                int port = Integer.parseInt(urlport[1]);

                HttpClient httpClient = new DefaultHttpClient();

                HttpRoute route = new HttpRoute(new HttpHost(ipaddr, port));
                ClientConnectionRequest connRequest = httpClient.getConnectionManager().requestConnection(route, null);
                ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);
                 
                try {
                    //使用客户端配置的 URL 列表打开连接。
                    conn.open(route, new BasicHttpContext(), new BasicHttpParams());
                } catch (ConnectException e) {
                    System.out.println("AliveList init refuse:[" + ipaddr + ":" + port + "]");
                    continue;
                }

                if (conn.isOpen()) {
           //如果测试连接成功,则此连接将添加到活跃链接列表中。
                    aliveUrlList.add(urlLists.get(i).toString());
                    System.out.println("AliveList init Success:[" + this.aliveUrlList + "]");
                    conn.releaseConnection();
                    continue;
                } else {
                    continue;
                }
            }
        } catch (Exception e) {
            System.out.println("HttpConnection Alive Url List init fail,please check Http URL,Exception:" + e.toString());
        }
        System.out.println("HttpConnection Alive Url List List =[" + aliveUrlList + "]");
        //提供给F5服务的活跃链接列表以供选择。
        serverF5.init(aliveUrlList);
    }

    /**
     * 可用 URL 链接通过算法选择并返回。
     */
    public String getServerUrl() {
        ServerF5.Server server = serverF5.GetServer();
        String ip = server.getIp();
        int port = server.getPort();
        String url = ip + ":" + port;
        return url;
    }

    /**
     * 初始化 F5 工具类的上下文环境,以便用户可以调用它。
     */
    public static ServerF5Utils getContext(final List urlLists) {
        if (context == null) {
            context = new ServerF5Utils();
            context.updateAliveList(urlLists);
            context.timer = new Timer();
            context.timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    context.updateAliveList(urlLists);
                }
            }, 50000, 300000);
        }
        return ServerF5Utils.context;
    }

    //Test
    public static void main(String[] args) {
        List<String> urls= new ArrayList<>();
        urls.add("11.2.43.3:8080");
        urls.add("11.2.43.4:8080");
        urls.add("11.2.43.5:8080");
        String shotUrl = ServerF5Utils.getContext(urls).getServerUrl();
        System.out.println("shotUrl="+shotUrl);
    }
}

测试和调用方法将服务器构建的选定 URL 列表传递给 F5 工具类上下文。 在 F5 负载平衡初始化成功后,返回可供调用者使用的选定 URL 链接。


发表回复

Thanks for your support to bet365fans!