“你们的agent占了好多系统的port。把我们的非常多业务系统都给整死了,给我们造成了非常大的损失。要求你们的相关领导下周过来道歉”   --   来自我们的一个客户。

 怎么可能呢,我们都不相信,我们的agent仅仅占一个port啊!

事实胜过雄辩。经过查证。确实是因为我们的agent占了好多系统的port。我看了一下日志。基本把系统可用的port占完了!

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhb2ZhbndlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" />

为什么呢?MINA框架私自开的!

因为我们的agent端使用了NIO通信框架MINA,但并没有使用好,造成了这一差点儿毁灭行的灾难。

还是先看代码吧。

  1. /**
  2. * 异步发送消息
  3. * @param agent
  4. * @param request
  5. */
  6. public void sendMessageToAgent(Agent agent, HyRequest request) {
  7. IoSession session = null;
  8. IoConnector connector=null;
  9. long startTime = System.currentTimeMillis();
  10. try {
  11. // 创建一个非堵塞的客户端程序
  12. connector = new NioSocketConnector();
  13. // 设置链接超时时间
  14. connector.setConnectTimeoutMillis(connectTimeoutMillis);
  15.  
  16. ObjectSerializationCodecFactory objsCodec = new ObjectSerializationCodecFactory();
  17. objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);
  18. objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);
  19. ProtocolCodecFilter codecFilter = new ProtocolCodecFilter(
  20. objsCodec);
  21. // 数据转换。编码设置
  22. connector.getFilterChain()
  23. .addLast("codec", codecFilter);
  24. // 消息
  25. connector.setHandler(clientHandler);
  26.  
  27. SocketAddress socketAddress = new InetSocketAddress(
  28. agent.getIpAddr(), agent.getAgentPort());
  29. ConnectFuture future = connector.connect(socketAddress);
  30. future.awaitUninterruptibly();
  31. session = future.getSession();
  32. String json = mapper.writeValueAsString(request);
  33. session.write(json);
  34.  
  35. long endTime = System.currentTimeMillis();
  36.  
  37. logerr.debug("send-time:" + (endTime - startTime));
  38.  
  39. } catch (Exception e) {
  40. logerr.error("host:" + agent.getIpAddr() + ", AgentPORT:" + agent.getAgentPort()
  41. + ", 连接异常..."+e.getMessage());
  42. clientHandler.handlerConnectError(agent, request);
  43.  
  44. }
  45. }
  1. public class MinaClientHandler extends IoHandlerAdapter {
  2. // 日志
  3. private Logger log = Logger.getLogger(getClass());
  4.  
  5. private MinaResponseProcesser minaResponseProcesser;
  6.  
  7. ObjectMapper mapper=null;
  8.  
  9. @Override
  10. public void messageReceived(IoSession session, Object message)
  11. throws Exception {
  12. String msg = message.toString();
  13. log.info("receive message from " + session.getRemoteAddress().toString() + ",message:" + message);
  14. if(null == mapper){
  15. mapper = new ObjectMapper();
  16. }
  17. //请求消息转换为HyResponse对象
  18. HyResponse response = mapper.readValue(msg, HyResponse.class);
  19. String remoteIp= ((InetSocketAddress)session.getRemoteAddress()).getAddress().getHostAddress();
  20. response.setRemoteIp(remoteIp);
  21. HyRequest request = minaResponseProcesser.processResponse(response);
  22. if(request == null){
  23. //关闭当前session
  24. closeSessionByServer(session,response);
  25. }else{
  26. session.write(mapper.writeValueAsString(request));
  27. }
  28. }
  29. }

上面的逻辑就是,当要发送一个消息时,创建一个新的connector,并获取一个session发送消息后直接返回,在MinaClientHandler类的messageReceived里面处理接受到的响应数据,并进行业务处理。最后假设不须要再次发送请求,则关闭当前session。

事实上出现本文一開始的问题就是在这里造成的。

在出现我们的agent占用大量port后,我们这边的project人员就迅速定位到了这个问题,并非常快修复了。但修复并不理想,但修复过后的代码。

  1. /**
  2. * 异步发送消息
  3. * @param agent
  4. * @param request
  5. */
  6. public void sendMessageToAgent(Agent agent, HyRequest request) {
  7. IoSession session = null;
  8. IoConnector connector=null;
  9. long startTime = System.currentTimeMillis();
  10. try {
  11. // 创建一个非堵塞的客户端程序
  12. connector = new NioSocketConnector();
  13. // 设置链接超时时间
  14. connector.setConnectTimeoutMillis(connectTimeoutMillis);
  15.  
  16. ObjectSerializationCodecFactory objsCodec = new ObjectSerializationCodecFactory();
  17. objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);
  18. objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);
  19. ProtocolCodecFilter codecFilter = new ProtocolCodecFilter(
  20. objsCodec);
  21. // 数据转换,编码设置
  22. connector.getFilterChain()
  23. .addLast("codec", codecFilter);
  24. // 消息
  25. connector.setHandler(clientHandler);
  26.  
  27. SocketAddress socketAddress = new InetSocketAddress(
  28. agent.getIpAddr(), agent.getAgentPort());
  29. ConnectFuture future = connector.connect(socketAddress);
  30. future.awaitUninterruptibly();
  31. session = future.getSession();
  32. String json = mapper.writeValueAsString(request);
  33. session.write(json);
  34. // 等待断开连接
  35. session.getCloseFuture().awaitUninterruptibly();
  36. long endTime = System.currentTimeMillis();
  37.  
  38. logerr.debug("send-time:" + (endTime - startTime));
  39. //connector.dispose();
  40. } catch (Exception e) {
  41. logerr.error("host:" + agent.getIpAddr() + ", AgentPORT:" + agent.getAgentPort()
  42. + ", 连接异常..."+e.getMessage());
  43. clientHandler.handlerConnectError(agent, request);
  44.  
  45. }finally{
  46. if(null!=session){
  47. session.close(true);
  48. session=null;
  49. }
  50. if(null !=connector){
  51. connector.dispose();
  52. }
  53. }
  54. }

