- 浏览: 78014 次
- 性别:
- 来自: 上海
最新评论
-
rockythd:
视界这个概念终于搞清楚了,谢谢!
Java关于Scala的“视界(view bound)”的模拟 -
regular:
写了一个更通用的方法:ObjectUtils.cast。目的是 ...
Java关于Scala的“视界(view bound)”的模拟 -
lrztiancai:
谢谢分享。正在找这个!
Parsley+SpiceLib 2.4 Developer Manual -
kraft:
第二版什么时候出啊
Programming In Scala 翻译 -
justjavac:
xpf7622 写道haixu.huang@live @前的名 ...
Programming In Scala 翻译
集群技术,也就是俗称的Cluster,是为了保证某种应用不间断的服务而采取的一种技术手段。
服务运行在A,B两台机器上,其中一台为主用机,一台为备用机。备用机不断检测主用机的心跳信息。当发现主用机宕机或不能提供服务的时候,会自动转变为主用机,继续提供服务。
实现细节包括主备用机之间的心跳协议,物理线缆连接方式,以及虚拟出来的服务接口。
其他都还好说,不过虚拟服务接口的确不是很容易实现的。本文对虚拟服务接口技术做了模拟。
虚拟接口,实际是指虚拟的IP地址以及在这个IP地址接口侦听的应用服务。
由于客户机并不会自动改变请求服务的IP地址和端口,因此集群必须提供一个唯一的对外服务接口,并实现主备之间的无缝转换。
虚拟接口我以为有两种办法:
第一种,在计算机上虚拟一块网卡出来,然后把服务绑定到这块网卡上;
第二种,把指向虚拟IP的IP协议包以及ARP协议包转到主机实际存在的网卡上。
我这里是使用了JPCAP工具,实现了第二种方案。
具体要做两件事:
实现的时候发现,如果使用JPCAP直接转发ICMP包的话会出现问题。
ECHO_REPLY不能被识别,造成Ping不通的现象。
之后研究了ICMP的头结构,发现是在REPLY的时候不能自动填充id和seq,修改之后运转正常。
主旨
服务运行在A,B两台机器上,其中一台为主用机,一台为备用机。备用机不断检测主用机的心跳信息。当发现主用机宕机或不能提供服务的时候,会自动转变为主用机,继续提供服务。
实现细节包括主备用机之间的心跳协议,物理线缆连接方式,以及虚拟出来的服务接口。
其他都还好说,不过虚拟服务接口的确不是很容易实现的。本文对虚拟服务接口技术做了模拟。
虚拟接口,实际是指虚拟的IP地址以及在这个IP地址接口侦听的应用服务。
由于客户机并不会自动改变请求服务的IP地址和端口,因此集群必须提供一个唯一的对外服务接口,并实现主备之间的无缝转换。
方案
虚拟接口我以为有两种办法:
第一种,在计算机上虚拟一块网卡出来,然后把服务绑定到这块网卡上;
第二种,把指向虚拟IP的IP协议包以及ARP协议包转到主机实际存在的网卡上。
我这里是使用了JPCAP工具,实现了第二种方案。
具体要做两件事:
- 实现ARP协议的ARP_REPLY;
- 转发IP包。
实现的时候发现,如果使用JPCAP直接转发ICMP包的话会出现问题。
ECHO_REPLY不能被识别,造成Ping不通的现象。
之后研究了ICMP的头结构,发现是在REPLY的时候不能自动填充id和seq,修改之后运转正常。
/** * Network Utilities */ package cn.sh.huang; import jpcap.NetworkInterface; import jpcap.NetworkInterfaceAddress; public final class NetworkUtilities { private NetworkUtilities() { } public static byte[] getMacBytes(String mac) { byte[] bytes = new byte[6]; String[] hex = mac.split("-"); if (hex.length != 6) { throw new IllegalArgumentException("Invalid MAC address."); } try { for (int i = 0; i < 6; i++) { bytes[i] = (byte) Integer.parseInt(hex[i], 16); } } catch (NumberFormatException ex) { throw new IllegalArgumentException("Invalid hex digit in MAC address."); } return bytes; } public static String getMacString(byte[] mac) { StringBuffer sb = new StringBuffer(); for (byte hex : mac) { sb.append('-').append(((int)hex) & 0xFF); } return sb.substring(1); } public static NetworkInterface fetchDevice(NetworkInterface[] devices, String ip) { for (NetworkInterface device : devices) { for (NetworkInterfaceAddress address : device.addresses) { if (ip.equals(address.address.getHostAddress())) { return device; } } } return null; } } /** * ClusterDaemon */ package cn.sh.huang; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import jpcap.JpcapCaptor; import jpcap.JpcapSender; import jpcap.NetworkInterface; import jpcap.packet.ARPPacket; import jpcap.packet.EthernetPacket; import jpcap.packet.ICMPPacket; import jpcap.packet.IPPacket; import jpcap.packet.Packet; import jpcap.packet.TCPPacket; public class ClusterDaemon { private static final String PRV_IP = "192.168.56.1"; private static final String PUB_IP = "10.61.97.207"; private static final String NAT_IP = "10.61.96.7"; private static final String MAP_IP_PREFIX = "192.168.111."; private static final InetAddress PRV_IP_ADDR; private static final InetAddress NAT_IP_ADDR; static { PRV_IP_ADDR = getIpAddr(PRV_IP); NAT_IP_ADDR = getIpAddr(NAT_IP); } private static InetAddress getIpAddr(String ip) { InetAddress ipAddr = null; try { ipAddr = InetAddress.getByName(ip); } catch (UnknownHostException ex) { ex.printStackTrace(); } return ipAddr; } private final NetworkInterface pubInterf, prvInterf; private final JpcapSender pubSender, prvSender; private final JpcapCaptor pubCaptor, prvCaptor; private final Map<String, byte[]> macMap; private ClusterDaemon() throws IOException { NetworkInterface[] devices = JpcapCaptor.getDeviceList(); pubInterf = NetworkUtilities.fetchDevice(devices, PUB_IP); pubCaptor = JpcapCaptor.openDevice(pubInterf, 65535, false, 20); pubSender = pubCaptor.getJpcapSenderInstance(); prvInterf = NetworkUtilities.fetchDevice(devices, PRV_IP); prvCaptor = JpcapCaptor.openDevice(prvInterf, 65535, false, 20); prvSender = prvCaptor.getJpcapSenderInstance(); macMap = new HashMap<String, byte[]>(); Thread pubIfListener = new Thread(new Runnable() { @Override public void run() { Packet pack; while (true) { pack = pubCaptor.getPacket(); if (pack instanceof ARPPacket) { ARPPacket arpPack = (ARPPacket) pack; // 若arp的目的为请求newIpAddr的MAC地址,则回应 if (Arrays.equals(arpPack.target_protoaddr, NAT_IP_ADDR.getAddress()) && arpPack.operation == ARPPacket.ARP_REQUEST) { // if (!Arrays.equals(arpPack.sender_protoaddr, pubIpAddr.getAddress())) // 避免自问自答 // { pubSender.sendPacket(createArpPack(pubInterf.mac_address, NAT_IP_ADDR.getAddress(), arpPack.sender_hardaddr, arpPack.sender_protoaddr, pubInterf.mac_address, arpPack.sender_hardaddr, ARPPacket.ARP_REPLY)); // } } } else if (pack instanceof IPPacket) { IPPacket ipPack = (IPPacket) pack; if (!(ipPack instanceof TCPPacket || ipPack instanceof ICMPPacket)) { continue; } // else // { // System.out.println("PubIf " + ipPack); // } InetAddress dstIp = ipPack.dst_ip; InetAddress srcIp = ipPack.src_ip; if (dstIp.equals(NAT_IP_ADDR)) { // 转发给prvIf EthernetPacket eth = (EthernetPacket) ipPack.datalink; String srcIpAddr = srcIp.getHostAddress(); macMap.put(srcIpAddr, eth.src_mac); macMap.put(NetworkUtilities.getMacString(eth.src_mac), ipPack.src_ip.getAddress()); String mapIp = MAP_IP_PREFIX + srcIpAddr.substring(srcIpAddr.lastIndexOf('.') + 1); macMap.put(mapIp, eth.src_mac); try { ipPack.src_ip = InetAddress.getByName(mapIp); } catch (UnknownHostException ex) { ex.printStackTrace(); } eth.dst_mac = prvInterf.mac_address; ipPack.dst_ip = PRV_IP_ADDR; if (ipPack instanceof ICMPPacket) // ICMP包要注意id和seq不要漏掉(大概是JPCAP的bug) { ICMPPacket icmp = (ICMPPacket) ipPack; if (icmp.id == 0 && icmp.seq == 0) { icmp.id = (short) (icmp.header[38] * 256 + icmp.header[39]); icmp.seq = (short) (icmp.header[40] * 256 + icmp.header[41]); } } prvSender.sendPacket(ipPack); } } } } }); pubIfListener.start(); Thread prvIfListener = new Thread(new Runnable() { @Override public void run() { Packet pack; while (true) { pack = prvCaptor.getPacket(); if (pack instanceof ARPPacket) { ARPPacket arpPack = (ARPPacket) pack; // 若arp的目的为请求mapIp的MAC地址,则回应 String fakeAddr = null; try { fakeAddr = InetAddress.getByAddress(arpPack.target_protoaddr).getHostAddress(); } catch (UnknownHostException ex) { ex.printStackTrace(); } if (fakeAddr.startsWith(MAP_IP_PREFIX) && arpPack.operation == ARPPacket.ARP_REQUEST) { byte[] fakeMAC = macMap.get(fakeAddr); prvSender.sendPacket(createArpPack(fakeMAC, arpPack.target_protoaddr, arpPack.sender_hardaddr, arpPack.sender_protoaddr, fakeMAC, arpPack.sender_hardaddr, ARPPacket.ARP_REPLY)); } } else if (pack instanceof IPPacket) { IPPacket ipPack = (IPPacket) pack; if (!(ipPack instanceof TCPPacket || ipPack instanceof ICMPPacket)) { continue; } // else // { // System.out.println("PrvIf " + ipPack); // } if (ipPack.dst_ip.getHostAddress().startsWith(MAP_IP_PREFIX)) // mapIp { // 转发给pubIf EthernetPacket eth = (EthernetPacket) ipPack.datalink; eth.src_mac = pubInterf.mac_address; ipPack.src_ip = NAT_IP_ADDR; try { ipPack.dst_ip = InetAddress.getByAddress(macMap.get(NetworkUtilities .getMacString(eth.dst_mac))); } catch (UnknownHostException ex) { ex.printStackTrace(); } if (ipPack instanceof ICMPPacket) { ICMPPacket icmp = (ICMPPacket) ipPack; if (icmp.id == 0 && icmp.seq == 0) { icmp.id = (short) (icmp.header[38] * 256 + icmp.header[39]); icmp.seq = (short) (icmp.header[40] * 256 + icmp.header[41]); } } pubSender.sendPacket(ipPack); } } } } }); prvIfListener.start(); } public static void main(String[] args) throws IOException { /** * <pre> * Thread thread = new Thread(new Runnable() { * * @Override * public void run() * { * while (true) * { * if (state == ArpState.REQUEST) * { * ARPPacket arp = createArpPack(pubIf.mac_address, pubIpAddr, new byte[] { * 0, 0, 0, 0, 0, 0 * }, newIpAddr, pubIf.mac_address, new byte[] { * -1, -1, -1, -1, -1, -1 * }, ARPPacket.ARP_REQUEST); * pubSender.sendPacket(arp); * try * { * Thread.sleep(30000); * } * catch (InterruptedException ex) * { * ex.printStackTrace(); * } * } * } * } * }); * thread.setDaemon(true); * thread.start(); * </pre> */ new ClusterDaemon(); } private static ARPPacket createArpPack(byte[] sender_hardaddr, byte[] sender_protoaddr, byte[] target_hardaddr, byte[] target_protoaddr, byte[] eth_src_mac, byte[] eth_dst_mac, short operation) { ARPPacket arp = new ARPPacket(); arp.hardtype = ARPPacket.HARDTYPE_ETHER; arp.prototype = ARPPacket.PROTOTYPE_IP; arp.operation = operation; arp.hlen = 6; arp.plen = 4; arp.sender_hardaddr = sender_hardaddr; // 发送方的MAC地址 arp.sender_protoaddr = sender_protoaddr; // 发送方协议地址 arp.target_hardaddr = target_hardaddr; // 目标MAC地址 arp.target_protoaddr = target_protoaddr; // 目标协议地址 EthernetPacket eth = new EthernetPacket(); // 创建以太网头 eth.frametype = EthernetPacket.ETHERTYPE_ARP; // 以太包类型 eth.src_mac = eth_src_mac; // 以太源 MAC地址 eth.dst_mac = eth_dst_mac; // 以太汇 MAC地址 arp.datalink = eth; // 将以太头放在ARP包前 return arp; } /** * <pre> * private static void receivePack() throws UnknownHostException * { * Packet pack = null; * int ident = 10000; * while (true) * { * pack = pubCaptor.getPacket(); * if (pack instanceof IPPacket) * { * IPPacket ipPack = (IPPacket) pack; * byte[] srcIp = ipPack.src_ip.getAddress(); * byte[] dstIp = ipPack.dst_ip.getAddress(); * if (Arrays.equals(dstIp, newIpAddr)) * { * * } * else if (!Arrays.equals(dstIp, pubIpAddr)) * { * * } * if (Arrays.equals(dstIp, newIpAddr) || Arrays.equals(srcIp, newIpAddr)) * { * if (ipPack instanceof ICMPPacket) * { * // System.out.println(ipPack); * if (Arrays.equals(dstIp, newIpAddr)) * { * ICMPPacket icmpPack = (ICMPPacket) ipPack; * ICMPPacket icmp = new ICMPPacket(); * icmp.type = ICMPPacket.ICMP_ECHOREPLY; * icmp.setIPv4Parameter(0, false, false, false, 0, false, false, false, 0, ident++, 128, * IPPacket.IPPROTO_ICMP, InetAddress.getByName(newIp), icmpPack.src_ip); * long millisec = Calendar.getInstance().getTimeInMillis(); * icmp.sec = millisec / 1000000; * icmp.usec = millisec % 1000000; * icmp.data = icmpPack.data; * EthernetPacket echoEther = (EthernetPacket) icmpPack.datalink; * EthernetPacket ether = new EthernetPacket(); * ether.frametype = EthernetPacket.ETHERTYPE_IP; * ether.dst_mac = echoEther.src_mac; * ether.src_mac = pubIf.mac_address; * icmp.datalink = ether; * icmp.id = icmpPack.id; * icmp.seq = icmpPack.seq; * if (icmp.id == 0 && icmp.seq == 0) * { * icmp.id = (short) (icmpPack.header[38] * 256 + icmpPack.header[39]); * icmp.seq = (short) (icmpPack.header[40] * 256 + icmpPack.header[41]); * } * // System.out.println(icmpPack); * pubSender.sendPacket(icmp); * } * } * // System.out.println("IPPacket:"); * // System.out.println(ipPack); * } * } * else if (pack instanceof ARPPacket) * { * ARPPacket arpPack = (ARPPacket) pack; * // if (Arrays.equals(arpPack.sender_protoaddr, newIpAddr) * // || Arrays.equals(arpPack.target_protoaddr, newIpAddr)) * // { * // System.out.println(arpPack); * // } * if (Arrays.equals(arpPack.target_protoaddr, newIpAddr)) * { * if (!Arrays.equals(arpPack.sender_protoaddr, pubIpAddr)) * { * ARPPacket arp = createArpPack(pubIf.mac_address, newIpAddr, arpPack.sender_hardaddr, * arpPack.sender_protoaddr, pubIf.mac_address, arpPack.sender_hardaddr, ARPPacket.ARP_REPLY); * pubSender.sendPacket(arp); * state = ArpState.REPLY; * } * } * } * else * { * if (pack == null) * continue; * // System.out.println("Unknown:"); * // System.out.println(pack); * } * } * } * </pre> */ }
发表评论
-
把Spring容器中的bean绑定到通过代码创建的对象
2012-04-26 16:17 2277Spring提供了对配置中创建对象的字段实例注入。但如果是通过 ... -
动态注册消息类型及处理函数
2011-10-01 15:56 1007内容略。参见代码演示。 -
代码实例
2011-02-14 17:17 1032代码实例文件 -
如何在类外部调用被子类覆盖的父类方法
2011-01-20 14:46 1899题目比较绕。以下用一个简单的例子说明: public cl ... -
SWT应用的开发实例:没有使用到OSGi
2011-01-14 11:27 1530添加音效,以及中奖名单回看功能。 SWT应用一枚。具体方法见 ... -
运行期代码问题检查技术的研究
2010-11-29 13:30 1143以下用我之前代码中的一个bug作为说明,解释如何实现代码在运行 ... -
代码潜在故障的动态分析
2010-11-16 12:24 1520引子 大家都听说过FindBugs的大名。这是一款静态代码分析 ... -
健壮的、便捷的、异步的SocketChannel实现
2010-04-27 10:34 8396Socket通信比较常见的问题有如下几种: 1、设置收发超时; ... -
打算研究学习一下OSGi和Equinox
2010-02-10 11:26 1156看到一本很直接讨论这个题目的书,不过要等到3月1日才出来。 ... -
JarSpur 检查引用包归属的小工具
2009-12-25 17:31 1086图形化的界面,允许你导入任意多的在项目中可能需要的Jar包。 ... -
class.getResourceAsStream()与ClassLoader.getResourceAsStream()的区别
2009-11-11 17:33 2054在jar包里获得流形式的资源有两种方法,一个是Class.ge ... -
MultiKeyedMap方案的实现
2009-11-10 11:55 3760方案背景 所谓“MultiKey ... -
Java2D: 硬件加速 - 第二部分 - 缓冲策略:Buffer Strategies
2009-11-02 12:52 2953原文地址:Java2D: Hardware ... -
Java2D: 硬件加速 - 第一部分 - 非恒定图像类:Volatile Image
2009-10-30 16:19 4297原文地址:Java2D: Hareware Accelerat ... -
自建的MiniChart库,目前实现了点图、折线图、柱状图和饼图
2009-07-15 11:08 1245花了大约一个星期时间做的MiniChart库。 由于现在的免费 ... -
BM方案模式匹配的Java代码实现
2009-06-17 13:47 1585速度还算快,例子里比较的文件一共371个,3,293,472字 ... -
对于经典模式匹配算法的一些改动
2009-06-12 12:44 1490从一个很长的字符串(或者数组)中,查找某个子串(模式串)是否存 ... -
读写进程的互斥锁
2009-03-16 15:27 1591以下的代码完成了对某个资源的读写互斥锁,具体说明如下:1. 若 ... -
Object数组到泛型数组转换的伪解决方案
2009-01-23 10:44 4372闲来无事,想要用目前的Java技术模拟一个对象数据库。最初只是 ...
相关推荐
选择合适的集群技术取决于应用需求,例如,高可用集群适合需要高稳定性的关键业务,负载均衡集群适合处理高流量、大负载的网站或服务,而科学计算集群则适用于需要大规模并行计算的科研和工业应用。
它通过模拟技术使单个CPU能够模拟多CPU并行,支持多种操作系统在同一平台上运行,互不影响。 服务器虚拟化集群技术则是两者的结合,它通过将多台服务器集群,并在虚拟主机上运行业务软件,实现硬件资源的高效利用和...
在Java应用服务器集群环境下进行代码编写时,需要注意多个关键点以确保软件的高效、稳定和可扩展性。首先,理解集群的基本概念至关重要。集群是指一组同时运行相同Web应用的服务器,对外表现为单一服务,旨在提高...
服务器集群和优化是大型网站或应用维持高性能和高可用性的关键策略。当面临大量请求和高并发场景时,单一服务器往往无法承受,这时就需要通过服务器集群和一系列优化手段来分散负载,提升响应速度。 首先,减少请求...
并行算法的设计和实现是集群并行技术应用的关键,它需要考虑任务的分解、分配和同步等问题,确保各个节点能够高效协同工作,完成整个数据处理过程。 并行算法的设计需要考虑多方面因素,包括算法的负载平衡、通信...
其中,**请求分配和选择机制**是集群技术中的关键环节,直接影响着系统的整体性能和服务质量。 #### 二、Web服务器集群概述 Web服务器集群是指一组协同工作的Web服务器,它们共同提供服务来处理来自客户端的HTTP...
高可用性集群技术的主要目标是减少服务中断时间,确保关键业务连续运行。在HA集群中,通常会有一台主服务器负责处理请求,而其他服务器作为备用,在主服务器出现故障时立即接管服务,实现近乎无缝的切换。这种技术...
在众多的机器人应用领域中,路径规划技术是实现机器人集群自主导航的关键技术之一。路径规划不仅关系到单个机器人路径的最优化,更关键的是能够实现集群内多个机器人之间的协同配合,保证在执行任务时能够有效避免...
本文将深入探讨众核处理器和众核集群的并行模拟技术,以及它们在应对复杂系统模拟挑战中的必要性和可行性。 众核处理器是指含有多个计算核心的处理器,每个核心都可以独立执行指令,通过共享内存和通信机制协同工作...
在IT领域,特别是数据库管理和服务器架构中,"关于2008R2的集群简单应用"这个主题涉及到的是Windows Server 2008 R2操作系统中的两种关键技术:网络负载均衡(NLB)和故障转移集群。这两种技术都是为了提高服务的...
Tomcat作为Apache软件基金会的一个开源项目,是Java Servlet和JavaServer Pages(JSP)技术的开源Web应用服务器,而集群则能提供更高的可用性和可扩展性。 【描述】中的内容提到了这个压缩包包含三个关键部分:已经...
4. **应用服务器**:关键业务应用如ERP、CRM系统可部署在集群环境中,保证服务不中断。 **五、挑战与最佳实践** 1. **网络复杂性**:需要专门的集群网络,可能会增加网络管理的复杂性。 2. **成本**:集群需要额外...
高可用性集群确保服务不间断,适合关键业务应用,如Web服务器、工业控制器等;而高性能计算集群则用于处理大规模计算任务,如气象模拟、石油勘探等。 Linux作为开源操作系统,因其跨平台兼容性、稳定性及安全性,...