下面我们进行性能测试:
  测试场景:
  每个请求的业务处理时间110ms
  100个线程并发测试,每个线程循环请求服务端
  测试环境:
  客户端服务器:
  Cpu为4线程 2400mhz
  服务端cpu: 4线程 3000Mhz
  测试结果:
  在经过10分钟测试之后,稳定情况下的tps
  Tps:554左右
  客户端Cpu:30%
  服务端cpu:230%
  该方案的优点:
  程序实现起来简单
  该方案的缺点:
  1. Socket发送消息时,需要先发送至socket缓冲区,因此系统为每个socket分配缓冲区
  当缓冲不足时,达到了大连接数的限制
  2. 连接数大,也意味着系统内核调用的越多,socket的accept和close调用
  3.每次通信都重新开启新的tcp连接,握手协议耗时间,tcp是三次握手
  4.tcp是慢启动,TCP 数据传输的性能还取决于 TCP 连接的使用期(age)。TCP 连接会随着时间进行自我“调谐”,起初会限制连接的大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐被称为 TCP 慢启动(slow start),用于防止因特网的突
  然过载和拥塞 。
  tcp长连接同步通信
  长连接同步的传输图

  一个socket连接在同一时间只能传递一个请求的信息
  只有等到response之后,第二个请求才能开始使用这个通道
  为了提高并发性能,可以提供多个连接,建立一个连接池,连接被使用的时候标志为正在使用,
  使用完放回连接池,标识为空闲,这和jdbc连接池是一样的。
  假设后端服务器,tps是1000,即每秒处理业务数是1000
  现在内网传输耗时是5毫秒,业务处理一次请求的时间为150毫秒
  那么一次请求从客户端发起请求到得到服务端的响应,总共耗时150毫秒+5毫秒*2
  =160毫秒,如果只有一个连接通信,那么1秒内只能完成2次业务处理,即tps为2
  如果要使tps达到1000,那么理论上需要500个连接,但是当连接数上升的时候,其性能却在下降,
  因此该方案将会降低网站的吞吐量。
  实现挑战:
  mina的session.write()和receive消息都是异步的,那么需要在主线程上阻塞以等待响应的到达。
  连接池代码:
/**
* 空闲连接池
*/
private static BlockingQueue<Connection> idlePool = new LinkedBlockingQueue<Connection>();
/**
* 使用中的连接池
*/
public static BlockingQueue<Connection> activePool = new LinkedBlockingQueue<Connection>();
public static Connection getConn() throws InterruptedException{
long time1 = System.currentTimeMillis();
Connection connection = null;
connection = idlePool.take();
activePool.add(connection);
long time2 = System.currentTimeMillis();
//log.info("获取连接耗时:"+(time2-time1));
return connection;
}
  客户端代码:
public TransInfo send(TransInfo info) throws InterruptedException {
Result result = new Result();
//获取tcp连接
Connection connection = ConnectFutureFactory.getConnection(result);
ConnectFuture connectFuture = connection.getConnection();
IoSession session = connectFuture.getSession();
session.setAttribute("result", result);
//发送信息
session.write(info);
//同步阻塞获取响应
TransInfo synGetInfo = result.synGetInfo();
//此处并不是真正关闭连接,而是将连接放回连接池
ConnectFutureFactory.close(connection,result);
return synGetInfo;
}
  阻塞获取服务端响应代码:
public synchronized TransInfo synGetInfo() {
//等待消息返回
//必须要在同步的情况下执行
if (!done) {
try {
wait();
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
}
return info;
}
public synchronized void synSetInfo(TransInfo info) {
this.info = info;
this.done = true;
notify();
}