套接字序列化减速
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了套接字序列化减速相关的知识,希望对你有一定的参考价值。
我只想说明我是套接字序列化的新手,在进行downvoting之前,请建议我可以添加进行编辑。我试图尽可能小地破解代码,因为项目非常大。
我正在尝试创建一个非常简单的RPC类型中间件,其中客户端可以调用服务器上的方法并在方法生成此类对象时检索对象。我正在使用FST-Serializer库来序列化我的对象并通过网络/套接字发送它们。
虽然我已经开始运行,但我发现了一个非常奇怪的问题,当发生这种情况时,序列化的性能会显着降低(下面的代码示例):
Client Serialize params/method name -> Server retrieves information and executes method.
这意味着网络速度慢或实现不能足够快地调用它,但是如果发生这种情况,它会显着加速:
Client Serialize params/method name -> Server retrieves information and executes method -> Server serializes an object sends it back to client.
虽然这一开始看起来并不是什么大问题,但对于无效方法来说,它可能会变得很烦人,因为我必须发回虚拟数据,这意味着我必须无缘无故地花费一次网络旅行。
我想也许这可能是缓冲区不够大,但我已经尝试了不同的缓冲区大小,似乎没有解决它,我还想澄清应用程序仍然工作正常(即没有阻止)只是一个性能时间命中。所以我的问题是什么可以导致如减速,是否可预防/可修复?
我运行YouKit性能以查看热点分析(对此也是新的)并且似乎BufferedReader.Read方法减慢了很多。
监听传入调用的ServerThread片段(客户端代码类似,使用相同的buffersize创建输入/输出):
public ServerThread(Socket connection){
this.connection = connection;
isActive = true;
}
@Override
public void run() {
try {
input = new BufferedInputStream(connection.getInputStream(), BUFFER_SIZE);
output = new BufferedOutputStream(connection.getOutputStream(), BUFFER_SIZE); //Buffersize is 512_000 atm
do{
Method m = (Method) readObject(input);
//Invoke method via reflection
Server.methodNames.get(m.getName()).invoke(this, m.getParams());
}while(isActive);
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void transactionWillEnd() {
this.currentTransactionLog = null;
// This sends dummy data back to client or slowdown will occur
try{
writeObject(output, "SUCCESS");
output.flush();
} catch(Exception e){
e.printStackTrace();
}
}
从客户端发送到Serverthread的序列化方法类
public class Method implements Serializable{
private String name;
private Object[] params;
public Method(String name, Object...params) {
this.name = name;
this.params = params;
}
public String getName() {
return name;
}
public Object[] getParams() {
return params;
}
}
TCPSerializer基于FST中的TCPObjectSocket(由serverthread和client继承:
public class TCPSerializer {
private static FSTConfiguration config;
public static int BUFFER_SIZE = 512_000;
AtomicBoolean readLock = new AtomicBoolean(false);
AtomicBoolean writeLock = new AtomicBoolean(false);
public TCPSerializer() {
config = FSTConfiguration.createDefaultConfiguration();
}
public Object readObject(InputStream input) throws Exception{
try {
while ( !readLock.compareAndSet(false,true) );
return config.decodeFromStream(input);
} finally {
readLock.set(false);
}
}
public void writeObject(OutputStream output, Object toWrite) throws Exception{
try {
while ( !writeLock.compareAndSet(false,true) );
config.encodeToStream(output, toWrite);
} finally {
writeLock.set(false);
}
}
有关客户端调用方法的示例:
@Override
public void transactionWillEnd() {
String methodName = Helpers.getMethodName(0);
Method m = new Method(methodName);
try {
client.writeObject(client.getOutput(), m);
client.flush();
//Read dummy data before continuing.
String verify = (String) client.readObject(client.getInput());
if(!verify.equals("SUCCESS")) throw new Exception(verify);
} catch (Exception e) {
e.printStackTrace();
}
}
如果不执行请求/响应操作,Nagle's algorithm可以减慢连接速度。我已经看到它等待40毫秒,以便另一个字节块合并成一个数据包。
如果您在没有回复的情况下传输数据,我建议您尝试将其关闭。
socket.setTcpNoDelay(true);
https://docs.oracle.com/javase/9/docs/api/java/net/Socket.html#setTcpNoDelay(boolean)
以上是关于套接字序列化减速的主要内容,如果未能解决你的问题,请参考以下文章
11.按要求编写Java应用程序。 创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)减速(车速自减)修改车牌号,查询车的(代码片段
按要求编写Java应用程序。 创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)减速(车速自减)修改车牌号,查询车的载重量(代码片段