Quantas requisiçõe o tomcat aguenta? Será menos de 1000?

Estou desenvolvendo uma apicação dentro do tomcat6.
Sendo que, eu recebe várias requisições através de uma servlet que é chamada por um outro pc.
Esta servlet recebe uns parâmetros via GET e guarda os mesmos em um arquivo, ela abre e fecha o arquivo, usando a java.io.File e java.io.FileOutputStream, para abrir e escrever em um arquivo.
Eu uso o log4j para fazer uns logs.
Sendo que quando coloquei esta Servlet para fazer alguns testes com ela recebendo 1000 requisições, mas quando chega na 970ª requisição da um erro de status 500, erro interno do servidor.
O tomcat6 não aguenta muitas requisições? Será que tenho que mudar de jsp para servlet? Alguém saberia explicar o que está acotencendo?

Isso vai depender basicamente de três variáveis: 1) a máquina que o tomcat roda, 2) a configuração (tunning) dele, 3) e o que a sua aplicação faz, e se ela faz “performaticamente” bem.

Quanto ao número de requisições, com certeza o Tomcat suporta mais do que 1000 requisições, isso é certo.

Em todo caso, coloque aí a maneira como está sendo iniciado o tomcat.

ps.: talvez já esteja usando, mas sugiro o JMeter (jakarta.apache.org/jmeter/) para estes testes :slight_smile:

Bom dia,

Brother, o melhor jeito de vc obter essa informação é utilizando uma ferramenta de monitoramento.
Eu utilizo o Lambda Probe, com ele consigo ver em tempo real o número de requisições, e gráficos mostrando como está o desempenho da aplicação com aquelas X requisições.
Dá uma olhada:
http://www.lambdaprobe.org/d/index.htm

t+

Segue um bom tutorial sobre o JMeter: http://javaboutique.internet.com/tutorials/JMeter/

A máquina que o tomcat está rodando, pelo menos eu acho, muito boa, é uma 8 core, ou seja 4 processadores, cada um com 2 núcleo, e 6 a ou 8 gigas de ram, e o tomcaat tá com as configurações default.
E vou colocar aqui o código da servlet e da classe que grava os parâmetros get no arquivo.

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import control.Catcher;

public class MainServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		File fileProperties = new File("/usr/local/apache-tomcat-6.0.16/webapps/AppWeb/WEB-INF/config/conf.properties");
		FileInputStream fileInputStream = new FileInputStream(fileProperties);
		Properties properties = new Properties();
		properties.load(fileInputStream);
		OpenFile.PATH_TXT = properties.getProperty("PATH_TXT");
		OpenFile.PATH_LOG = properties.getProperty("PATH_LOG");
		OpenFile.LAYOUT_LOG = properties.getProperty("LAYOUT_LOG");
		OpenFile.PREFIX_FILE_LOG = properties.getProperty("PREFIX_FILE_LOG");
		fileInputStream.close();
		OpenFilecatcher = new OpenFile(request.getRemoteAddr(), request.getQueryString());
		OpenFile.saveGetInDisk();
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<body>");
		out.println("<p>REQUEST SUCESS</p>");
		out.println("&lt;/body&gt;");
		out.println("&lt;/html&gt;");
	}
}

[code]
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileOutputStream;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import util.BrazilCalendar;

public class OpenFile{

private String query;
private String ip;
private File file;
private BrazilCalendar brazilCalendar;
private static final Logger LOGGER = Logger.getLogger(Catcher.class);
public static String PATH_TXT ;
public static String PATH_LOG ;
public static String LAYOUT_LOG = "%d{yyyy-M-dd HH:mm:ss} [%t] %p %c %x - %m%n";
public static String PREFIX_FILE_LOG ;

public OpenFile(){
	super();
	BasicConfigurator.configure();
	PatternLayout patternLayout = new PatternLayout(Catcher.LAYOUT_LOG);
	Catcher.LOGGER.setLevel(Level.INFO);
	try {
		this.brazilCalendar = new BrazilCalendar();
		FileAppender fileAppender = new FileAppender(patternLayout, Catcher.PATH_LOG + Catcher.PREFIX_FILE_LOG + this.brazilCalendar.getFullDateForSystem("") + ".log");
		OpenFile.LOGGER.addAppender(fileAppender);
		OpenFile.LOGGER.info("------- NEW PROCESS -------");
		OpenFile.LOGGER.debug("TIME START: " + this.brazilCalendar.getFullDateForSystemWithHour("-"));
	} catch (IOException e) {
		OpenFile.LOGGER.info("------- NEW PROCESS -------");
		OpenFile.LOGGER.error("CANNOT OPEN FILE LOG");
		OpenFileOpenFile.LOGGER.error(e.getMessage());
		OpenFile.LOGGER.info("------- END PROCESS -------");
	}
}

public OpenFile(String query){
	this();
	this.setQuery(query);
}

public OpenFile(String ip, String query){
	this(query);
	this.setIp(ip);
}

/**
 * @return the query
 */
public String getQuery() {
	return query;
}

/**
 * @param query the query to set
 */
public void setQuery(String query) {
	this.query = query;
	OpenFile.LOGGER.info("SET QUERY: " + this.query);
}

/**
 * @return the Ip
 */
public String getIp() {
	return plexIp;
}

/**
 * @param Ip the Ip to set
 */
public void setIp(StringIp) {
	this.ip = Ip;
	OpenFile.LOGGER.info("SET IP: " + this.Ip);
}

public void saveMoQueueInDisk(){
	BrazilCalendar brazilCalendar = new BrazilCalendar();
	String fileName = "get" + brazilCalendar.getFullDateForSystem("") + ".txt";
	this.file = new File(OpenFile.PATH_TXT + fileName);
	if(!this.file.exists()){
		try {
			this.file.createNewFile();
			OpenFile.LOGGER.info("FILE CREATED");
		} catch (IOException e) {
			OpenFile.LOGGER.error("CANNOT CREATE FILE");
		}
	}
	try {			FileOutputStream fileOutputStream = new FileOutputStream(this.file, true);
		OpenFile.LOGGER.info("FILE OPEN: " + fileOutputStream.toString());
		String forFile = brazilCalendar.getFullDateForSystemWithHour("-") + " " + this.ip + " " + this.query + "\n";
		fileOutputStream.write(forFile.getBytes());
		fileOutputStream.flush();
		fileOutputStream.close();
		OpenFile.LOGGER.info("FILE CLOSED: " + fileOutputStream.toString());
		Catcher.LOGGER.info("DATA SAVED");
	} catch (FileNotFoundException e) {
		OpenFile.LOGGER.error("MESSAGE: " + e.getMessage());
		OpenFile.LOGGER.error("CAUSE: " + e.getCause());			
	} catch (IOException e) {
		OpenFile.LOGGER.error("MESSAGE: " + e.getMessage());
		OpenFile.LOGGER.error("CAUSE: " + e.getCause());
	} finally{
		OpenFile.LOGGER.debug("END TIME: " + this.brazilCalendar.getFullDateForSystemWithHour("-"));
		OpenFile.LOGGER.info("------- END PROCESS -------");
	}
}	

}[/code]

