NIO框架之MINA源码解析(一):背景
来源:互联网 发布:下载点读机软件 编辑:程序博客网 时间:2024/04/30 13:24
“你们的agent占了好多系统的端口,把我们的很多业务系统都给整死了,给我们造成了很大的损失,要求你们的相关领导下周过来道歉” -- 来自我们的一个客户。
怎么可能呢,我们都不相信,我们的agent只占一个端口啊!
事实胜过雄辩,经过查证,确实是由于我们的agent占了好多系统的端口,我看了一下日志,基本把系统可用的端口占完了!
为什么呢?MINA框架私自开的!
由于我们的agent端使用了NIO通信框架MINA,但并没有使用好,造成了这一几乎毁灭行的灾难。
还是先看代码吧。
- /**
- * 异步发送消息
- * @param agent
- * @param request
- */
- public void sendMessageToAgent(Agent agent, HyRequest request) {
- IoSession session = null;
- IoConnector connector=null;
- long startTime = System.currentTimeMillis();
- try {
- // 创建一个非阻塞的客户端程序
- connector = new NioSocketConnector();
- // 设置链接超时时间
- connector.setConnectTimeoutMillis(connectTimeoutMillis);
- ObjectSerializationCodecFactory objsCodec = new ObjectSerializationCodecFactory();
- objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);
- objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);
- ProtocolCodecFilter codecFilter = new ProtocolCodecFilter(
- objsCodec);
- // 数据转换,编码设置
- connector.getFilterChain()
- .addLast("codec", codecFilter);
- // 消息
- connector.setHandler(clientHandler);
- SocketAddress socketAddress = new InetSocketAddress(
- agent.getIpAddr(), agent.getAgentPort());
- ConnectFuture future = connector.connect(socketAddress);
- future.awaitUninterruptibly();
- session = future.getSession();
- String json = mapper.writeValueAsString(request);
- session.write(json);
- long endTime = System.currentTimeMillis();
- logerr.debug("send-time:" + (endTime - startTime));
- } catch (Exception e) {
- logerr.error("host:" + agent.getIpAddr() + ", AgentPORT:" + agent.getAgentPort()
- + ", 连接异常..."+e.getMessage());
- clientHandler.handlerConnectError(agent, request);
- }
- }
- public class MinaClientHandler extends IoHandlerAdapter {
- // 日志
- private Logger log = Logger.getLogger(getClass());
- private MinaResponseProcesser minaResponseProcesser;
- ObjectMapper mapper=null;
- @Override
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- String msg = message.toString();
- log.info("receive message from " + session.getRemoteAddress().toString() + ",message:" + message);
- if(null == mapper){
- mapper = new ObjectMapper();
- }
- //请求消息转换为HyResponse对象
- HyResponse response = mapper.readValue(msg, HyResponse.class);
- String remoteIp= ((InetSocketAddress)session.getRemoteAddress()).getAddress().getHostAddress();
- response.setRemoteIp(remoteIp);
- HyRequest request = minaResponseProcesser.processResponse(response);
- if(request == null){
- //关闭当前session
- closeSessionByServer(session,response);
- }else{
- session.write(mapper.writeValueAsString(request));
- }
- }
- }
上面的逻辑就是,当要发送一个消息时,创建一个新的connector,并获取一个session发送消息后直接返回,在MinaClientHandler类的messageReceived里面处理接受到的响应数据,并进行业务处理,最后如果不需要再次发送请求,则关闭当前session。
其实出现本文一开始的问题就是在这里造成的。
在出现我们的agent占用大量端口后,我们这边的工程人员就迅速定位到了这个问题,并很快修复了,但修复并不理想,但修复过后的代码。
- /**
- * 异步发送消息
- * @param agent
- * @param request
- */
- public void sendMessageToAgent(Agent agent, HyRequest request) {
- IoSession session = null;
- IoConnector connector=null;
- long startTime = System.currentTimeMillis();
- try {
- // 创建一个非阻塞的客户端程序
- connector = new NioSocketConnector();
- // 设置链接超时时间
- connector.setConnectTimeoutMillis(connectTimeoutMillis);
- ObjectSerializationCodecFactory objsCodec = new ObjectSerializationCodecFactory();
- objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);
- objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);
- ProtocolCodecFilter codecFilter = new ProtocolCodecFilter(
- objsCodec);
- // 数据转换,编码设置
- connector.getFilterChain()
- .addLast("codec", codecFilter);
- // 消息
- connector.setHandler(clientHandler);
- SocketAddress socketAddress = new InetSocketAddress(
- agent.getIpAddr(), agent.getAgentPort());
- ConnectFuture future = connector.connect(socketAddress);
- future.awaitUninterruptibly();
- session = future.getSession();
- String json = mapper.writeValueAsString(request);
- session.write(json);
- // 等待断开连接
- session.getCloseFuture().awaitUninterruptibly();
- long endTime = System.currentTimeMillis();
- logerr.debug("send-time:" + (endTime - startTime));
- //connector.dispose();
- } catch (Exception e) {
- logerr.error("host:" + agent.getIpAddr() + ", AgentPORT:" + agent.getAgentPort()
- + ", 连接异常..."+e.getMessage());
- clientHandler.handlerConnectError(agent, request);
- }finally{
- if(null!=session){
- session.close(true);
- session=null;
- }
- if(null !=connector){
- connector.dispose();
- }
- }
- }
只改了一个地方,就是在发送完消息后,加了一个等待断开连接语句和finally语句块-关闭session和connector。
虽然不会出现程序占用大量的系统端口这个问题,但会造成另外一个问题-当有一个消息队列需要异步调用上面语句发送消息时,有原来的异步(发送完直接返回,相当于快速并发发送)变成伪异步(发送完消息后并等待消息返回处理后返回,相当于顺序处理队列里面的消息)。
上面的修改并不是我们想要的结果,但至少修复了占用大量端口的问题。
由于怀着想彻底修复这个问题的想法,我想还是深入了解一下MINA源码吧。
- NIO框架之MINA源码解析(一):背景
- NIO框架之MINA源码解析(一):背景
- NIO框架之MINA源码解析(二):mina核心引擎
- NIO框架之MINA源码解析(二):mina核心引擎
- NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信
- NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信
- NIO框架之MINA源码解析(三):底层通信与责任链模式应用
- NIO框架之MINA源码解析(三):底层通信与责任链模式应用
- NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码
- NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码
- NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码
- (一)Mina源码解析之整体架构
- Java NIO框架之 Mina
- NIO框架之MINA详解
- NIO通讯框架之Mina
- (二)Mina源码解析之IoService
- (三)Mina源码解析之IoFilter
- (四)Mina源码解析之IoSession
- 正则表达式
- spring-boot学习心得
- 智能指针(二):shared_ptr实现原理
- Sqlite 插入数据太慢
- 最长递增子序列(算法)
- NIO框架之MINA源码解析(一):背景
- iOS的socket开发基础
- Git 忽略一些文件不加入版本控制
- C#的DataGridView中,设置固定的列宽,自动填充宽度
- java实现文件下载
- 九度题目1207:质因数的个数
- 使用 SO_KEEPALIVE 选项检测TCP连接
- 怎么没有人研究自动并行化Par4all编译器,一个很好的HPC开源工具
- CCSpriteFrameCache的用法(转)