I am running 2 java (7) servlets on a tomcat 7 VPS server. One servlet returns a json response and the other servlet returns 4 lines of pure html code.
If I only run the json response servlet, I have no problems handling 12+ million request per day (~140 request per second).
Currently I run only half the traffic on the json servlet (so ~70 request per second).
if I add the servlet which returns html the server response time explodes and returns errors when the number of requests not even reaches 20 per second for this servlet. (So the total amount of requests is ~90 per second).
However if the requests for the html servlet drop to ~2 per minute everything is fine. So it looks like the servlet itself doesn't have any errors.
the two servlets which I am running are:
// Loading required libraries
import java.lang.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.DataSource;
import javax.naming.*;
import java.util.Random;
import java.math.*;
import java.security.*;
import java.sql.*;
/**
* Servlet implementation class test
*/
@WebServlet("/html")
public class html extends HttpServlet{
private static final long serialVersionUID = 12L;
public html() {
super();
// TODO Auto-generated constructor stub
}
private DataSource dataSource;
public void init() throws ServletException {
try {
// Get DataSource
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/testdb");
System.out.println("Obtained Cached Data Source ");
} catch (NamingException e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Get all parameters from request.
String source = null;
String UA = null;
String id = null;
String ip = null;
source = request.getParameter("source");
UA = request.getHeader("User-Agent");
//is client behind something?
ip = request.getHeader("X-FORWARDED-FOR");
if (ip == null) {
ip = request.getRemoteAddr();
}
Connection conn = null;
Statement stmt = null;
int exit = 0;
// Set response content type
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try{
// Open a connection
conn = dataSource.getConnection();
stmt = conn.createStatement();
// Execute SQL query
stmt = conn.createStatement();
String sql;
sql = "SELECT data from db";
ResultSet rs = stmt.executeQuery(sql);
rs.next();
String url = rs.getString("url");
String url_src = rs.getString("url_src");
out.println("<html>");
out.println("<body>");
out.println("<a href=\"url\">");
out.println("<img src=\"url_src\"/></a>");
out.println("</body></html>");
long time = System.currentTimeMillis()/1000;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(250);
String toEnc = ip + time + UA + randomInt; // Value to hash
MessageDigest mdEnc = MessageDigest.getInstance("MD5");
mdEnc.update(toEnc.getBytes(), 0, toEnc.length());
id = new BigInteger(1, mdEnc.digest()).toString(16);// Hashed
sql = "insert request";
stmt.execute(sql);
// Clean-up environment
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}finally{
//finally block used to close resources
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}// nothing we can do
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}//end finally try
} //end try*/
}
}
And the second servlet is:
// Loading required libraries
import java.lang.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.sql.DataSource;
import javax.naming.*;
import java.util.Random;
import java.math.*;
import java.security.*;
import java.sql.*;
/**
* Servlet implementation class test
*/
@WebServlet("/json")
public class json extends HttpServlet{
private static final long serialVersionUID = 11L;
public json() {
super();
// TODO Auto-generated constructor stub
}
private DataSource dataSource;
public void init() throws ServletException {
try {
// Get DataSource
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/testdb");
System.out.println("Obtained Cached Data Source ");
} catch (NamingException e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// Get all parameters from request.
String source = null;
String UA = null;
String id = null;
String ip = null;
source = request.getParameter("source");
UA = request.getParameter("ua");
ip = request.getParameter("clientIP");
Connection conn = null;
Statement stmt = null;
int exit = 0;
// Set response content type
response.setContentType("application/json");
PrintWriter out = response.getWriter();
try{
// Open a connection
conn = dataSource.getConnection();
stmt = conn.createStatement();
// Execute SQL query
stmt = conn.createStatement();
String sql;
sql = "SELECT * from db";
ResultSet rs = stmt.executeQuery(sql);
rs.next();
String url = rs.getString("url");
String url_src = rs.getString("url_src");
String jsonResponse = "{\"url\":\"url\","\"media_url\":\"url_src\"}";
out.println(jsonResponse);
long time = System.currentTimeMillis()/1000;
Random randomGenerator = new Random();
int randomInt = randomGenerator.nextInt(250);
String toEnc = ip + time + UA + randomInt; // Value to hash
MessageDigest mdEnc = MessageDigest.getInstance("MD5");
mdEnc.update(toEnc.getBytes(), 0, toEnc.length());
id = new BigInteger(1, mdEnc.digest()).toString(16);// Hashed
sql = "insert request";
stmt.execute(sql);
// Clean-up environment
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}finally{
//finally block used to close resources
try{
if(stmt!=null)
stmt.close();
}catch(SQLException se2){
}// nothing we can do
try{
if(conn!=null)
conn.close();
}catch(SQLException se){
se.printStackTrace();
}//end finally try
} //end try*/
}
}
I have setup a connection pool with JDBC. And I have the following config.xml file:
<?xml version='1.0' encoding='utf-8'?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- The contents of this file will be loaded for each web application -->
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Resource name="jdbc/testdb"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/database"
username="username"
password="password"
maxActive="250"
maxIdle="60"
minIdle="30"
maxWait="10000"
poolPreparedStatements="true"
maxOpenPreparedStatements="100"
/>
</Context>
I have set the envirenment variables or JAVA_OPTS in the file /tomcat/bin/setenv.sh:
export CATALINA_OPTS="-Djava.library.path=/usr/local/apr/lib"
NORMAL="-d64 -Xmx1536m -Xms512m -server"
MAX_PERM_GEN="-XX:MaxPermSize=512m"
HEADLESS="-Djava.awt.headless=true"
JAVA_OPTS="$NORMAL $MAX_PERM_GEN $HEADLESS"
export JAVA_OPTS
My vps has 2gb of ram, with 4 cpu cores of 2ghz. I have tried changing the heap size or the MaxPermSize but it does not seem to matter.
Can someone explain to me what I am doing wrong with the configuration? I don't understand why the server could handle so much load with just one servlet and crashes when the traffic is split over another.
Thanks