深入浅出Java分布式系统通信
作者:网络转载 发布时间:[ 2015/5/14 14:12:17 ] 推荐标签:开发语言
下面我们进行性能测试:
测试场景:
每个请求的业务处理时间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();
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11