曾经有这样一个需求,来自公网(互联网)上的前端请求发送到内网系统A,内网系统A需要通过一个渠道系统处理,渠道系统处理之后,将结果反馈给内网系统A,内网系统A处理之后再反馈给客户端,客户端然后在通过一定的途径发送请求到第三方系统。
一:设计思想
这个系统作为多个外部业务系统的一个渠道;对外围系统提供统一的通讯服务,同时由于各种历史原因,它需要和安装互联网上各个地方的客户端进行连接服务。也就是说对于业务系统,它是一个底层的通讯服务系统,对于各个客户端来说,它又是一个上层的服务应用。
那么整个数据的流转如下:
图一
上图中客户端是发布在互联网的,而业务系统和渠道服务系统是发布在内网,属于内部通讯。
二:多个SERVER的通讯处理
方式一:
大家知道MINA2的通讯机制,是采用责任链的设计模式,在服务启动的时候,将日志,业务处理,线程等增加进去,在所有的报文过来的时候都会按照链式的结构一个节点一个节点的去处理:
如下图是SERVER端的一个处理流程,本系统将会启动两个SOCKET SERVER,这两个SERVER分别处理来自业务系统的请求和处理来自客户端的请求。
图二
如上图所示,所有的客户端和服务端的交换都需要经过上述转换,如日志,编码/解码,加密/解密等。所有的数据交换均采用XML报文的格式。
由于TCP/IP传输的时候,无法确定报文的边界,那么在报文的头上面需要加入固定格式的长度。如果你设置成1,2,4,那么就很方便了,在MINA2中有提供现成的方法判断报文。
如图一所示,系统中两个通讯服务端需要进行通信,特别是由业务系统发过来经过渠道系统的业务模块处理之后需要发送给另外一个SOCKET服务,那么这个时候如何处理?
在MINA2中两个SOCKET SERVER进行通讯,可以采用虚拟机内部的管道的方式。在MINA2的源码包里面自带了这个例子:
IoAcceptor acceptor = new VmPipeAcceptor();
VmPipeAddress address = new VmPipeAddress(8080);
// Set up server
acceptor.setHandler(new TennisPlayer());
acceptor.bind(address);
// Connect to the server.
VmPipeConnector connector = new VmPipeConnector();
connector.setHandler(new TennisPlayer());
ConnectFuture future = connector.connect(address);
future.awaitUninterruptibly();
IoSession session = future.getSession();
// Send the first ping message
session.write(new TennisBall(10));
// Wait until the match ends.
session.getCloseFuture().awaitUninterruptibly();
acceptor.unbind();
方式二:也可以将IoSession对方放入全局的线程安全的Map中去,当需要发送的时候根据KEY取出来,然后write出去。
当你发现在两个socket server A 需要等待 socket server B的执行结果然后,将结果处理完之后返回给前端系统,可以采用JDK1.5的EXCHANGE类。
三:系统难点
该渠道系统要保持成千上万个客户端的长连接,因为如果客户端如果不保持长连接,渠道系统将无法知道客户端的IP,因为客户端是按照在企业内部局域网。如果不知道客户端的信息,那么渠道服务系统也就无法推送信息给客户端了,这点类似于我们常用的QQ,旺旺的方式。一旦登陆上去就保持长连接。
四:系统优化
1.将系统中所有的基础数据,类似于城市这样的数据进行缓存,增加访问速度。
2.当第三方系统有结果返回给渠道系统时,将结果消息放入通知系统。然后启动定时任务,也就是一个轮训线程,定时将通知结果返回给各个业务系统。减少网络的调用。