仅仅改了一个地方。就是在发送完消息后,加了一个等待断开连接语句和finally语句块-关闭session和connector。

尽管不会出现程序占用大量的系统port这个问题。但会造成另外一个问题-当有一个消息队列须要异步调用上面语句发送消息时,有原来的异步(发送完直接返回,相当于高速并发发送)变成伪异步(发送完消息后并等待消息返回处理后返回,相当于顺序处理队列里面的消息)。

上面的改动并非我们想要的结果,但至少修复了占用大量port的问题。

因为怀着想彻底修复这个问题的想法,我想还是深入了解一下MINA源代码吧。

NIO框架之MINA源代码解析(一):背景的更多相关文章

  1. NIO框架之MINA源代码解析(二):mina核心引擎

    NIO框架之MINA源代码解析(一):背景 MINA的底层还是利用了jdk提供了nio功能,mina仅仅是对nio进行封装.包含MINA用的线程池都是jdk直接提供的. MINA的server端主要有 ...

  2. NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信

    1.NIO超级陷阱 之所以说NIO超级陷阱,就是因为我在本系列开头的那句话,因为使用缺陷导致客户业务系统瘫痪.当然,我对这个问题进行了很深的追踪,包括对MINA源码的深入了解,但其实之所以会出现这个问 ...

  3. NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码

    1.粘包与段包 粘包:指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.造成的可能原因: 发送端需要等缓冲区满才发送出去,造成粘包 接收 ...

  4. NIO框架之MINA源码解析(转)

    http://blog.csdn.net/column/details/nio-mina-source.html http://blog.csdn.net/chaofanwei/article/det ...

  5. (一)Mina源代码解析之总体架构

    Apache Mina Server 是一个网络通信应用框架.也就是说,它主要是对基于TCP/IP.UDP/IP协议栈的通信框架(当然,也能够提供JAVA 对象的序列化服务.虚拟机管道通信服务等).M ...

  6. NIO框架Mina学习

    前言: 找了篇文章看了看,nio框架数Mina用的最多! 代码: 服务端: package com.mina; import java.net.InetSocketAddress; import ja ...

  7. NIO通讯框架之Mina

          在两三年前,阿堂在技术博客(http://blog.sina.com.cn/heyitang)上曾经写过"JAVA新I/O学习系列笔记(1)"和"JAVA新I ...

  8. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...

  9. 【原创】NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战

    概述 本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo. 当前由于NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能. ...

随机推荐

  1. 关于libnmap 的一些应用

    随笔描述 nmap 可以进行端口的扫描,在安全或运维中可以说是一款不错的神奇吧,在大部分LINUX 里面都自带了nmap 这款工具,他不仅仅是端口扫描,自身还提供许多插件可以使用. 官方文档 nmap ...

  2. 基于Quick_Thought Vectors的Sentence2Vec神经网络实现

    一.前言 1.Skip-Thought-Vector论文 https://github.com/ryankiros/skip-thoughts 2.本文假设读者已了解Skip-Gram-Vector和 ...

  3. Python学习笔记(7)字典

    2019-03-07 字典(dict): (1)字典用大括号({})定义,字典由多个键及其对应的值组合而成,每一对键值组合称为项. (2)字典的键唯一,但是值可以是任何(不可变的)数据类型(整型,字符 ...

  4. pytorch 7 save_reload 保存和提取神经网络

    import torch import matplotlib.pyplot as plt # torch.manual_seed(1) # reproducible # fake data x = t ...

  5. ActiveMQ学习总结(4)——业界消息队列简介

    最近开发公司的短信平台,要用到消息队列,之前用的是亚马逊的SQS,考虑到后续业务发展,对消息推送的高并发要求,公司决定采用RabbitMQ来替换.借此机会开始熟悉各种MQ产品,下面先给大家简介下业界常 ...

  6. C#-单元测试知识点

    指的是软件中对最小单元进行测试的一种测试方法 开发阶段的测试发现问题并解决问题是最节省时间和成本 Ctrl+R Ctrl+A 自动化执行单元测试 查看代码覆盖率,通常要达到80,90%的代码测试覆盖率 ...

  7. Android native CursorWindow数据保存原理

    我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中.CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享.共享内存所採用的实现方式是文件映射. 在 ...

  8. android 极细线

    最后找到一个还算好用的方法:伪类 + transform 原理是把原先元素的 border 去掉,然后利用:before或者:after重做 border ,并 transform 的 scale 缩 ...

  9. JAVA配置Tomcat

    1.下载tomcat,我jdk是1.8的,网上查了一下,说要安装tomcat8及以上的tomcat 尝试点击,弹出, 2.配置环境 3.安装通过cmd安装 4.点击开启服务 5.输入localhost ...

  10. 高斯滤波及高斯卷积核C++实现

    高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,在图像处理的降噪.平滑中应用较多,特别是对抑制或消除服从正态分布的噪声非常有效. 高斯滤波的过程其实就是对整幅图像进行加权平均操作的过程.滤波后图像上每 ...