JAVA, Performance
Mensageria
Bom pessoal, no último artigo falamos sobre melhorar performance utilizando-se de processamento paralelo (JAVA, Performance). Para continuarmos nossa demonstração de uso do WebSphere MQ, como o sistema de Mensageria em um ambiente utilizando-se linguagem JAVA, vamos construir uma pequena e simples aplicação de console, que lê um diretório e coloca os arquivos em uma fila MQ, e uma outra aplicação que lê desta fila e grava em outro diretório. Bom é claro que esta não é uma solução para nenhum caso visto que o SO (Windows, Linux e etc) já faz isso para você. Mas queremos mostrar como uma atividade dentro de sua aplicação pode ser separada pelo MQ para ganhar performance.
Abaixo nosso programa inicial, que faz a leitura de um diretório e a colocação na fila. O programa é bem simples e pode ser adaptado a qualquer contexto de simples execução.
package br.com.numeroreal; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import com.ibm.mq.MQC; import com.ibm.mq.MQEnvironment; import com.ibm.mq.MQMD; import com.ibm.mq.MQPutMessageOptions; import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQQueue; import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; public class dirPut { // private static MQQueueManager qMgr; private static MQQueue queue; // Enviroment private static String HOST = "192.168.1.100"; private static int PORT = 1414; private static String CHAN = "SYSTEM.DEF.SVRCONN"; // Queue Manager , Queue private static String qmName="QM"; private static String qName="FL.SERVICO.REQ"; // private static String dir="D://Temp-Req"; private static final int openOptions = MQC.MQOO_INQUIRE | MQC.MQOO_BROWSE | MQC.MQOO_OUTPUT | MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING; public dirPut() { } public static void main(final String[] args) throws MQException, IOException { /* * Verify parameters */ int verbose=0; for (String arg : args) { if (arg.contains("-H:")) { String[] argHost = arg.split(":"); HOST = argHost[1]; } if (arg.contains("-P:")) { String[] argPort = arg.split(":"); PORT = Integer.parseInt(argPort[1]); } if (arg.contains("-QM:")) { String[] argQM = arg.split(":"); qmName = argQM[1]; } if (arg.contains("-Q:")) { String[] argQ = arg.split(":"); qName = argQ[1]; } if (arg.contains("-D:")) { String[] argD = arg.split(":"); dir = argD[1]; } if (arg.contains("-help")) { System.out.println("Use: MQTester "); System.out.println(" -H:host Name"); System.out.println(" -P:Port"); System.out.println(" -QM:Queue Manager Name"); System.out.println(" -Q:Queue Name"); System.out.println(" -D:Path Directory"); System.out.println(" -help this help"); System.exit(0); } } if (verbose>0) { System.out.println("Parameters: "); System.out.println(" -H:"+HOST); System.out.println(" -P:"+PORT); System.out.println(" -QM:"+qmName); System.out.println(" -Q:"+qName); } // Enviroment variables MQEnvironment.hostname = HOST; MQEnvironment.port = PORT; MQEnvironment.channel = CHAN; qMgr = new MQQueueManager(qmName); queue = qMgr.accessQueue(qName, openOptions); System.out.println("Open"); System.out.println("-----------------------------------------------------------------"); // Read Directory File file = new File(dir); File afile[] = file.listFiles(); int i = 0; for (int j = afile.length; i < j; i++) { File arquivo = afile[i]; putMessage(arquivo); } System.out.println("-----------------------------------------------------------------"); queue.close(); qMgr.close(); } /* * MQ Put */ private static void putMessage(File fileMsg) throws MQException, IOException { MQMessage fileMessage = new MQMessage(); MQPutMessageOptions pmo = new MQPutMessageOptions(); pmo.options = MQC.MQPMO_SYNCPOINT; fileMessage.applicationIdData=fileMsg.getName(); fileMessage.applicationOriginData=fileMsg.getName(); fileMessage.userId =fileMsg.getName(); fileMessage.writeBytes("["+fileMsg.getName()+"]"); BufferedReader br = new BufferedReader(new FileReader(fileMsg)); while (br.ready()) { fileMessage.write(br.read()); } queue.put(fileMessage, pmo); qMgr.commit(); } }
Abaixo nosso programa final, que realiza a retirada da fila de cada mensagem (arquivo), e grava em um diretório. Podemos até pensar que o MQ é o ponto de contato entre estes 2 ambientes operacionais.
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import com.ibm.mq.MQC; import com.ibm.mq.MQEnvironment; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQQueue; import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; public class getDir { // private static MQQueueManager qMgr; private static MQQueue queue; // Enviroment private static String HOST = "192.168.1.100"; private static int PORT = 1414; private static String CHAN = "SYSTEM.DEF.SVRCONN"; // Queue Manager , Queue private static String qmName="QM"; private static String qName="FL.SERVICO.REQ"; // private static String dir="D://Temp-Resp"; private static final int openOptions = MQC.MQOO_INQUIRE | MQC.MQOO_BROWSE | MQC.MQOO_OUTPUT | MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING; public getDir() { // MQQueueManager qMgr; MQQueue queue; // Enviroment String HOST = "10.205.105.189"; int PORT = 1414; String CHAN = "IIB.TO.WAS"; // Queue Manager , Queue String qmName="IIB9QM"; String qName="FL.APOIO"; // String dir="D://Temp-Resp//"; final int openOptions = MQC.MQOO_INQUIRE | MQC.MQOO_BROWSE | MQC.MQOO_OUTPUT | MQC.MQOO_INPUT_SHARED | MQC.MQOO_FAIL_IF_QUIESCING; } public static void main(String[] args) throws MQException, IOException { /* * Verify parameters */ int verbose=0; for (String arg : args) { if (arg.contains("-H:")) { String[] argHost = arg.split(":"); HOST = argHost[1]; } if (arg.contains("-P:")) { String[] argPort = arg.split(":"); PORT = Integer.parseInt(argPort[1]); } if (arg.contains("-QM:")) { String[] argQM = arg.split(":"); qmName = argQM[1]; } if (arg.contains("-Q:")) { String[] argQ = arg.split(":"); qName = argQ[1]; } if (arg.contains("-D:")) { String[] argD = arg.split(":"); dir = argD[1]; } if (arg.contains("-help")) { System.out.println("Use: MQTester "); System.out.println(" -H:host Name"); System.out.println(" -P:Port"); System.out.println(" -QM:Queue Manager Name"); System.out.println(" -Q:Queue Name"); System.out.println(" -D:Path Directory"); System.out.println(" -help this help"); System.exit(0); } } if (verbose>0) { System.out.println("Parameters: "); System.out.println(" -H:"+HOST); System.out.println(" -P:"+PORT); System.out.println(" -QM:"+qmName); System.out.println(" -Q:"+qName); } // Write Directory File file = new File(dir); // Enviroment variables MQEnvironment.hostname = HOST; MQEnvironment.port = PORT; MQEnvironment.channel = CHAN; qMgr = new MQQueueManager(qmName); queue = qMgr.accessQueue(qName, openOptions); System.out.println("Open"); System.out.println("-----------------------------------------------------------------"); File arquivo; String mensagem; if (queue.getCurrentDepth()>0) { for(int i=1;i<=queue.getCurrentDepth();i++) { MQMessage msg = get(); mensagem = null; mensagem = msg.readStringOfByteLength(msg.getMessageLength()); arquivo = new File(dir+"//"+mensagem.substring(1, mensagem.indexOf("]"))); mensagem = mensagem.substring(mensagem.indexOf("]"),mensagem.length()); FileOutputStream fos = null; fos = new FileOutputStream(arquivo); fos.write(mensagem.getBytes()); fos.close(); } } System.out.println("-----------------------------------------------------------------"); queue.close(); qMgr.close(); } /* * MQ Get */ private static MQMessage get() throws MQException { MQMessage rcvMessage = new MQMessage(); MQGetMessageOptions gmo = new MQGetMessageOptions(); gmo.options = MQC.MQGMO_NONE; queue.get(rcvMessage, gmo); return rcvMessage; } }
Explicando o paralelismo, segundo a Lei de Amhdal.
Com base na Lei de Amhdal, vimos que não só existe a possibilidade de paralelismo entre alguns processos, como existe ainda uma forma de calcular até onde podemos realizar o paralelismo. Neste caso específico o paralelismo esta limitado ao sistema operacional, que provoca um semáforo para acesso ao recurso operacional , o disco. Então devemos ter este cuidado, mas para explicar como a performance será aumentada sem o uso de threads, recurso geralmente não permitido em ambientes onde existem Servidores de Aplicação, podemos apenas ter , por exemplo, 3 processos sendo executados em paralelo para a retirada da fila, assim a gravação dos arquivos será bem mais rápida que se fosse realizada por apenas 1 processo, tal qual como existe em um único programa sendo executado.
Então vamos propor um outro cenário onde retiramos da fila e colocamos esta mensagem em um Banco de Dados, assim teríamos um cenário possível de se acontecer no mundo real. Agora pense de forma semelhante ao apontado no parágrafo anterior, ou seja vamos ter vários trabalhadores para inserir no Banco de Dados, reduzindo o tempo de processamento.
Bom pessoal, este foi mais uma etapa das matérias sobre Java-Performance, que estamos abordando, em especifico utilizando Mensageria como uma solução, em breve retornamos com mais exemplos, e casos de utilização.
Clique aqui, para o download dos fontes do programas citados acima.
O post JAVA, Performance (Mensageria) – Parte II apareceu primeiro em NumeroReal.