Como o jeveaux disse, vai depender realmente do seu “tunning” do tomcat.

De uma olhada neste link:
http://tomcat.apache.org/tomcat-6.0-doc/config/executor.html

Abraços

Utilizar Connector NIO do tomcat 6 é interessante pois ele usa api NIO que é mais performática que a API IO normal do java.

Dá uma olhada neste artigo: http://blog.covalent.net/roller/covalent/entry/20070308

mudei de IO para buffer, mas mesmo assim continua dando erro…
como posso configurar o tomcat para um ambiente de produção?

Você pode começar a mexer no Tomcat da forma que todos fazem, aumentando a memória alocada para o Tomcat. Apesar de não ser (sempre) a melhor alternativa de tunning, em quase todos os casos onde tunning é necessário, esta configuração também se faz necessária.

No bin/catalina.sh do seu tomcat existe uma variável chamada CATALINA_OPTS. Defina esta variável usando os parâmetros a seguir:

Xms - Quantidade de memória heap inicialmente alocada

Xmx - Quantidade de memória heap máxima a ser alocada

Você pode deixar mais ou menos assim:

CATALINA_OPTS = "-Xms256M -Xmx1024M"

Vale lembrar que estes valores que eu coloquei foram “chutes”. Aconselho você fazer um teste completo com JMeter e usar um Profiler na sua aplicação para acompanhar todo o comportamento dela e chegar em valores reais para a customização do seu tomcat.

Além dos parâmetros acima existem outros que são usado com menos frequência, como Xss (que definie o tamanho inicial do stack) Xmn e Xrs (que irão definir como/quanto o heap irá aumentar e diminuir) e vários outros que você pode encontrar neste link (http://blogs.sun.com/watt/resource/jvm-options-list.html).

Você já tentou fazer esse teste sem escrever o arquivo?

Tentei agora e rodou as 1000 requisições…

o código agora está assim para salvar em disco:

FileWriter fileWriter = new FileWriter(this.file);
BufferedWriter writerFile = new BufferedWriter(fileWriter);
OpenFile.LOGGER.info("FILE OPEN: " + writerFile.toString());
String forFile = brazilCalendar.getFullDateForSystemWithHour("-") + " " + this.ip + " " + this.query + "\n";
writerFile.write(forFile);
writerFile.close();
fileWriter.close();

Eu poderia criar uma única instância de um objeto com o arquivo aberto e usar o mesmo objeto para vária requisições?
Eu iria ganhar mais desempenho?

Por acaso esse é um servidor linux?

Os sistemas Linux/Unix geralmente limitam a quantidade de arquivos abertos por processo, não sei se é o caso.

É um sistema Linux sim…
Mas acho que o erro não seja esse, pq o sistema está configurado para 760.000 file descriptor por usuário… ou não seria isso?

Só para informar, fiz um teste tirando a parte do código que grava os dados em um arquivo e o erro continua, na requisição 950 eu recebo um status 500 do tomcat…

Ué, mas você conseguiu rodar ou não conseguiu? hehehe

Cole aí o stack trace do erro que está aparecendo

O primeiro teste que eu falei que rodou foi assim, dentro da servlet tem uma classe que eu chamo que abre o arquivo, grava os dados e fecha o arquivo, então, tirei o objeto de dentro da servlet. E rodou tranquilo.
No segundo teste deixei o objeto que faz as persistências no arquivo, mas tirei a parte que abre o arquivo, grava os dados e fecha. E não rodou as 1000 requisições.

O erro que eu recebo na linha de comando é este:

[quote]HTTP request sent, awaiting response… 500 Internal Server Error
11:15:11 ERROR 500: Internal Server Error.[/quote]

qual a sua server.xml?

qual o maxThreads? Qual o acceptCount?

Sobre o limite de arquivos, você pegou esse valor em “/proc/sys/fs/file-max”?

Mas acho que realmente não seja isso porque 1000 é um numero muito pequeno.

Talvez o erro seja de estouro de memoria ou algo assim.

Abra o arquivo de logs do tomcat e veja qual erro está dando e se não souber o que é, coloque aqui pra gente ver.

Com certeza isso esta com cara de ser estouro de memória e stack.

Cole aqui o stacktrace que aparece no log do tomcat.

Abraços.