Desenvolvi uma aplicação que roda em dois serviços que estão em máquinas diferentes. A comunicação é feita via socket utilizado ObjectInputStream e ObjectOutputStream. Nos testes que fiz, o tempo de comunicação e transporte dos dados entre as máquinas consomem um tempo significativo do tempo total de execução e pior, testei em rede de 100 MB e rede Giga, o tempo de comunicação é o mesmo.
Já li que a latência, a serialização e desserialização são desvantagens na arquitetura. Pergunto: Existe alguma forma de melhorar o desempenho de comunicação entre as máquinas e reduzir o tempo de transferência dos dados? Por que não tem diferença entre desempenho na rede MB e Giga? Por acaso o ObjectInputStream já envia via rede conforme serializa?
Só com essas informações não dá pra ter certeza a causa da lentidão, mas se a mensagem transportada for relativamente simples dá pra usar o DataInputStream e DataOutputStream, em que você transporta os valores dos objetos em vez do objeto java inteiro. Pode melhorar em até 6 vezes a performance comparado com usar apenas ObjectInputStream/ObjectOutputStream.
Estou transferindo resultado de uma consulta em banco de dados para tratar em outra máquina por outro service. Mais de 40.000 registros com tamanho de ~130 MiB, em geral será um grande volume de dados. Em um serviço executo a consulta no banco, armazeno o resultado em um ArrayList e envio essa Lista para outra máquina, na qual outro serviço anonimiza os dados:
socketPrivacy = new Socket("privacy",9002);
outputPrivacy = new ObjectOutputStream(socketPrivacy.getOutputStream());
inputPrivacy = new ObjectInputStream(socketPrivacy.getInputStream());
System.out.println("Sending Result to Apply Privacy....");
outputPrivacy.writeObject(result);
outputPrivacy.writeObject(params.get(2));
outputPrivacy.writeUTF(user);
outputPrivacy.writeUTF(sql);
outputPrivacy.flush();
System.out.println("Receiving Result of Privacy Service....");
result = concatList((ArrayList<String[]>) inputPrivacy.readObject(), (ArrayList<String[]>) resultSQL.get(1));
message = (String) inputPrivacy.readUTF();
Com esse cenário, posso usar o DataInputStream e DataOutputStream? O MQTT se aplicaria (apesar de não conhecer esse protocolo)?
Ah, então seria mais complicado usar só DataInputStream.
Usar BefferedOutputStream com ObjectOutputStream melhora a performance significativamente também, só não sei vai ser o suficiente pro seu caso.
// =================== ENVIANDO OS DADOS ===================
ObjectOutputStream outputPrivacy = new ObjectOutputStream(new BufferedOutputStream(socketPrivacy.getOutputStream()));
outputPrivacy.writeObject(result);
outputPrivacy.flush();
...
// =================== RECEBENDO OS DADOS ===================
ObjectInputStream inputPrivacy = new ObjectInputStream(new BufferedInputStream(socketPrivacy.getInputStream()));
ArrayList<String[]> result = (ArrayList<String[]>) inputPrivacy.readObject();
Mas a forma ideal de transportar dados entre serviços diferentes da mesma aplicação geralmente é por protocolos que segue o padrão publisher/subscriber como AMQP, SQS da Amazon, Kafka, acho que o MQTT também faz algo parecido.
Agradeço a ajuda. Vou incluir o BufferedOutputStream e ver se melhora o desempenho. Sobre os protocolos, como funciona o Kafka? Ele é uma plataforma que tenho que instalar e configurar em outra máquina ou um biblioteca que adiciona às minhas aplicações Java?
O Kafka é uma plataforma que você sobe e configura em alguma máquina (ou em várias) da mesma forma que você instala e configura um banco de dados separadamente da aplicação. Aí a sua aplicação vai enviar e ouvir mensagens do Kafka. Existem bibliotecas em várias linguagens que facilita acessar, mandar mensagens, configurar um cluster Kafka.
Você pode ouvir vários termos como publisher/subscriber, filas, message broker, mensageria, etc. Cada um talvez tenha um significado levemente diferente, mas no geral todos significa você centralizar o envio/recebimento de mensagens num lugar pra permitir troca de mensagens/dados entre vários serviços da aplicação.
Obrigado novamente pela informação sobre Kafka, vou estudar melhor. Achei muito interessante. Sobre a aplicação, não dá erro, é como se entrasse em um loop infinito.
Pode ser um deadlock. As threads devem estar bloqueadas esperando o fim da conexão, mas como nenhum dos lados encerra, a conexão fica “pendurada” e as respectivas threads ficam bloqueadas, esperando a troca de mais dados. Nesses casos, é interessante que você defina algum tipo de “terminandor” da transmissão, para que quando o outro lado receber esse “terminador” a outra ponta encerre a conexão.