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 链接。 文章导航 Linux recursive search string, batch replacement, support URL replacement. A simple F5 load balancing function implemented by JAVA code