Linuxhotel Wiki

Wie ging das nochmal?

Benutzer-Werkzeuge

Webseiten-Werkzeuge


tomcat_administration:start

Dies ist eine alte Version des Dokuments!


Tomcat

Pre Installation

sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) universe"
sudo apt-get update
sudo apt-get install tree
sudo apt-get install curl

Java Installation

Pakete

Ubuntu 8.04, Debian Lenny:

sun-java6-jdk

Ubuntu 10.04:

openjdk-6-jdk



Aufgrund der geänderten Oracle Lizenzbestimmungen, wurden die Oracle Java Packete aus den Standard-Repositories entfernt. non-free wird für die bequeme Installation benötigt, /etc/apt/sources.list anpassen.

Debian 6 Squeeze:

deb http://ftp.de.debian.org/debian/ squeeze main non-free
deb-src http://ftp.de.debian.org/debian/ squeeze main non-free
deb http://security.debian.org/ squeeze/updates main non-free
deb-src http://security.debian.org/ squeeze/updates main non-free
# squeeze-updates, previously known as 'volatile'
deb http://ftp.de.debian.org/debian/ squeeze-updates main non-free
deb-src http://ftp.de.debian.org/debian/ squeeze-updates main non-free

Mint 13:

deb http://packages.linuxmint.com/ maya main upstream import non-free

Java Konfiguration

Debian / Ubuntu:

update-alternatives --config java

java-6-sun auswählen

Oracle Java 7 Installation

java -version
sudo apt-get purge openjdk*
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer
java -version

Alternative Oracle Java 7 Installation

sudo mkdir -p /usr/lib/jvm
cd ~/Downloads
sudo cp jdk-7u21-linux-i586.tar.gz /usr/lib/jvm
cd /usr/lib/jvm
sudo tar zxvf jdk-7u21-linux-i586.tar.gz
sudo rm jdk-7u21-linux-i586.tar.gz
ls -l
#jdk1.7.0_21
sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.7.0_21/bin/javac" 1
sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.7.0_21/bin/java" 1
sudo update-alternatives --set "javac" "/usr/lib/jvm/jdk1.7.0_21/bin/javac"
sudo update-alternatives --set "java" "/usr/lib/jvm/jdk1.7.0_21/bin/java"
sudo nano /etc/profile

/etc/profile : ( anhängen )

JAVA_HOME=/usr/lib/jvm/jdk1.7.0_21
PATH=$PATH:$JAVA_HOME/bin
export JAVA_HOME
export PATH
. /etc/profile
java –version
java version 1.7.0_21
#Java(TM) SE Runtime Environment (build 1.7.0_21-b12)
#Java HotSpot(TM) Client VM (build 23.21-b01, mixed mode)
javac –version
#javac 1.7.0_21

Alternative Oracle Java 8 Installation

echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | \
  tee /etc/apt/sources.list.d/webupd8team-java.list
echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | \
  tee -a /etc/apt/sources.list.d/webupd8team-java.list
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
apt-get update
echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | \
  /usr/bin/debconf-set-selections
apt-get install -yq oracle-java8-installer
apt-get install -yq oracle-java8-set-default

Tomcat Installation von Hand

Tomcat 6: Linux .tar.gz runterladen von: http://tomcat.apache.org/download-60.cgi z.B.:

cd
mkdir workshop
cd workshop
wget http://www.osnt.org/apache/tomcat/tomcat-6/v6.0.38/bin/apache-tomcat-6.0.38.tar.gz
tar xzf apache-tomcat-6.0.38.tar.gz
ln -s apache-tomcat-6.0.38 apache-tomcat

Tomcat 7: Linux .tar.gz runterladen von: http://tomcat.apache.org/download-70.cgi z.B.:

cd
mkdir workshop
cd workshop
wget http://www.osnt.org/apache/tomcat/tomcat-7/v7.0.52/bin/apache-tomcat-7.0.52.tar.gz
tar xzf apache-tomcat-7.0.52.tar.gz
ln -s apache-tomcat-7.0.52 apache-tomcat

Tomcat 8: Linux .tar.gz runterladen von: http://tomcat.apache.org/download-80.cgi z.B.:

cd
mkdir workshop
cd workshop
wget http://www.osnt.org/apache/tomcat/tomcat-8/v8.0.24/bin/apache-tomcat-8.0.32.tar.gz
tar xzf apache-tomcat-8.0.32.tar.gz
ln -s apache-tomcat-8.0.32 apache-tomcat

Tomcat Minimal Konfiguration

cd
cd workshop
mkdir node73
cd node73
mkdir bin conf webapps logs work temp
# File server und JSP Support only!
#cp ../apache-tomcat/conf/web.xml conf/

conf/server.xml : ( komplett, kurze Version )

<?xml version='1.0' encoding='utf-8'?>
<Server port="${port.prefix}05" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
 
  <Service name="Catalina">
    <Connector port="${port.prefix}80" 
               protocol="HTTP/1.1" 
               />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="node${port.prefix}">
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true" >
      </Host>
    </Engine>
  </Service>
</Server>

conf/server.xml : ( Tomcat 8 )

<?xml version='1.0' encoding='utf-8'?>
<Server port="${port.prefix}05" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
 
  <Service name="Catalina">
    <Connector port="${port.prefix}80"
      protocol="HTTP/1.1"
    />
    <Engine name="Catalina"
      defaultHost="localhost" jvmRoute="node${port.prefix}">
      <Host name="localhost"
          appBase="webapps">
      </Host>
    </Engine>
  </Service>
</Server>

bin/startup.sh :

#!/bin/bash
export CATALINA_HOME=~/workshop/apache-tomcat
export CATALINA_BASE=~/workshop/node73
export JAVA_OPTS="-Dport.prefix=73"
export CATALINA_OPTS="-Xmx128m"
export CATALINA_PID="${CATALINA_BASE}/logs/tomcat.pid"
${CATALINA_HOME}/bin/catalina.sh start $@

bin/shutdown.sh :

#!/bin/bash
export CATALINA_HOME=~/workshop/apache-tomcat
export CATALINA_BASE=~/workshop/node73
export JAVA_OPTS="-Dport.prefix=73"
export CATALINA_PID="${CATALINA_BASE}/logs/tomcat.pid"
${CATALINA_HOME}/bin/catalina.sh stop $@

Startfähigkeit herstellen

  chmod +x bin/startup.sh
  #cp -a bin/startup.sh bin/shutdown.sh
  chmod +x bin/shutdown.sh

Verzeichnisbaum nach dem Start

├── bin
│   ├── shutdown.sh
│   └── startup.sh
├── conf
│   ├── Catalina
│   │   └── localhost
│   └── server.xml
├── logs
│   ├── catalina.out
│   └── tomcat.pid
├── temp
├── webapps
└── work

Check der server.xml ab Apache Tomcat 7

bin/configtest.sh :

#!/bin/bash
export CATALINA_HOME=~/workshop/apache-tomcat
export CATALINA_BASE=~/workshop/node73
export JAVA_OPTS="-Dport.prefix=73"
${CATALINA_HOME}/bin/catalina.sh configtest $@

conf/web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
  <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
mkdir webapps/ROOT
echo "hello" >webapps/ROOT/index.html

Ergebnis einer index.html Auslieferung

nutzer18@notebook18:~/workshop/node73/conf$ telnet 127.0.0.1 7380
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /index.html HTTP/1.0 

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"6-1394459464000"
Last-Modified: Mon, 10 Mar 2014 13:51:04 GMT
Content-Length: 6
Date: Mon, 10 Mar 2014 13:59:42 GMT
Connection: close

hello
Connection closed by foreign host.
nutzer18@notebook18:~/workshop/node73/conf$ pwd

Mimetypes conf/web.xml

<web-app ....>
... 
  <!-- Nach servlet-mapping -->
  <mime-mapping>
        <extension>css</extension>
        <mime-type>text/css</mime-type>
  </mime-mapping>
  <mime-mapping>
        <extension>ico</extension>
        <mime-type>image/x-icon</mime-type>
  </mime-mapping>
  <mime-mapping>
        <extension>html</extension>
        <mime-type>text/html</mime-type>
  </mime-mapping>
  <mime-mapping>
        <extension>jpg</extension>
        <mime-type>image/jpeg</mime-type>
  </mime-mapping>
  <mime-mapping>
        <extension>js</extension>
        <mime-type>application/javascript</mime-type>
  </mime-mapping>
  <mime-mapping>
        <extension>json</extension>
        <mime-type>application/json</mime-type>
  </mime-mapping>
   <mime-mapping>
       <extension>png</extension>
       <mime-type>image/png</mime-type>
   </mime-mapping>
   <mime-mapping>
       <extension>xml</extension>
       <mime-type>application/xml</mime-type>
   </mime-mapping>
...
<web-app>

oder einfacher alles aus der Distribution übernehmen:)

cd workshop/node73
cp ../apache-tomcat/conf/web.xml conf/web.xml
bin/shutdown.sh -force
bin/startup.sh

Hinweis zur server.xml Konfiguration

Der Connector Parameter „HTTP/1.1“ steht für den Alias

org.apache.coyote.http11.Http11Protocol

wenn kein APR Listener erfolgreich den APR Native Libs gefunden hat. Wenn das APR initialisiert werden konnte, wird der ProtokollHandler auf die Klasse

org.apache.coyote.http11.Http11AprProtocol

gesetzt. Ähnliches gilt für den AJP/1.3 Alias. Das Projekt Apache Portable Runtime ist ein C-Lib die es ermöglich unter verschiedenen Betriebssystemen Threads, IO, usw. zu nutzen. Für den Tomcat existiert mit dem Projekt tcnative eine Anbindung für Java.

Testen

Tomcat starten:

./bin/startup.sh

Prozesse sehen:

jps
jps -v
lsof -a -i -c java
lsof -i | grep java
lsof -i | grep $(cat ../logs/tomcat.pid)

Speicherbelegung der Prozesse:

jstat -gc $(cat logs/tomcat.pid)

Free Memory

jstat -gc $(cat logs/tomcat.pid) | tail -1 | awk '{print "free old memory:",($7-$8)/1024, "mb"}'
jstat -gc $(cat logs/tomcat.pid) | tail -1 | awk '{print "free perm memory:",($9-$10)/1024, "mb"}'

Stacktrace ausgeben lassen:

kill -3 $(cat logs/tomcat.pid)
less logs/catalina.out
#stacktrace snapshot erzeugen
jstack -l $(cat logs/tomcat.pid) >"logs/stack-`date`"
firefox http://localhost:7380/

bin/restart.sh : ( restart Tomcat)

#!/bin/bash
~/workshop/node73/bin/shutdown.sh -force
~/workshop/node73/bin/startup.sh

Checks

Check Pid, Ports, Alive

  if [ -f ~/workshop/node73/logs/tomcat.pid ]; then
    pid_no=`cat ~/workshop/node73/logs/tomcat.pid`
    DATE=`date --rfc-3339=ns`
    ps_pid=`ps aux |grep -c $pid_no`
 
    echo "$DATE - OK - pid ($pid_no) existiert"
 
    if [ $ps_pid -gt 1 ]; then
      echo "$DATE - Ok - Zugehoeriger Prozess existiert"
    else
      echo "$DATE - Err - Zugehoeriger Prozess existiert nicht"
    fi
 
    port_7380=`lsof -i | grep $pid_no | grep -q ':7380' && echo -n "Ok - 7380" || echo -n "Err - 7380"` 
    port_7309=`lsof -i | grep $pid_no | grep -q ':7309' && echo -n "Ok - 7309" || echo -n "Err - 7309"` 
    port_7305=`lsof -i | grep $pid_no | grep -q ':7305' && echo -n "Ok - 7305" || echo -n "Err - 7305"` 
 
    for x in "$port_7380" "$port_7309" "$port_7305" ; do
      echo "$DATE - $x"
    done 
 
    temp=`curl --silent http://localhost:7380/test1/test1_ok.jsp | grep -c 'Ok'` 
    if [ $temp -eq 1 ]; then
      echo "$DATE - Ok - AliveCheck"
    else
      echo "$DATE - Err - AliveCheck"
    fi
  else
    echo "$DATE - Err: pid existiert nicht!"
  fi

Check JVM Free Mem

Prüfen ob noch genügend freier Speicher vorhanden ist:

bin/check_jvmfreemem.sh :

#!/bin/bash
# resolve links - $0 may be a softlink
case $0 in
    /*)
        PRG="$0"
        ;;
    *)
        PWD=`pwd`
        PRG="$PWD/$0"
        ;;
esac
 
while [ -h "$PRG" ]; do
  ls=`ls -ld "$PRG"`
  link=`expr "$ls" : '.*-> \(.*\)$'`
  if expr "$link" : '/.*' > /dev/null; then
    PRG="$link"
  else
    PRG=`dirname "$PRG"`/"$link"
  fi
done
cd "`dirname "$PRG"`"
PWD=`pwd`
PRGDIR=`dirname "$PWD"`
PID=$(cat ${PRGDIR}/logs/tomcat.pid)
DATE=`date --rfc-3339=ns`
 
MEMOLDUSAGE=$(jstat -gc $PID | tail -1 | awk '{print $(8)}')
PERFOLDDATA=$(jstat -gcoldcapacity $PID | tail -1 | awk -v usage=$MEMOLDUSAGE '{print "free old memory:",($2-usage)/1024, "mb ;", "percentage:",(($2-usage) * 100 / $2),"%" }')
MEMPERMUSAGE=$(jstat -gc $PID | tail -1 | awk '{print $(10)}')
PERFPERMDATA=$(jstat -gcpermcapacity $PID | tail -1 | awk -v usage=$MEMPERMUSAGE '{print "free perm memory:",($2-usage)/1024, "mb ;", "percentage:",(($2-usage) * 100 / $2),"%" }')
 
VALUE=$(echo $PERFOLDDATA | awk '{print int($8)}')
 
STATUS=OK
if [ $VALUE -lt $1 ] ; then
    STATUS=WARNING  
elif [ $VALUE -lt $2 ] ; then
    STATUS=CRITICAL
fi
 
echo $STATUS
 
if [ $STATUS != "CRITICAL" ] ; then
VALUE=$(echo $PERFPERMDATA | awk '{print int($8)}')
 
if [ $VALUE -lt $3 ] ; then
    STATUS=WARNING
elif [ $VALUE -lt $4 ] ; then
    STATUS=CRITICAL
fi
fi
 
echo "JVMFREEMEM $STATUS - $DATE$PERFOLDDATA | $PERFPERMDATA" 
case $STATUS in
	OK) exit 0 ;;
	WARNING) exit 1 ;;
	CRTICAL) exit 2 ;;
	*) exit 3;;
esac

Check TomcatStartup State

Als Parameter benötigt das Skript den Pfad zur Logdatei.

bin/check_tomcatstartup.sh :

#!/bin/bash
OIFS=$IFS
IFS=$'
'
 
LOGFILE=$1
RESPONSE_CODE_OK=0
RESPONSE_CODE_WARNING=1
RESPONSE_CODE_CRITICAL=2
RESPONSE_CODE_UNKNOWN=3
 
WARN_COUNT=0
ERROR_COUNT=0
ANALYSE_STATE=0
 
if [ ! -f $LOGFILE ]; then
   IFS=$OIFS
   echo "File not found"
   exit $RESPONSE_CODE_UNKNOWN
fi
 
for x in $(tac $LOGFILE) ;
  do
	if [ `echo $x | grep 'Server startup in' ` ]; then
	  ANALYSE_STATE=1
	fi;
 
	if [ ${ANAlYSE_STATE}="1" ]; then
		if [ `echo $x | grep 'ERROR'` ]; then
              		ERROR_COUNT=$(($ERROR_COUNT+1))
		fi;
		if [ `echo $x | grep 'WARN' ` ]; then
			WARN_COUNT=$(($WARN_COUNT+1))
		fi;
 
		if [ `echo $x | grep 'Starting service Catalina'` ]; then
                        break
                fi;
	fi;
done ;
 
IFS=$OIFS
 
if [ $ERROR_COUNT -ge "1" ]; then
   echo "TomcatStartupCheck - CRITICAL | "
   echo "WARN COUNT: $WARN_COUNT"
   echo "ERROR COUNT: $ERROR_COUNT | "
   exit $RESPONSE_CODE_CRITICAL
fi
 
if [ $WARN_COUNT -ge "1" ]; then
   echo "TomcatStartupCheck - WARNING | "
   echo "WARN COUNT: $WARN_COUNT"
   echo "ERROR COUNT: $ERROR_COUNT | "
   exit $RESPONSE_CODE_WARNING
fi
 
if [ ${ANAlYSE_STATE}="1" ];
   then
      echo "TomcatStartupCheck - OK | "
      echo "WARN COUNT: $WARN_COUNT"
      echo "ERROR COUNT: $ERROR_COUNT | "
      exit $RESPONSE_CODE_OK
   else
      echo "TomcatStartupCheck - UNKNOWN | "
      echo "WARN COUNT: $WARN_COUNT"
      echo "ERROR COUNT: $ERROR_COUNT | "
      exit $RESPONSE_CODE_UNKNOWN
fi

Applikationen

Hello World

mkdir webapps/hello

webapps/hello/index.jsp :

hello! <br>
es ist <%=new java.util.Date() %> Uhr!
firefox http://localhost:7380/hello/

Hello World Servlet

mkdir -p webapps/hello/WEB-INF/classes
cd webapps/hello/WEB-INF/classes
vi HelloWorld.java

webapps/hello/WEB-INF/classes/HelloWorld.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}
javac -cp ~/workshop/apache-tomcat/lib/servlet-api.jar HelloWorld.java
cd ..
vi web.xml

webapps/hello/WEB-INF/web.xml

<web-app>
    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/world</url-pattern>
    </servlet-mapping>
</web-app>

Restart des Servers

cd ~/workshop/node73
bin/shutdown.sh
bin/startup.sh
firefox http://localhost:7380/hello/world

Test mit telnet

nutzer20@notebook20:~/workshop/node73$ telnet 127.0.0.1 7380
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
GET /hello/world HTTP/1.0

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html
Content-Length: 103
Date: Thu, 08 Mar 2012 14:10:34 GMT
Connection: close

<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Connection closed by foreign host.

Autoreload auf WEB-INF/web.xml

node73/conf/context.xml

<Context>
   <WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>

Autoreload für Änderungen von Klassen aller Anwendungen

node73/conf/context.xml

<Context reloadable="true">
   <WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>

Nun muss der Server ebenfalls nochmals restartet werden. Ab jetzt kann man Änderungen an der Java Quelle Datei vornehmen und nach jeder Übersetzung wird diese in der Laufenden Anwendung sichtbar.

Ab dem Apache Tomcat 7 mit dem Servlet API 3.0 lassen sich die Konfigurationen auch direkt in den Servlet Code schreiben:

Anlage der Anwendung world

cd ~/workshop/node73/webapps
mkdir world
mkdir world/WEB-INF
mkdir world/WEB-INF/classes
mkdir world/WEB-INF/classes/world
cd world/WEB-INF/classes/world
vi Hello.java
javac -cp ~/workshop/apache-tomcat/lib/servlet-api.jar Hello.java
# restart des Servers
package world;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet ;

@WebServlet("/hello")
public class Hello extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

.war

mkdir /tmp/hello2

/tmp/hello2/index.jsp :

hello2! <br>
es ist <%=new java.util.Date() %> Uhr!
jar cf hello2.war -C /tmp/hello2/ index.jsp
cp hello2.war webapps/
firefox http://localhost:7380/hello2/

Tomcat 6 Installation mit Ubuntu

Ubuntu Standard Tomcat Installation

sudo apt-get install tomcat6
sudo apt-get install tomcat6-admin

User Node Installation für Test

sudo apt-get install tomcat6-user 
tomcat6-instance-create node91 -p 9180 -c 9105 -w qwewqeiq879qewq
node91/bin/startup.sh
node91/bin/shutdown.sh

Basic Authentication

Application hello mit Basic Authentication absichern

conf/server.xml :

<Server ..>
..
  <GlobalNamingResources>
    <Resource name="UserDatabase" 
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
 
  <Service ..>
    <Engine ..>
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
        ..
    </Engine>
  </Service>
</Server>

conf/tomcat-users.xml :

<tomcat-users>
  <user username="manager" password="tomcat" roles="manager-gui" />
</tomcat-users>

webapps/hello/WEB-INF/web.xml :

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5"> 

  <display-name>Hello World Application</display-name>
  <description>
    Tolle Hello World Application
  </description>
  <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/world</url-pattern>
    </servlet-mapping>
  <!-- Define a Security Constraint on this Application -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Hello</web-resource-name>
      <url-pattern>/index.jsp</url-pattern>
      <url-pattern>/world</url-pattern>

      <!-- <url-pattern>/html/*</url-pattern>  -->
    </web-resource-collection>
    <auth-constraint>
       <!-- NOTE:  This role is not present in the default users file -->
       <role-name>manager-gui</role-name>
    </auth-constraint>
  </security-constraint>

  <!-- Define the Login Configuration for this Application -->
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Hello World Application</realm-name>
  </login-config>

  <!-- Security roles referenced by this web application -->
  <security-role>
    <description>
      The role that is required to log in to the Hello Application
    </description>
    <role-name>manager-gui</role-name>
  </security-role>

  <error-page>
    <error-code>401</error-code>
    <location>/401.jsp</location>
  </error-page>

</web-app>

Syntax Tomcat 6 Servlet Api 2.5 checken:

xmllint --noout --schema http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd webapps/hello/WEB-INF/web.xml

Syntax Tomcat 7 - Servlet API 3.0 checken:

xmllint --noout --schema http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd webapps/hello/WEB-INF/web.xml

webapps/hello/401.jsp :

hello error 401

Setzen einer kontrollierten Fehlerreaktion für „File not found“ Status Code 404 webapps/hello/WEB-INF/web.xml

<web-app>
..
  <error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
  </error-page>
  <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/exception.jsp</location>
  </error-page>

..
</web-app>

Für Tomcat 7 ist das web-app Schema folgendes.

webapps/hello/WEB-INF/web.xml :

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0">
</web-app>

webapps/hello/404.jsp :

<%@ page session="false" isErrorPage="true" %>

<html>
<head><title>404 Not Found</title></head>
<body>
<h1>404 Not Found</h1>

The url <code>${requestScope["javax.servlet.error.request_uri"]}</code> 
was not found.
</body>
</html>

Verfügbare RequestScope Attribute

Attribute Type
javax.servlet.error.status_code java.lang.Integer
javax.servlet.error.message java.lang.String
javax.servlet.error.request_uri java.lang.String
javax.servlet.error.servlet_name java.lang.String
javax.servlet.error.exception java.lang.Throwable
javax.servlet.error.exception_type java.lang.Class

webapps/hello/my.jsp :

<%@ page session="false" errorPage="exception.jsp" %>
<html>
<head><title>My World</title></head>
<body>
<h1>Yep</h1>
<%
	if(true) {
		throw new RuntimeException("my world");
	}
%>
</body>
</html>

webapps/hello/exception.jsp :

<%@ page session="false" isErrorPage="true" import="java.io.*" %>
<html>
<head>
	<title>Exceptional Even Occurred!</title>
	<style>
	body, p { font-family:Tahoma; font-size:10pt; padding-left:30; }
	pre { font-size:8pt; }
	</style>
</head>
<body>

<%-- Exception Handler --%>
<font color="red">
<%= exception.toString() %><br>
</font>

<%
out.println("<!--");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
exception.printStackTrace(pw);
out.print(sw);

sw.close();
pw.close();
out.println("-->");
application.log(sw.toString());

%>

</body>
</html>

Digest password

Generierung des Password mit Digest

apache-tomcat/bin/digest.sh -a SHA1 manager

Eintragen der Password in die tomcat-users.xml

node73/conf/tomcat-users.xml:

<tomcat-users>
  <user username="manager" password="536c0b339345616c1b33caf454454d8b8a190d6c" roles="manager-gui" />
  <user username="tomcat" password="536c0b339345616c1b33caf454454d8b8a190d6c" roles="user" />

</tomcat-users>

Eintragen des Digest Algo im Realm node73/conf/server.xml

..
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="node${port.prefix}">
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             digest="SHA1" 
             resourceName="UserDatabase"/>
..
    </Engine>

Restart des Servers

Manager Application

Erste Option ist die Übernahme der manager Anwendung in die Node.

cp -a ../apache-tomcat/webapps/manager/ webapps/

Besser wäre eine Referenz der Manager Anwendung in den Node zuvereinbaren.

conf/Catalina/localhost/manager.xml :

<Context docBase="${catalina.home}/webapps/manager" antiResourceLocking="false" privileged="true" useHttpOnly="true"/>
firefox http://localhost:7380/manager/html

Benutzername: manager Password: tomcat ( siehe conf/tomcat-users.xml )

conf/tomcat-users.xml

<tomcat-users>
<user name="manager" password="tomcat" roles="manager-gui" />
</tomcat-users>

Tomcat 8: conf/tomcat-users.xml

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
  <role rolename="manager-gui"/>
  <user username="manager" password="tomcat" roles="manager-gui"/>
</tomcat-users>

Mit dem GlobalResourcesLifecycleListener werden die Daten der UserDatabase im MbeanServer (JMX) veröffentlicht und sind damit änderbar. Wenn die UserDatabase schreibar ist, kann man die Änderungen sogar wieder speichern.

Vorsicht die Passwörter sind via JMX einsehbar und evtl. temporär änderbar!!!

conf/server.xml

<Server .. >
 <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" 
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" 
              readonly="false" />
  </GlobalNamingResources>
  <Service ..>
    <Engine ..>
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
        ..
    </Engine>
  </Service>
<Server/> 

Zur Installation von Anwendungen auf dem Server kann man auch curl nutzen. Dazu ist es notwendig das der „User“ der Manager Anwendung in der Role „manager-script“ eingetragen ist.

curl --user manager:tomcat "http://localhost:7380/manager/text/deploy?path=/docs&config=file:/home/nutzer18/workshop/node73/docs.xml"

docs.xml

<Context docBase="${catalina.home}/webapps/docs" />

Einschränkung des Zugriffs auf die Manager Anwendung nur vom lokalen Host conf/Catalina/localhost/manager.xml :

<Context docBase="${catalina.home}/webapps/manager" antiResourceLocking="false" privileged="true" useHttpOnly="true">
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192\.168\.1\.\d+"/>
</Context>

conf/server.xml

    <Engine ...>
    
    
    <Realm className="org.apache.catalina.realm.LockOutRealm">
         <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
              resourceName="UserDatabase"/>

    </Realm>
   
   ...
   </Engine>

Weitere Manager Berechtigungen

conf/tomcat-users.xml

<tomcat-users>
<user name="manager" password="tomcat" roles="manager-gui" />
<user name="script" password="tomcat" roles="manager-script" />
<user name="jmx" password="tomcat" roles="manager-jmx" />
<user name="status" password="tomcat" roles="manager-status" />
</tomcat-users>
curl -u status:tomcat http://localhost:7380/manager/status/all?XML=true 

Ergebnis

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/manager/xform.xsl" ?>
<status>
    <jvm>
        <memory free="61724312" total="72613888" max="119341056"/>
        <memorypool name="PS Eden Space" type="Heap memory" usageInit="15007744" usageCommitted="30015488" usageMax="36503552" usageUsed="795720"/>
        <memorypool name="PS Old Gen" type="Heap memory" usageInit="40108032" usageCommitted="40108032" usageMax="89522176" usageUsed="7624024"/>
        <memorypool name="PS Survivor Space" type="Heap memory" usageInit="2490368" usageCommitted="2490368" usageMax="2490368" usageUsed="2469832"/>
        <memorypool name="Code Cache" type="Non-heap memory" usageInit="2555904" usageCommitted="2555904" usageMax="50331648" usageUsed="1095104"/>
        <memorypool name="PS Perm Gen" type="Non-heap memory" usageInit="21757952" usageCommitted="21757952" usageMax="174063616" usageUsed="16175656"/>
    </jvm>
    <connector name="&quot;http-bio-7380&quot;">
        <threadInfo maxThreads="200" currentThreadCount="10" currentThreadsBusy="1"/>
        <requestInfo maxTime="53" processingTime="146" requestCount="7" errorCount="0" bytesReceived="0" bytesSent="121567"/>
        <workers>
            <worker stage="R" requestProcessingTime="0" requestBytesSent="0" requestBytesReceived="0" remoteAddr="?" virtualHost="?" method="?" currentUri="?" currentQueryString="?" protocol="?"/>
            <worker stage="R" requestProcessingTime="0" requestBytesSent="0" requestBytesReceived="0" remoteAddr="?" virtualHost="?" method="?" currentUri="?" currentQueryString="?" protocol="?"/>
            <worker stage="S" requestProcessingTime="4" requestBytesSent="0" requestBytesReceived="0" remoteAddr="0:0:0:0:0:0:0:1" virtualHost="localhost" method="GET" currentUri="/manager/status/all" currentQueryString="XML=true" protocol="HTTP/1.1"/>
        </workers>
    </connector>
    <connector name="&quot;ajp-bio-7309&quot;">
        <threadInfo maxThreads="200" currentThreadCount="0" currentThreadsBusy="0"/>
        <requestInfo maxTime="0" processingTime="0" requestCount="0" errorCount="0" bytesReceived="0" bytesSent="0"/>
        <workers/>
    </connector>
</status>

* Tomcat CSRF Filter * Cross-Site-Request-Forgery * XML Pretty Printer

Monitoring mit der Jconsole

Remote Monitoring mit dem Befehl jconsole

bin/startup.sh

export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=7304 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=$(hostname) \
-Djava.rmi.server.useLocalHostname=true"

Wenn eine Autorisierung nötig ist geht das mit:

	
    -Dcom.sun.management.jmxremote.authenticate=true \
    -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password \
    -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access \

conf/jmxremote.access

	
monitorRole readonly
controlRole readwrite

conf/jmxremote.password

			
monitorRole tomcat
controlRole tomcat

Tipp: Der Password-file muss read-only und nur von UNIX Prozess Nutzers des Tomcats lesbar sein!!

Konfiguration im Tomcat für Server und Registry port!

download jmx remote download http://tomcat.apache.org/download-70.cgi

cp catalina-jmx-remote.jar node73/lib

<Server ...>
   <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
             rmiRegistryPortPlatform="${port.prefix}03"
             rmiServerPortPlatform="${port.prefix}04" />
          
</Server>

Freischaltung der Firewall

  sudo iptables -A INPUT -p tcp --dport 7303 -j ACCEPT
  sudo iptables -A INPUT -p tcp --dport 7304 -j ACCEPT

Access URL

    service:jmx:rmi://192.168.1.218:7304/jndi/rmi://192.168.1.218:7303/jmxrmi  

conf/tomcat-users.xml

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
  <role rolename="manager-jmx"/>
  <role rolename="manager-gui"/>
  <user username="jmx" password="tomcat" roles="manager-jmx"/>
  <user username="manager" password="tomcat" roles="manager-gui,manager-jmx"/>
</tomcat-users>

Access MBean Attribute WebModule stateName

http://notebook31:7380/manager/jmxproxy/?get=Catalina:j2eeType=WebModule,name=//localhost/hello,J2EEApplication=none,J2EEServer=none&att=stateName

Access with curl

$curl --user "jmx:tomcat" "http://notebook31:7380/manager/jmxproxy/?get=Catalina:j2eeType=WebModule,name=//localhost/hello,J2EEApplication=none,J2EEServer=none&att=stateName"
OK - Attribute get 'Catalina:j2eeType=WebModule,name=//localhost/hello,J2EEApplication=none,J2EEServer=none' - stateName = STARTED
$ curl --user "jmx:tomcat" "http://notebook31:7380/manager/jmxproxy/?get=Catalina:j2eeType=WebModule,name=//localhost/hello,J2EEApplication=none,J2EEServer=none&att=stateName" --silent | awk '{print $1 " " $(NF)}'
OK STARTED

http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html

Logging

Logging: Minimale Konfiguration

conf/logging.properties :

handlers = 1catalina.org.apache.juli.FileHandler

.handlers = 1catalina.org.apache.juli.FileHandler

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.

#java.util.logging.ConsoleHandler.level = FINE
#java.util.logging.ConsoleHandler.formatter = 

Anwendung mit eigener Log- Konfiguration

bin/setenv.sh :

#!/bin/bash
JAVA_OPTS="$JAVA_OPTS -Dlogdir=${CATALINA_BASE}/logs"
cd bin
chmod +x setenv.sh
cd ..
mkdir -p webapps/ROOT/WEB-INF/classes
vi webapps/ROOT/WEB-INF/classes/logging.properties

webapps/ROOT/WEB-INF/classes/logging.properties :

handlers=1root.org.apache.juli.FileHandler
.handlers=1root.org.apache.juli.FileHandler
.level=FINE
1root.org.apache.juli.FileHandler.level=FINE
1root.org.apache.juli.FileHandler.directory=${logdir}
1root.org.apache.juli.FileHandler.prefix=root-

Level :

  • OFF
  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST
  • ALL

Unterdrücken der WebSocket Meldung bei Verwendung von Java 6 conf/logging.properties

org.apache.tomcat.websocket.server.WsSci.level = OFF

Autoreloading Anwendung nachdem die logging.properties geändert wurde

webapps/ROOT/META-INF/context.xml :

<Context>
   <WatchedResource>WEB-INF/classes/logging.properties</WatchedResource>
</Context>

webapps/ROOT/log.jsp :

<%@ page import="java.util.logging.*" %>
<%

Logger logger = Logger.getLogger("");
logger.info("Info");
logger.fine("Fine");

application.log("context log");
System.out.println("system.out");
System.err.println("system.err");
%>
see logfiles
curl http://localhost:7380/log.jsp

Ausgabe

/var/log/tomcat/node74/root-<Date>.log
13.07.2010 15:25:32 org.apache.jsp.log_jsp _jspService
INFO: Info
13.07.2010 15:25:32 org.apache.jsp.log_jsp _jspService
FEIN: Fine
13.07.2010 15:25:32 org.apache.catalina.core.ApplicationContext log
INFO: context log

Unterdrücken der Tomcat Meldungen:

webapps/ROOT/WEB-INF/classes/logging.properties

handlers=1root.org.apache.juli.FileHandler
.handlers=1root.org.apache.juli.FileHandler
.level=FINE
1root.org.apache.juli.FileHandler.level=FINE
1root.org.apache.juli.FileHandler.directory=${logdir}
1root.org.apache.juli.FileHandler.prefix=root-
org.apache.catalina.level=INFO
org.apache.tomcat.level=INFO
org.apache.jasper.level=INFO

Ausgabe des Tomcat8

05-May-2015 10:03:24.863 INFO [http-nio-7380-exec-7] org.apache.jsp.log_jsp._jspService Info
05-May-2015 10:03:24.864 FINE [http-nio-7380-exec-7] org.apache.jsp.log_jsp._jspService Fine
05-May-2015 10:03:24.864 INFO [http-nio-7380-exec-7] org.apache.catalina.core.ApplicationContext.log context log

Änderung der Sprache für die LogAusgabe

check :

echo $LANG
de_DE.UTF-8

bin/startup.sh und bin/shutdown.sh oder in der setenv.sh

export LANG="en_US.UTF-8"
export JAVA_OPTS="$JAVA_OPTS -Duser.language=en -Duser.country=US"

Ausgabe

/var/log/tomcat/node74/root-<Date>.log
Sep 3, 2010 10:09:11 AM org.apache.jsp.log_jsp _jspService
INFO: Info
Sep 3, 2010 10:09:11 AM org.apache.jsp.log_jsp _jspService
FINE: Fine
Sep 3, 2010 10:09:11 AM org.apache.catalina.core.ApplicationContext log
INFO: context log
/var/log/tomcat/node74/catalina.out
system.out
system.err

Umlenkung der Ausgabe von System.out und System.err in das Appliction.log

webapps/ROOT/META-INF/context.xml :

  <Context swallowOutput="true" />

logrotate

/etc/logrotate.d/tomcat :

/home/nutzer01/workshop/node73/logs/catalina.out {
    size=+10
    compress
    create 640 nutzer01 nutzer01
    copytruncate
    # Achtung: hierbei können einzelne Logmeldungen während des Kopier/Compress Vorgangs verloren gehen
}

testen

logrotate /etc/logrotate.conf

oder etwas ernsthafter

/etc/logrotate.d/tomcat :

/home/nutzer01/workshop/node73/logs/catalina.out {
    rotate 8
    daily
    compress
    create 640 nutzer01 nutzer01
    copytruncate
    # Achtung: hierbei können einzelne Logmeldungen während des Kopier/Compress Vorgangs verloren gehen
}

Ausschalten der Rotierung eines FileHandlers

webapps/ROOT/WEB-INF/classes/logging.properties

..
1root.org.apache.juli.FileHandler.rotatable=false

http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/juli/FileHandler.html

/var fuer log-files nutzen

sudo mkdir /var/log/tomcat/node73
sudo mkdir /var/tmp/tomcat/node73/temp
sudo mkdir /var/tmp/tomcat/node73/work
sudo chown nutzer01:nutzer01 /var/log/tomcat/node73
sudo chown -R nutzer01:nutzer01 /var/tmp/tomcat/node73

home/nutzer01/workshop/node73/bin/startup.sh :

...
export CATALINA_OUT=/var/log/tomcat/node73/catalina.out
export CATALINA_TMPDIR=/var/tmp/tomcat/node73/temp
export JAVA_OPTS=-Dport.prefix=73 -Dcatalina.workdir=/var/tmp/tomcat/node73/work
...

home/nutzer01/workshop/node73/bin/shutdown.sh :

...
export CATALINA_OUT=/var/log/tomcat/node73/catalina.out
export CATALINA_TMPDIR=/var/tmp/tomcat/node73/temp
export JAVA_OPTS=-Dport.prefix=73 -Dcatalina.workdir=/var/tmp/tomcat/node73/work
...

home/nutzer01/workshop/node73/conf/server.xml :

<Engine ...> 
   <Host name="localhost" appBase="webapps" workDir="${catalina.workdir}" >
   </Host>
</Engine>

Anpassung der /etc/logrotate.d auf /var/log/tomcat/catalina.out nicht vergessen!

Nutzen von Logback für Tomcat

mkdir -p ~/workshop/logback
cd ~/workshop/logback
mkdir -p ../node73/lib
wget https://github.com/grgrzybek/tomcat-slf4j-logback/releases/download/tomcat-8.0.32.SP1/tomcat-juli-8.0.32-slf4j-1.7.16-logback-1.1.5.zip
unzip tomcat-juli-8.0.32-slf4j-1.7.16-logback-1.1.5.zip
cp lib/logback-core-1.1.5.jar ../node73/lib
cp lib tomcat-juli ../node73/bin
cd ../node73
vi setenv.sh
vi ../conf/logback.xml

bin/setenv.sh

CLASSPATH=${CATALINA_BASE}/bin
JAVA_OPTS="$JAVA_OPTS -Djuli-logback.configurationFile=file:$CATALINA_BASE/conf/logback.xml"

conf/logback.xml

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <appender name="STDOUT" class="org.apache.juli.logging.ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %-5level {%thread} [%logger{20}] : %msg%n</pattern>
        </encoder>
  </appender>

  <root level="INFO">
      <appender-ref ref="STDOUT" />
  </root>

</configuration>

Java 7 und Tomcat >7.0.42 formatting

conf/logging.properties

.handlers=java.util.logging.ConsoleHandler

handlers=java.util.logging.ConsoleHandler

java.util.logging.ConsoleHandler.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s %4$s: %5$s%n
org.apache.tomcat.util.digester.Digester.level=OFF

Ausgabe

Sep 02, 2014 12:02:23 PM org.apache.catalina.startup.Catalina load WARNING: Catalina.start using conf/server.xml: Attribute name "port" associated with an element type "Server" must be followed by the ' = ' character.
Sep 02, 2014 12:02:23 PM org.apache.catalina.startup.Catalina load WARNING: Catalina.start using conf/server.xml: Attribute name "port" associated with an element type "Server" must be followed by the ' = ' character.
Sep 02, 2014 12:02:23 PM org.apache.catalina.startup.Catalina start SEVERE: Cannot start server. Server instance is not configured.
.handlers=java.util.logging.ConsoleHandler

handlers=java.util.logging.ConsoleHandler

java.util.logging.ConsoleHandler.level=FINE

java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS.%1$tL%1$tz %2$s %4$s: %5$s%n

org.apache.tomcat.util.digester.Digester.level=OFF

Ausgabe

2014-09-02T12:15:09.333+0200 org.apache.catalina.startup.Catalina load WARNING: Catalina.start using conf/server.xml: Attribute name "port" associated with an element type "Server" must be followed by the ' = ' character.
2014-09-02T12:15:09.338+0200 org.apache.catalina.startup.Catalina load WARNING: Catalina.start using conf/server.xml: Attribute name "port" associated with an element type "Server" must be followed by the ' = ' character.
2014-09-02T12:15:09.338+0200 org.apache.catalina.startup.Catalina start SEVERE: Cannot start server. Server instance is not configured.

Es fehlt die Angabe über den Threadname oder die ID dieses gibt es nur mit dem OneLineFormatter bisher!

Einsatz OneLineformatter des Tomcat 7 - JULI

Als erster müssen wir die Source aus dem Trunk des Apache Tomcat 7 holen.

mkdir -p workshop/formatter/src/org/apache/juli
cd workshop/formatter/src/org/apache/juli
wget http://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/juli/OneLineFormatter.java
wget http://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/juli/DateFormatCache.java
javac -cp ../../../../../apache-tomcat.6.0.32/bin/tomcat-juli.jar *.java
cd ../../..
jar -cf ../formatter.jar org/apache/juli/*.class
cp ../formatter.jar ../../node73/bin
cd ../../node73

bin/setenv.sh

#!/bin/bash
export CLASSPATH=$CLASSPATH:$CATALINA_BASE/bin/formatter.jar

conf/logging.properties

handlers = 1catalina.org.apache.juli.FileHandler
.handlers = 1catalina.org.apache.juli.FileHandler
.level=INFO
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
1catalina.org.apache.juli.FileHandler.formatter = org.apache.juli.OneLineFormatter

restart des Servers und Kontrolle des Log Files

logs/catalina.YYYY-MM_DD.log

12-Jul-2011 12:38:09.835 INFO org.apache.coyote.http11.Http11Protocol.start Starting Coyote HTTP/1.1 on http-7380
12-Jul-2011 12:38:10.046 INFO org.apache.jk.common.ChannelSocket.init JK: ajp13 listening on /0.0.0.0:7309
12-Jul-2011 12:38:10.060 INFO org.apache.jk.server.JkMain.start Jk running ID=0 time=0/44  config=null
12-Jul-2011 12:38:10.086 INFO org.apache.catalina.startup.Catalina.start Server startup in 5390 ms

Im Tomcat 7 existiert noch ein AsyncFileHandler der sich für High Traffic Sites eignet.

conf/logging.properties

handlers = 1catalina.org.apache.juli.AsyncFileHandler

.handlers = 1catalina.org.apache.juli.AsyncFileHandler

1catalina.org.apache.juli.AsyncFileHandler.level = FINE
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina
1catalina.org.apache.juli.AsyncFileHandler.rotatable= false
1catalina.org.apache.juli.AsyncFileHandler.formatter = java.util.logging.SimpleFormatter

java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS.%1$tL%1$tz %2$s %4$s: %5$s%n

org.apache.tomcat.util.digester.Digester.level=OFF
System properties Default
org.apache.juli.AsyncOverflowDropType 1
org.apache.juli.AsyncMaxRecordCount 10000
org.apache.juli.AsyncLoggerPollInterval 1000
AsyncOverflowDropType Wert
OVERFLOW_DROP_LAST 1
OVERFLOW_DROP_FIRST 2
OVERFLOW_DROP_FLUSH 3
OVERFLOW_DROP_CURRENT 4

Referenz der Properties: http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/juli/FileHandler.html

Access Log

./conf/server.xml unterhalb des Tags Engine oder Host oder innerhalb der Context Definition für eine Anwendung ./conf/Catalina/localhost/<app>.xml :

      <Valve className="org.apache.catalina.valves.AccessLogValve" 
             directory="logs"  
             prefix="access" 
             suffix=".log" 
             pattern="%h %l &quot;%u&quot; %t &quot;%r&quot; %s %b %D %S" 
             resolveHosts="false"
      />

Im Apache Tomcat 7 lässt sich der Zeitstempel auf die Millisekunde genau erzeugen und man kann festlegen, ob der Zeitstempel vom Beginn oder Ende des Requests ausgeben wird. ./conf/Catalina/localhost/<app>.xml :

        <Valve className="org.apache.catalina.valves.AccessLogValve"
           directory="logs"  
           prefix="access"
           suffix=".log"
           rotatable="true"
           pattern="%h &quot;%{begin:yyyy-MM-dd'T'HH:mm:ss:SSSZ}t&quot; %{begin:msec}t &quot;%r&quot; &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; %s %b &quot;%I&quot; %D %S"
           resolveHosts="false"/>

testen

100 Anfragen schicken:

ab -c 5 -n 100 -k http://localhost:7380/hello/index.jsp

Anfragen größer 70 Millisekunden filter:

awk '$(NF-1)/10 >= 7' logs/access-2010-06-25.log
perl -a -n -e 'print $F[-2],$/ if $F[-2] > 70' logs/access-2010-06-25.log

Dokumentation

Dynamische Konfiguration des AccessLogValve

Einfügen des ServerLifeCycleListener bewirkt, das das JMX Mbean MBeanFactory hinzugefügt wird. Mit Hilfe des Mbean kann man zur Laufzeit Tomcat Komponenten wie eine AccessLogValve hinzufügen und ein Ausgabe setzen.

Im Apache Tomcat 7 gibt es diese Klasse nicht mehr und die MbeanFactory ist immer aktiv!

conf/server.xml

<Server ..>
   <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
   ..
  
   <Service ..>
   ..
   </Service>
</Server>

Attribute Pattern für das AccesLogValve mit einer erweiterten Ausgabe

%h %l "%u" %t "%r" %s %b %D %S "%{User-Agent}i" "%{Referer}i"

Vorsicht: In der server.xml die Doppelten Anführungsstriche bitte durch &quot; ersetzen.

Mit dem Attribute

enabled=false

des AccessLogValve kann ein Ausgabe unterbunden werden. Dafür kann der JMX Zugang via jconsole genutzt werden.

Dynamisch kann man diese Umschaltung auf via Manager App folgendermassen bewirken.

http://notebook20:7380/manager/jmxproxy?set=Catalina:type=Valve,name=AccessLogValve,seq=1&att=enabled&val=false

ELK-Stack for tomcat accesslog

Logstash

http://logstash.net/docs/1.4.2/tutorials/getting-started-with-logstash

curl -O https://download.elasticsearch.org/logstash/logstash/logstash-1.4.2.tar.gz
tar zxvf logstash-1.4.2.tar.gz
cd logstash-1.4.2
bin/logstash -e 'input { stdin { } } output { stdout {} }'
bin/logstash -e 'input { stdin { } } output { stdout { codec => rubydebug } }'

Bald 1.5.x

Auf jeder Maschine sollten die Logs mit dem logstashforwarder abgeholt werden.

https://github.com/elastic/logstash-forwarder

Aufgaben

* Multiline Logs * Exceptions * Direkt Log mit GELF * Informationen in Log Meldungen maschinenlesbar formulieren * Begrenzung der Logs auf Verwertbares * Ausfall und wiederaufsetzen der LogInfrastruktur

  • Redis Cache
  • Skallierung

Elasticsearch

https://github.com/elastic/elasticsearch

curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.5.2.tar.gz
tar zxvf elasticsearch-1.5.2.tar.gz
cd elasticsearch-1.5.2/
cd config
vi elasticsearch.conf
# disable autorecovery cluster
discovery.zen.ping.multicast.enabled: false
./bin/elasticsearch
bin/logstash -e 'input { stdin { } } output { elasticsearch { host => localhost } }'
curl 'http://localhost:9200/_search?pretty'

tomcat.conf

input { stdin { } }

filter {
  grok {
      match => { "message" => "%{IPORHOST:clientip} \"%{TIMESTAMP_ISO8601:timestamp}\" %{NUMBER:unixtime:int} \"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\" \"(?:%{URI:referrer}|-)\" \"%{GREEDYDATA:agent}\" %{NUMBER:response:int} (?:%{NUMBER:bytes:int}|-) \"%{GREEDYDATA:thread}\" %{NUMBER:duration:int} (?:%{WORD:session_id}.%{WORD:node}|-)"}
  }

}

output {
  elasticsearch { host => localhost }
  stdout { codec => rubydebug }
}

Parse all access logs

input {
  file {
    path => "/home/nutzer17/workshop/*/logs/access-*.log"
    start_position => beginning
  }
}


filter {
  grok {
      match => { "message" => "%{IPORHOST:clientip} \"%{TIMESTAMP_ISO8601:timestamp}\" %{NUMBER:unixtime:int} \"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\" \"(?:%{URI:referrer}|-)\" \"%{GREEDYDATA:agent}\" %{NUMBER:response:int} (?:%{NUMBER:bytes:int}|-) \"%{GREEDYDATA:thread}\" %{NUMBER:duration:int} (?:%{WORD:session_id}.%{WORD:node}|-)"}
  }
}

output {
  elasticsearch { host => localhost }
  stdout { codec => rubydebug }
}

Install HQ Plugin

http://www.elastichq.org/support_plugin.html

open http://localhost:9200/_plugin/HQ/

Aufgaben

* Erlernen der Query Sprache ist komplex und aufwendig * Cluster * Backup und Restore von Indexen

Kibana

https://github.com/elastic/kibana

curl -O https://download.elastic.co/kibana/kibana/kibana-4.0.2-linux-x64.tar.gz
tar zxvf kibana-4.0.2-linux-x64.tar.gz
cd kibana-4.0.2/bin
./kibana
open http://localhost:5601

Änderungen in config/kibana.yml

Aufgaben

* Erstellen eines Dashboards * Sollen Metriken auch in Elasticsearch gespeichert werden? (Volumen)

Speicher einstellen

bin/startup.sh :

export CATALINA_OPTS="-Dport.prefix=73 -Xms64m -Xmx128m"

Perm Heap vergössern

-XX:MaxPermSize=256m

GC Logging

DATE=`date +'%y-%m-%d-%H-%M-%S'`
export CATALINA_OPTS="$CATALINA_OPTS -verbosegc -Xloggc:$CATALINA_BASE/logs/gc-$DATE.log"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintTenuringDistribution"

Jstat Memory Trace

jstat -gc `cat logs/tomcat.pid` 5000

GCViewer

VmParameter

Sessions

http://localhost:7380/manager/html/sessions?path=/hello

Eine alternativer Tomcat Manager ist psi-probe.

Schicker: http://code.google.com/p/psi-probe runterladen und

unzip probe-2.3.3.zip
cp probe.war webapps

Weitere Tomcat Instanz

cd
cp -a node73/ node74
cd node74/

bin/startup.sh :

#!/bin/bash
export CATALINA_HOME=~/apache-tomcat/
export CATALINA_BASE=~/node74/
export JAVA_OPTS="-Dport.prefix=74"
export CATALINA_OPTS="-Xmx128m"
export CATALINA_PID="${CATALINA_BASE}/logs/tomcat.pid"
${CATALINA_HOME}/bin/catalina.sh start $@

bin/shutdown.sh :

#!/bin/bash
export CATALINA_HOME=~/apache-tomcat/
export CATALINA_BASE=~/node74/
export JAVA_OPTS="-Dport.prefix=74"
export CATALINA_PID="${CATALINA_BASE}/logs/tomcat.pid"
${CATALINA_HOME}/bin/catalina.sh stop $@
./bin/startup.sh

oder::

vi start
ln -s start stop
vi setenv.sh
vi restart
chmod 700 start stop restart

start

#!/bin/bash
export CATALINA_HOME=~/workshop/apache-tomcat
export CATALINA_BASE=~/workshop/node74
${CATALINA_HOME}/bin/catalina.sh `basename $0` $@

setenv.sh

export JAVA_OPTS="-Dport.prefix=74"
export CATALINA_PID="${CATALINA_BASE}/logs/tomcat.pid"
export CATALINA_OPTS="-Xmx128m"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access \
-Djava.rmi.server.hostname=$(hostname) \
-Djava.rmi.server.useLocalHostname=true"
export CATALINA_OPTS="$CATALINA_OPTS -Djava.awt.headless=true" 

restart

#!/bin/bash
~/workshop/node74/bin/stop -force
sleep 2
~/workshop/node74/bin/start

Praktischere Minimale Konfiguration

cp -a ../apache-tomcat-6.0.35/conf/* conf/

Änderungen ( nicht vollständig ):

conf/server.xml :

<Server port="${port.prefix}05" shutdown="SHUTDOWN" >
<Connector port="${port.prefix}80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<Connector port="${port.prefix}09" protocol="AJP/1.3" redirectPort="8443" />

Universelles Start Skript

ermittelt seinen Namen aus dem Verzeichnis node<prefix> und setzt die jvmRoute und den port.prefix für die server.xml.

bin/startup.sh :

#!/bin/bash
# Get the fully qualified path to the script
case $0 in
    /*)
        SCRIPT="$0"
        ;;
    *)
        PWD=`pwd`
        SCRIPT="$PWD/$0"
        ;;
esac
 
# Change spaces to ":" so the tokens can be parsed.
SCRIPT=`echo $SCRIPT | sed -e 's; ;:;g'`
# Get the real path to this script, resolving any symbolic links
TOKENS=`echo $SCRIPT | sed -e 's;/; ;g'`
REALPATH=
for C in $TOKENS; do
    REALPATH="$REALPATH/$C"
    while [ -h "$REALPATH" ] ; do
        LS="`ls -ld "$REALPATH"`"
        LINK="`expr "$LS" : '.*-> \(.*\)$'`"
        if expr "$LINK" : '/.*' > /dev/null; then
            REALPATH="$LINK"
        else
            REALPATH="`dirname "$REALPATH"`""/$LINK"
        fi
    done
done
# Change ":" chars back to spaces.
REALPATH=`echo $REALPATH | sed -e 's;:; ;g'`
 
# Change the current directory to the location of the script
cd "`dirname "$REALPATH"`"
cd "`dirname "$SCRIPT"`"
REALDIR=`pwd`
parentdir=`dirname $REALDIR`
export CATALINA_BASE=$parentdir
 
INSTANCE_NAME=`basename $parentdir`
PORT_PREFIX=`echo $INSTANCE_NAME | awk '{ printf substr($1,5,2)}'`
 
export CATALINA_HOME=/home/nutzer01/workshop/apache-tomcat-6.0.35
export CATALINA_OUT=/var/log/tomcat/$INSTANCE_NAME/catalina.out
mkdir -p /var/log/tomcat/$INSTANCE_NAME
export CATALINA_TMPDIR=/var/tmp/tomcat/$INSTANCE_NAME/temp
mkdir -p /var/tmp/tomcat/$INSTANCE_NAME
export JAVA_OPTS="-DjvmRoute=$INSTANCE_NAME -Dport.prefix=$PORT_PREFIX"
export CATALINA_OPTS="-server -Xmx128m -Dcatalina.workdir=/var/tmp/tomcat/$INSTANCE_NAME/work"
export CATALINA_PID=/var/log/tomcat/$INSTANCE_NAME/tomcat.pid
$CATALINA_HOME/bin/catalina.sh start $@

Dokumentation

Java Tools

Liste aller Java Prozesse eines Nutzers

jps
2390 Bootstrap
8259 Jps
8244 Bootstrap

Ausgabe der Parameter der Java Prozesse

jps -vml
2390 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/home/nutzer06/workshop/apache-tomcat-6.0.28/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/nutzer06/workshop/apache-tomcat-6.0.28/endorsed -Dcatalina.base=/home/nutzer06/workshop/apache-tomcat-6.0.28 -Dcatalina.home=/home/nutzer06/workshop/apache-tomcat-6.0.28 -Djava.io.tmpdir=/home/nutzer06/workshop/apache-tomcat-6.0.28/temp
8295 sun.tools.jps.Jps -vml -Dapplication.home=/usr/lib/jvm/java-6-openjdk -Xms8m
8244 org.apache.catalina.startup.Bootstrap start -Dnop -DjvmRoute=node74 -Dport.prefix=74 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dcatalina.workdir=/var/tmp/tomcat/node74/work -Djava.endorsed.dirs=/home/nutzer06/workshop/apache-tomcat-6.0.28/endorsed -Dcatalina.base=/home/nutzer06/workshop/node74 -Dcatalina.home=/home/nutzer06/workshop/apache-tomcat-6.0.28 -Djava.io.tmpdir=/var/tmp/tomcat/node74/temp

Protokollierung des Speicherverbrauchs eines Java Prozesses

jstat -gc <jpid> <time msec>

Ausgabe

S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC   PU    YGC     YGCT    FGC    FGCT     GCT   
 64,0   64,0   0,0    32,0   4288,0   342,9    35776,0     3195,2   16384,0 10085,0    125    0,142  28      1,567    1,709
 64,0   64,0   0,0    32,0   4288,0   342,9    35776,0     3195,2   16384,0 10085,0    125    0,142  28      1,567    1,709
 64,0   64,0   0,0    32,0   4288,0   428,7    35776,0     3195,2   16384,0 10085,0    125    0,142  28      1,567    1,709

Connector in der server.xml

Im Tomcat 6 ist es möglich einen Threadpool auf der Basis des Standard Java Executor API zu nutzen. Damit können endlich auch verschiedenen Connectoren einen gemeinsamen Threadpool nutzen.

<Executor name="Catalina-Threads" namePrefix="Catalina-exec" maxThreads="200" minSpareThreads="50" />
<Connector port="${port.prefix}80" executor="Catalina-Threads" protocol="HTTP/1.1" />
<Connector port="${port.prefix}90" executor="Catalina-Threads" protocol="org.apache.coyote.http11.Http11NioProtocol" />

<Connector port="${port.prefix}09" executor="Catalina-Threads" protocol="org.apache.coyote.ajp.AjpProtocol" />

server.xml

<?xml version='1.0' encoding='utf-8'?>
<Server port="${port.prefix}05" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

 <GlobalNamingResources>
    <Resource name="UserDatabase" 
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources> 
  <Service name="Catalina">
    <Executor  name="TomcatThreads" 
               namePrefix="Catalina-exec"
               maxThreads="200" 
               minSpareThreads="50" />
    <Connector port="${port.prefix}80" 
               protocol="org.apache.coyote.http11.Http11NioProtocol"
               executor="TomcatThreads"    />
    <Connector port="${port.prefix}81" 
               protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               executor="TomcatThreads"    />
    <Connector port="${port.prefix}90"
               protocol="org.apache.coyote.http11.Http11Protocol"
               executor="TomcatThreads"/>

    <Engine name="Catalina"      defaultHost="localhost" jvmRoute="node${port.prefix}">
      <Valve className="org.apache.catalina.valves.AccessLogValve"
           directory="logs"  
           prefix="access-"
           suffix=".log"
           rotatable="true"
           pattern="%h &quot;%{begin:yyyy-MM-dd'T'HH:mm:ss:SSSZ}t&quot; %{begin:msec}t &quot;%r&quot; &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; %s %b &quot;%I&quot; %D %S"
           resolveHosts="false"/> 
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/> 
      <Host name="localhost" appBase="webapps">
      </Host>
    </Engine>
  </Service>
</Server>

Lasttest

sudo apt-get install apache2-utils

Erzeugung von statischen Dateien

cd webapps
mkdir last
cd last
dd if=/dev/urandom of=8k.bin bs=1024 count=8
dd if=/dev/urandom of=25k.bin bs=1024 count=25
dd if=/dev/urandom of=64k.bin bs=1024 count=64
dd if=/dev/urandom of=100k.bin bs=1024 count=100
dd if=/dev/urandom of=250k.bin bs=1024 count=250

Ausführen der Test mit ab einer Testserie mit 5,10,25,100,200,300 paralleln Anfragen mit jeweils 50000 Anfragen.

ab -c 5 -n 50000 -k http://127.0.0.1:7380/last/8k.bin
ab -c 10 -n 50000 -k http://127.0.0.1:7380/last/8k.bin
...

Ausführung eines Tests

cd workshop/node74
mkdir stat
vi last.sh
chmod 750 last.sh

last.sh

#!/bin/sh

req=50000
for port in 7480 ; do \
    for con in 10 50 100 250 400 800; do \
        for datei in 8 25 64 100 250 ; do \
          for iter in 1 2 3 ; do \
          sleep 1
          ab -c ${con} -n ${req} -k \
             http://localhost:${port}/last/${datei}k.bin > stat/${port}-${datei}k-${con}-${req}-${iter}.txt ;
          done ;
        done ;
    done ;
done

Auswertung der Dateien

cd stat
find . -exec grep -H "Requests per" {} \;

Start visualVM remote

ssh -X nutzer18@192.168.1.218
jvisualvm --jdkhome /usr/lib/jvm/java-6-sun-1.6.0.26

gnuplot

http://forums.cpanel.net/f402/using-apache-ab-benchmarking-gnuplot-graphing-275542.html
sudo -i
vi /etc/apt/sources-list
sudo apt-get update
sudo apt-get install gnuplot
vi plot.p
ab -c 5 -n 50000 -g data.dat http://localhost:7380/last/8k.bin

/etc/apt/sources-list

deb [arch=amd64] http://ubuntu/ubuntu          trusty          main restricted universe multiverse
deb [arch=amd64] http://ubuntu/ubuntu          trusty-security main restricted universe multiverse
deb [arch=amd64] http://ubuntu/ubuntu          trusty-updates  main restricted universe multiverse

plot.p

#output as png image
set terminal png

#save file to "data.png"
set output "data.png"

#graph title
set title "ab -n 50000 -c 5"

#nicer aspect ratio for image size
set size 1,0.7

# y-axis grid
set grid y

#x-axis label
set xlabel "request"

#y-axis label
set ylabel "response time (ms)"

#plot data from "domain.dat" using column 9 with smooth sbezier lines
#and title of "something" for the given data
plot "data.dat" using 9 smooth sbezier with lines title "something"
gnuplot <plot.p
ls -l data.*
-rw-rw-r-- 1 nutzer31 nutzer31 2200170 Sep  3 17:47 data.dat
-rw-rw-r-- 1 nutzer31 nutzer31    3993 Sep  3 17:54 data.png

APR Connector bereitstellen

sudo aptitude install libapr1-dev
sudo aptitude install libssl-dev
cd apache-tomcat-6.0.33/bin
cp tomcat-native.tar.gz ../..
cd ../..
tar xzf tomcat-native.tar.gz
cd tomcat-native-1.1.20-src/jni/native
./configure --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-6-sun --with-ssl=yes --prefix=/home/nutzer01/workshop/apache-tomcat-6.0.33
make
make install
cd ../../../node74

Ubuntu 14.04

sudo apt-get install libapr1-dev
sudo apt-get install libssl-dev
cd ~/workshop/apache-tomcat/bin
tar xzf tomcat-native.tar.gz
cd tomcat-native-1.1.31-src/jni/native
./configure --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-1.7.0-openjdk-amd64 --with-ssl=yes --prefix=/home/nutzer31/workshop/apache-tomcat
make
make install
cd ../../../node73

Ubuntu 14.04 (java 8 und tomcat 8)

sudo apt-get install libapr1-dev
sudo apt-get install libssl-dev
cd ~/workshop/apache-tomcat/bin
tar xzf tomcat-native.tar.gz
cd tomcat-native-1.1.33-src/jni/native
./configure --with-apr=/usr/bin/apr-1-config --with-java-home=/usr/lib/jvm/java-8-oracle/ --with-ssl=yes --prefix=/home/nutzer07/workshop/apache-tomcat
make
make install
cd ../../../node73

conf/server.xml

  <Server ...
     <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <Service ...

    <Connector port="${port.prefix}80" executor="Catalina-Threads"
               protocol="org.apache.coyote.http11.Http11Protocol" />
 
    <Connector port="${port.prefix}82" executor="Catalina-Threads" 
               protocol="org.apache.coyote.http11.Http11AprProtocol" />

    <Connector port="${port.prefix}84" executor="Catalina-Threads" 
               protocol="org.apache.coyote.http11.Http11NioProtocol" />

  <Engine ...

bin/startup.sh

  export CATALINA_HOME=/home/nutzer01/workshop/apache-tomcat-6.0.33
  export LD_LIBRARY_PATH=${CATALINA_HOME}/lib

Bereitstellung vieler File Pointer

/etc/security/limits.conf anhängen!

...
  * soft nofile 1024
  * hard nofile 20000
...

In der shell nachfolgende Befehle absetzen

ulimit -n 20000
echo 20000 > /proc/sys/fs/file-max

/etc/sysctl.conf anhängen!

fs.file-max = 20000

Es sollte in /etc/profiles.sh/ulimit.sh mit folgendem Inhalt erstellt werden:

ulimit - n 20000

Erzeugen eines HTTPS Connetors mit APR/OpenSSL

cd node73/conf
openssl genrsa -des3 -out tomcatkey.pem 2048

Eingabe des Password „tomcat“ (s.u.)

openssl req -new -x509 -key tomcatkey.pem -out tomcatcert.pem -days 1095

Anlage der Zertifikatsinformationen (Common Name sollte der Name des Rechners sein!)

#Eingabe
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:NRW
Locality Name (eg, city) []:Bochum
Organization Name (eg, company) [Internet Widgits Pty Ltd]:LinuxHotel
Organizational Unit Name (eg, section) []:noteboo16
Common Name (eg, YOUR name) []:notebook16
Email Address []:pr@objektpark.de

conf/server.xml

<Server ...
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

<Service ...
<!-- Define a SSL HTTP/1.1 Connector on port xx43 -->

<Connector port="${port.prefix}43" 
    executor="Catalina-Threads" 
    protocol="org.apache.coyote.http11.Http11AprProtocol"
    scheme="https"
    secure="true"
    sslProtocol="TLS"
	SSLEnabled="true"
	SSLCertificateFile="${catalina.base}/conf/tomcatcert.pem"
	SSLCertificateKeyFile="${catalina.base}/conf/tomcatkey.pem"
	SSLPassword="tomcat"
     />

Zugang via SSL zum Tomcat mit openssl

 openssl s_client -connect notebook16:7343

* http://www.madboa.com/geek/openssl/

GET /hello/index.jsp HTTP/1.0

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=3035FA551AD683F6939EDFA7A2CCE3D5.node73; Path=/hello/; Secure; HttpOnly
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 18
Date: Thu, 13 Sep 2012 10:50:02 GMT
Connection: close

Hello LinuxHotel!

Access https via url

curl --insecure https://192.168.1.218:7343/hello/index.jsp

last.sh

#!/bin/bash
K=10;    
HTTPSA='https://192.168.1.218:7343/last/8k.bin'    
date +%M-%S-%N>curlres.txt
for (( c=1; c<=$K; c++ ))
do
    curl --insecure --silent $HTTPSA >/dev/null&
done
date +%M-%S-%N>>curlres.txt

JSSE SSL

keytool -keystore keystore -genkey -alias tomcat -keyalg RSA
  1. Bitte als Password changeit wählen
  2. Als CN bzw. „Vor- und Nachname“ den Name des Server oder die IP angeben.
  3. Beispieleingabe
Neues Kennwort erneut eingeben: 
Wie lautet Ihr Vor- und Nachname?
  [Unknown]:  localhost
Wie lautet der Name Ihrer organisatorischen Einheit?
  [Unknown]:  development
Wie lautet der Name Ihrer Organisation?
  [Unknown]:  tomcat
Wie lautet der Name Ihrer Stadt oder Gemeinde?
  [Unknown]:  Bochum
Wie lautet der Name Ihres Bundeslands?
  [Unknown]:  NRW
Wie lautet der Ländercode (zwei Buchstaben) für diese Einheit?
  [Unknown]:  de
Ist CN=localhost, OU=development, O=tomcat, L=Bochum, ST=NRW, C=de richtig?
  [Nein]:  j
<Executor name="Catalina-Threads" namePrefix="Catalina-exec" maxThreads="200" minSpareThreads="50" />

<Connector
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           port="${port.prefix}43"
           connectionTimeout="120000"
           executor="Catalina-Threads"
           scheme="https"
           secure="true"
           SSLEnabled="true"
           keystoreFile="${catalina.base}/conf/keystore"
           keystorePass="changeit"
           clientAuth="false"
           sslProtocol="TLS"/>

Aufruf

https://localhost:7343/hello/index.jsp

Selfsign Cert mit eignem Ablaufdatum von 360 Tagen

keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048

Links

Tomcat Tuning

Tomcat JSPC

Download des Packet TomcatDeployer (apache-tomcat-6.0.35-deployer.tar.gz)

http://tomcat.apache.org/download-60.cgi

apache-tomcat-6.0.35-deployer/deployer.properties

url=http://localhost:7480/manager
username=manager
password=tomcat
webapp=/home/nutzer01/workshop/node74/webapps/ROOT
path=/myapp
  • ant
  • ant deploy

Eine neue Anwendung mit vorkompilierten JSP befindet sich in der Instanz node74.

Monitoring

Tomcat Manager API

|JMX_Proxy_Servlet

Alle MBeans

curl --user manager:tomcat http://192.168.1.218:7380/manager/jmxproxy?qry=*:*

Ein Mbean

curl --user manager:tomcat http://192.168.1.218:7380/manager/jmxproxy?qry=tomcat.jdbc:*
OK - Number of results: 1

Name: tomcat.jdbc:name="jdbc/DB",type=ConnectionPool,class=org.apache.tomcat.jdbc.pool.DataSource
modelerType: org.apache.tomcat.jdbc.pool.jmx.ConnectionPool
Size: 10
Idle: 10
Active: 0
NumIdle: 10
NumActive: 0
WaitCount: 0
Name: Tomcat Connection Pool[1-219730313]
Username: root
MaxAge: 0
MaxActive: 20
Password: Password not available as DataSource/JMX operation.
DefaultTransactionIsolation: -1
DriverClassName: com.mysql.jdbc.Driver
MaxIdle: 10
MinIdle: 10
InitialSize: 10
MaxWait: 15000
TestOnBorrow: true
TestOnReturn: false
TestOnConnect: false
TimeBetweenEvictionRunsMillis: 10000
NumTestsPerEvictionRun: 0
MinEvictableIdleTimeMillis: 180000
TestWhileIdle: true
Url: jdbc:mysql://127.0.0.1/tomcat?autoReconnect=true
ValidationQuery: SELECT 1
ValidationInterval: 30000
AccessToUnderlyingConnectionAllowed: true
RemoveAbandoned: true
RemoveAbandonedTimeout: 60
LogAbandoned: false
DbProperties: {user=root}
JdbcInterceptors: org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;             org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=2,maxQueries=1000)
JmxEnabled: true
FairQueue: true
UseEquals: true
AbandonWhenPercentageFull: 0
UseLock: false
SuspectTimeout: 0
AlternateUsernameAllowed: false
CommitOnReturn: false
RollbackOnReturn: false
UseDisposableConnectionFacade: true
LogValidationErrors: false
PropagateInterruptState: false
PoolName: Tomcat Connection Pool[1-219730313]
JdbcInterceptorsAsArray: Array[org.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition] of length 4
	org.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition@46e5dce1
	org.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition@856140c
	org.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition@4b3e241a
	org.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition@5cb44d8d
PoolSweeperEnabled: true

Anfrage an ein Attribute

curl --user manager:tomcat 'http://192.168.1.218:7380/manager/jmxproxy?get=tomcat.jdbc:name="jdbc/DB",type=ConnectionPool,class=org.apache.tomcat.jdbc.pool.DataSource&att=NumActive'

Result

OK - Attribute get 'tomcat.jdbc:name="jdbc/DB",type=ConnectionPool,class=org.apache.tomcat.jdbc.pool.DataSource' - NumActive = 0

Holte Anzahl der Busy Thread vom HTTP Connector

curl -X GET -u manager:tomcat "http://192.168.1.218:7480/manager/jmxproxy?get=Catalina:type=ThreadPool,name=%22http-bio-7480%22&att=currentThreadsBusy"

Ausgabe

OK - Attribute get 'Catalina:type=ThreadPool,name="http-bio-7480"' - currentThreadsBusy = 2

psi-probe

http://code.google.com/p/psi-probe
  • Download und probe.war in die Instanz kopieren

Manchmal gibt es Hänger beim Runterfahren von probe

Füge diese Startkonfiguration des Quartz Job Scheduler der Probe Anwendung hinzu: bin/setenv.sh

export CATALINA_OPTS="${CATALINA_OPTS} -Dorg.quartz.scheduler.makeSchedulerThreadDaemon=true -Dorg.quartz.scheduler.skipUpdateCheck=true"

Weitere Parameter http://quartz-scheduler.org/documentation/quartz-1.x/configuration/ConfigMain

Hat auch nicht geklappt! webapps/probe/WEB-INF/classes/shutdown

package shutdown;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.quartz.Scheduler;

public class ShutDownHook implements ServletContextListener {

@Override
public void contextDestroyed(ServletContextEvent arg0)
{
   try {
      // Get a reference to the Scheduler and shut it down
      WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
      Scheduler scheduler = (Scheduler) context.getBean("scheduler");
      scheduler.shutdown(true);

      // Sleep for a bit so that we don't get any errors
      Thread.sleep(1000);
   } catch (Exception e) {
      e.printStackTrace();
   }
}

@Override
public void contextInitialized(ServletContextEvent arg0){
}

}

Compile ShutDownHook.java

cd /workshop/node73/webapps/probe/WEB-INF/classes/shutdown
javac -cp ~/workshop/apache-tomcat/lib/servlet-api.jar:../../lib/quartz-1.6.0.jar:../../lib/spring-core-2.5.6.SEC01.jar:../../lib/spring-web-2.5.6.SEC01.jar:../../lib/spring-context-2.5.6.SEC01.jar:../../lib/spring-beans-2.5.6.SEC01.jar ShutDownHook.java 

WEB-INF/web.xml

<web-app ..>
       <display-name>PSI Probe for Apache Tomcat</display-name>
       <listener>
           <listener-class>shutdown.ShutDownHook</listener-class>
       </listener>
       ...
</web-app>       

javamelody

  • Download und javamelody.zip auspacken

https://github.com/javamelody/javamelody/wiki/UserGuide

Installation in eine Anwendung.

cd workshop
wget http://javamelody.googlecode.com/files/javamelody-1.29.0.zip
mkdir javamelody-1.29.0-src
cd javamelody-1.29.0-src
unzip ../javamelody-1.29.0.zip
mkdir ../node74/webapps/hello/WEB-INF/lib
cp javamelody.jar ../node74/webapps/hello/WEB-INF/lib
cp jrobin-1.5.9.1.jar ../node74/webapps/hello/WEB-INF/lib

../node74/webapps/hello/WEB-INF/web.xml

        <filter>
                <filter-name>monitoring</filter-name>
                <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
                <init-param>
                        <param-name>storage-directory</param-name>
                        <param-value>${catalina.base}/javamelody</param-value>
                </init-param>

        </filter>
        <filter-mapping>
                <filter-name>monitoring</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
        <listener>
                <listener-class>net.bull.javamelody.SessionListener</listener-class>
        </listener>
        
        <login-config>
                <auth-method>BASIC</auth-method>
                <realm-name>Monitoring</realm-name>
        </login-config>
        <security-role>
                <role-name>monitoring</role-name>
        </security-role>
        <security-constraint>
                <web-resource-collection>
                        <web-resource-name>Monitoring</web-resource-name>
                        <url-pattern>/monitoring</url-pattern>
                </web-resource-collection>
                <auth-constraint>
                        <role-name>monitoring</role-name>
                </auth-constraint>
                <!-- if SSL enabled (SSL and certificate must then be configured in the server)
                <user-data-constraint>
                        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
                </user-data-constraint> 
                -->
        </security-constraint>

Add User to Realm Database conf/tomcat-users.xml

  <role rolename="monitoring"/>
  <user username="monitoring" password="monitoring" roles="monitoring"/>

evtl. restart des Servers oder Reload der Anwendung.. Zugriff auf die Monitoring-Informationen

http://localhost:7480/hello/monitoring

<b>Tipp</b> Auf Servlet API 3.0 WebContainer wie der Tomcat 7 oder 8 kann man Java Meldody auf als Plugin in einen bestehende Anwendung einbinden, da die javameldody.jar (>1.48) ein META-INF/web-fragment.xml enthält.

In der eigenen Anwendung wird javamelody aktive wenn es im WEB-INF/lib Verzeichnis ist.

Für eine externe Einbindung kann man den ClassLoader der Anwendung einbinden.

cd node74
mkdir plugin
cp XXX/javamelody.jar plugins
cp jrobin-1.5.9.1.jar plugins
cd webapps/hello/
vi META-INF/context.xml

META-INF/context.xml

<Context>
<Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="${catalina.base}/plugins/javamelody.jar;${catalina.base}/plugins/jrobin-1.5.9.1.jar"
/>
</Context>

Es ist darauf zu achten, das

metadata-complete

auf <i>true</i> steht und bei der Wahl der absoluten Reihenfolgen von Fragments JavaMelody enthalten ist.

cd plugins
mkdir javamelody
cd javamelody
jar xf ../javamelody.jar
cd META-INF
vi web-fragment.xml
cd ..
# VORSICHT überschreibt orginal!
jar cf ../javamelody.jar

web-fragment.xml

<web-fragment xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
        version="3.0">
        <name>JavaMelody</name>
        <filter>
                <filter-name>javamelody</filter-name>
                <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
                <async-supported>true</async-supported>
        </filter>
        <filter-mapping>
                <filter-name>javamelody</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
        <listener>
                <listener-class>net.bull.javamelody.SessionListener</listener-class>
        </listener>
        
        <security-role>
            <role-name>monitoring</role-name>
        </security-role>
        <security-constraint>
                <web-resource-collection>
                        <web-resource-name>Monitoring</web-resource-name>
                        <url-pattern>/monitoring</url-pattern>
                </web-resource-collection>
                <auth-constraint>
                        <role-name>monitoring</role-name>
                </auth-constraint>
        </security-constraint>

</web-fragment>

Explizites einbinden webapps/hello/WEB-INF/web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="false">


        <login-config>
                <auth-method>BASIC</auth-method>
                <realm-name>Monitoring</realm-name>
        </login-config>
        <!-- only use JavaMelody -->
        <absolute-ordering>
           <name>JavaMelody</name> 
        </absolute-ordering>

</web-app>

Jolokia

http://www.jolokia.org/
  • Download und jolokia.war in die Instanz kopieren
  • Zugriff mit http und Ausgabe in JSON
  • Es existiert eine Perl Adpater der direkt fuer Nagios genutzt werden kann.

prometheus

http://prometheus.io/ https://github.com/prometheus/jmx_exporter

download linux 64 bit binary

cp jmx4prometheus.json node73/conf
cp -r prom node73/webapps/prom
node73/bin/restart.sh
./prometheus -config.file prometheus.conf

open localhost:9090/graph

prometheus.conf

# Global default settings.
global: {
  scrape_interval: "15s"     # By default, scrape targets every 15 seconds.
  evaluation_interval: "15s" # By default, evaluate rules every 15 seconds.

  # Attach these extra labels to all time series collected by this Prometheus instance.
  labels: {
    label: {
      name: "monitor"
      value: "tutorial-monitor"
    }
  }
}

# A job definition containing exactly one endpoint to scrape: Prometheus itself.
job: {
  # The job name is added as a label `job={job-name}` to any time series scraped from this job.
  name: "prometheus"
  # Override the global default and scrape targets from this job every 5 seconds.
  scrape_interval: "5s"

  # Let's define a group of static targets to scrape for this job. In this
  # case, only one.
  target_group: {
    # These endpoints are scraped via HTTP.
    target: "http://localhost:9090/metrics"
  }
}

job: {
  name: "prom4jmx"
  scrape_interval: "15s"
  target_group: {
      labels: {
        label: {
            name: "zone"
            value: "de-berlin-1"
        }
        label: {
            name: "env"
            value: "dev"
        }
    }
    target: "http://127.0.0.1:7380/prom/metrics"
  }
}

jmx4prometheus.conf

{
  "lowercaseOutputName": true,
  "lowercaseOutputLabelNames": true,
  "rules": [
    {
      "pattern": "Catalina<type=GlobalRequestProcessor, name=\"(\w+-\w+)-(\d+)\"><>(\w+):",
      "name": "tomcat_$3_total",
      "labels": {
        "protocol":"$1",
        "port":"$2" },
      "help": "Tomcat global $3",
      "type": "COUNTER",
    },
    {
      "pattern": "Catalina<j2eeType=Servlet, WebModule=//([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), name=([-a-zA-Z0-9+/$%~_-|!.]*), J2EEApplication=none, J2EEServer=none><>(requestCount|maxTime|processingTime|errorCount):",
      "name": "tomcat_servlet_$3_total",
      "labels": {
        "module":"$1",
        "servlet":"$2" },
      "help": "Tomcat servlet $3 total",
      "type": "COUNTER",
    },
    {
      "pattern": "Catalina<type=ThreadPool, name=\"(\w+-\w+)-(\d+)\"><>(currentThreadCount|currentThreadsBusy|keepAliveCount|pollerThreadCount|connectionCount):",
      "name": "tomcat_threadpool_$3",
      "labels": {
        "protocol":"$1",
        "port":"$2" },
      "help": "Tomcat threadpool $3",
      "type": "GAUGE",
    },
    {
      "pattern": "Catalina<type=Manager, host=([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), context=([-a-zA-Z0-9+/$%~_-|!.]*)><>(processingTime|sessionCounter|rejectedSessions|expiredSessions):",
      "name": "tomcat_session_$3_total",
      "labels": {
        "host":"$1",
        "context":"$2" },
      "help": "Tomcat session $3 total",
      "type": "COUNTER",
    },
  ]
}

More

DB Zugriff im Tomcat

Installation der Mysql

sudo aptitude install mysql-server
mysql -u root -p
create database tomcat ;
use tomcat ;
create table nutzer( firstname varchar(80), lastname varchar(80));
insert into nutzer values ("Nutzer01", "linuxhotel" );
quit

Im Dialog ein Password setzen. (tomcat)

Laden des MYSQL Treibers

http://www.mysql.com/downloads/connector/j/
evtl. scp mysql-connector-java-5.1.17.zip nutzer24@notebook24:/home/nutzer24/workshop
  • Kopieren des Treibers nach workshop/node74/lib
unzip mysql-connector-java-5.1.17.zip
cd mysql-connector-java-5.1.17
mkdir -p ../node74/lib
cp mysql-connector-java-5.1.17-bin.jar ../node74/lib

Definition einer DB-Ressource im Tomcat

node74/conf/server.xml

<GlobalNamingResources>
...
  <Resource name="jdbc/DB" auth="Container"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat"
          username="root"
          password="tomcat"
          maxActive="20"
          maxIdle="10"
          maxWait="15000"
	  removeAbandoned="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          />
...
</GlobalNamingResources>

Tomcat 8 DBCP 2

node74/conf/server.xml

<GlobalNamingResources>
...
   <Resource name="jdbc/DB" auth="Container"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat"
          username="root"
          password=""
          maxTotal="20"
          maxIdle="10"
          maxWaitMillis="15000"
          removeAbandonedOnBorrow="true"
          removeAbandonedOnMaintenance="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          />
</GlobalNamingResources>

Anlage einer Anwendung die die Ressource nutzt

cd node74/webapps
mkdir nutzer
mkdir nutzer/META-INF/
mkdir nutzer/WEB-INF
cd nutzer

META-INF/context.xml

<Context>
   <ResourceLink name="jdbc/DB" global="jdbc/DB" type="javax.sql.Datasource" />
</Context>

WEB-INF/web.xml

<web-app>
   <resource-ref>
  	<description>JDBC DB</description>
        <res-ref-name>jdbc/DB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
     </resource-ref>
</web-app>

index.jsp

<%@ page import="javax.sql.*,javax.naming.*,java.sql.*" session="false" %>
<%
InitialContext initCtx = new InitialContext() ;
Context envCtx = (Context)initCtx.lookup("java:comp/env/");
DataSource datasource =
     (DataSource) envCtx.lookup("jdbc/DB" ) ;
Connection con = null;
Statement stmt = null ;
ResultSet srs = null;

try {
  con = datasource.getConnection();
  stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                                     ResultSet.CONCUR_READ_ONLY);
  srs = stmt.executeQuery(
    "SELECT firstname, lastname FROM nutzer");
  while (srs.next()) {
        String firstName = srs.getString("firstname");
        String lastName = srs.getString("lastname");
        out.println(firstName + "     " + lastName);
  }
} finally {
  if(srs != null) srs.close();
  if(stmt != null) stmt.close();
  if(con != null) con.close();
}
%>

Test der Anwendung

node74/bin/shutdown.sh
cp apache-tomcat-6.0.32/conf/catalina.properties node74/conf
node74/bin/startup.sh
http://localhost:7480/nutzer/index.jsp

webapps/nutzer/insert.jsp

<%@ page import="javax.sql.*,javax.naming.*,java.sql.*" session="false" %>
<html>
<body>
<h1>Nutzer anlegen</h1>
<%
InitialContext initCtx = new InitialContext() ;
Context envCtx = (Context)initCtx.lookup("java:comp/env/");
DataSource datasource =
     (DataSource) envCtx.lookup("jdbc/DB" ) ;
Connection con = null;
Statement stmt = null ;

try {
  con = datasource.getConnection();
  stmt = con.createStatement();
  for(int i = 0; i < 100; i++) 
  {
        String name = "nutzer-" + i ;
  	stmt.executeUpdate(
    	"insert into nutzer values('" + name + "', 'linuxhotel"+ i + "')");
        out.println("New user: " + name + "</br>");
  }
} finally {
  if(stmt != null) stmt.close();
  if(con != null) con.close();
}
%>
</body>
</html>

restart mysql

sudo service mysql stop
sudo service mysql start

Parameter für Profile und Slow Query Detection

    <Resource name="jdbc/DB" auth="Container"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat?autoReconnect=true&amp;profileSQL=true&amp;logSlowQueries=true&amp;slowQueryThresholdMillis=2"
          username="root"
          password="tomcat"
          maxActive="20"
          maxIdle="10"
          maxWait="15000"
	  removeAbandoned="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          />

Result

Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [QUERY] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 0 ms, connection-id: 2585, statement-id: 20540, resultset-id: 20776, message: SELECT firstname, lastname FROM nutzer
Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [FETCH] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 1 ms, connection-id: 2585, statement-id: 20540, resultset-id: 20776
Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [QUERY] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 1 ms, connection-id: 2585, statement-id: 20541, resultset-id: 20777, message: SELECT 1
Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [FETCH] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 0 ms, connection-id: 2585, statement-id: 20541, resultset-id: 20777
Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [SLOW QUERY] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 5 ms, connection-id: 2585, statement-id: 20542, resultset-id: 20778, message: The following query was executed using no index, use 'EXPLAIN' for more details: SELECT firstname, lastname FROM nutzer
Thu Sep 13 15:19:03 CEST 2012 INFO: Profiler Event: [QUERY] 	at org.apache.tomcat.dbcp.dbcp.DelegatingStatement.executeQuery(DelegatingStatement.java:208) duration: 5 ms, connection-id: 2585, statement-id: 20542, resultset-id: 20778, message: SELECT firstname, lastname FROM nutzer
Download des Treibers von Maven Repo Tomcat > 7.0.19 tomcat-jdbc.jar
Kopieren in die Tomcat Installation node73/lib
Anpassen der Resource Definition durch hinzufügen von factory und jmxEnabled
Restart des Tomcats

conf/server.xml

    <Resource name="jdbc/DB" auth="Container"
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat?autoReconnect=true"
          username="root"         
          password="tomcat"
          maxActive="20"
          maxIdle="10"
          maxWait="15000"
          removeAbandoned="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          jmxEnabled="true"
        jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=2,maxQueries=1000)"
          />

Cluster Replikation

In zwei Instanzen muss die Konfiguration geändert werden. Beide Instanzen müssen dann in einem Abstand von 30 Sekunden gestartet werden. Jeder Teilnehmer sollte ein exklusiven Port in sein Startskript schreiben das in den vier Instanzen node84,node85,node94 und node95 gleich ist.

node84/bin/startup.sh
node94/bin/startup.sh
export CATALINA_OPTS="${CATALINA_OPTS} -Dcluster.prefix=416"
node85/bin/startup.sh
node95/bin/startup.sh
export CATALINA_OPTS="${CATALINA_OPTS} -Dcluster.prefix=417"

conf/server.xml Einfache Konfiguration

<Engine ...

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"  channelSendOptions="8" >
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
              <Membership className="org.apache.catalina.tribes.membership.McastService"
                   port="${cluster.prefix}00"
                   />
              <Receiver address="127.0.0.1"
                className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                maxThreads="6" port="${cluster.prefix}${port.prefix}" selectorTimeout="5000" />
         </Channel>
      </Cluster>
<Engine>
...
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
   channelSendOptions="8"> 
   <Channel className="org.apache.catalina.tribes.group.GroupChannel" >
        <Membership className="org.apache.catalina.tribes.membership.McastService"
            address="228.0.0.4"
            port="${cluster.prefix}00"
            frequency="500"
            dropTime="3000"/> 
   </Channel>
</Cluster>

</Engine>

/etc/apache2/mods-available/jk.conf

JKWorkerProperty worker.list=loadbalancer,jkstatus

JKWorkerProperty worker.node84.port=8409
JKWorkerProperty worker.node84.host=localhost
JKWorkerProperty worker.node84.type=ajp13
JkWorkerProperty worker.node84.secret=tomcat
JkWorkerProperty worker.node84.domain=cl24

JKWorkerProperty worker.node85.port=8509
JKWorkerProperty worker.node85.host=localhost
JKWorkerProperty worker.node85.type=ajp13
JkWorkerProperty worker.node85.secret=tomcat
JkWorkerProperty worker.node85.domain=cl25

JKWorkerProperty worker.node94.port=9409
JKWorkerProperty worker.node94.host=localhost
JKWorkerProperty worker.node94.type=ajp13
JkWorkerProperty worker.node94.secret=tomcat
JkWorkerProperty worker.node94.domain=cl24

JKWorkerProperty worker.node95.port=9509
JKWorkerProperty worker.node95.host=localhost
JKWorkerProperty worker.node95.type=ajp13
JkWorkerProperty worker.node95.secret=tomcat
JkWorkerProperty worker.node95.domain=cl25

JKWorkerProperty worker.loadbalancer.type=lb
JKWorkerProperty worker.loadbalancer.balance_workers=node84,node85,node94,node95

JKWorkerProperty worker.jkstatus.type=status

nodeXX/conf/server.xml

...
     <Connector port="${port.prefix}09"
          executor="Catalina-Threads"
          protocol="org.apache.coyote.ajp.AjpProtocol"
          requiredSecret="tomcat" />
...

/etc/apache2/sites-available/default

JkMount /ClusterTest* loadbalancer
sudo apache2clt restart
cd workshop/cluster
node84/bin/shutdown.sh -force
node94/bin/shutdown.sh -force
node85/bin/shutdown.sh -force
node95/bin/shutdown.sh -force
wget http://192.168.1.189:2211/cluster/ClusterTest.war
cp ClusterTest.war node84/webapps
cp ClusterTest.war node94/webapps
cp ClusterTest.war node85/webapps
cp ClusterTest.war node95/webapps

Deployment der ClusterTest.war von der CD. Durchstarten der beiden Instanzen hintereinander mit einer kleinen Wartezeit 10sec - 1Min.

node84/bin/startup.sh
node94/bin/startup.sh
node85/bin/startup.sh
node95/bin/startup.sh

conf/server.xml

<?xml version='1.0' encoding='utf-8'?>
<Server port="${port.prefix}05" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.core.AprLifecycleListener"  SSLEngine="on"/>
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" 
              auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" 
              readonly="false" />
    <Resource name="jdbc/DB" auth="Container"
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat?autoReconnect=true"
          username="root"
          password="tomcat"
          maxActive="100"
          maxIdle="10"
          maxWait="15000"
	  removeAbandoned="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          jmxEnabled="true"
          jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
            org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx(threshold=2,maxQueries=1000)"
          />
<!--
    <Resource name="jdbc/DB" auth="Container"
          type="javax.sql.DataSource"
          driverClassName="com.mysql.jdbc.Driver"
          url="jdbc:mysql://127.0.0.1/tomcat?autoReconnect=true&amp;profileSQL=true&amp;logSlowQueries=true&amp;slowQueryThresholdMillis=2"
          username="root"
          password="tomcat"
          maxActive="20"
          maxIdle="10"
          maxWait="15000"
	  removeAbandoned="true"
          validationQuery="SELECT 1"
          testOnBorrow="true"
          testWhileIdle="true"
          timeBetweenEvictionRunsMillis="10000"
          minEvictableIdleTimeMillis="180000"
          />
-->
  </GlobalNamingResources>
   
  <Service name="Catalina">
     <Executor name="Catalina-Threads" namePrefix="Catalina-exec" maxThreads="200" minSpareThreads="50" />
     <Connector port="${port.prefix}70" executor="Catalina-Threads" protocol="org.apache.coyote.http11.Http11AprProtocol" />
     <Connector port="${port.prefix}80" executor="Catalina-Threads" protocol="org.apache.coyote.http11.Http11Protocol" />
     <Connector port="${port.prefix}90" executor="Catalina-Threads" protocol="org.apache.coyote.http11.Http11NioProtocol" />
     <Connector port="${port.prefix}09" executor="Catalina-Threads" protocol="org.apache.coyote.ajp.AjpProtocol" />

     <Connector port="${port.prefix}43" 
    executor="Catalina-Threads" 
    protocol="org.apache.coyote.http11.Http11AprProtocol"
    scheme="https"
    secure="true"
    sslProtocol="TLS"
	SSLEnabled="true"
	SSLCertificateFile="${catalina.base}/conf/tomcatcert.pem"
	SSLCertificateKeyFile="${catalina.base}/conf/tomcatkey.pem"
	SSLPassword="tomcat"
     />
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="node${port.prefix}">
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
      <Valve className="org.apache.catalina.valves.AccessLogValve" 
             directory="logs"  
             prefix="access-" 
             suffix=".log" 
             pattern="%h %l &quot;%u&quot; &quot;%{begin:yyyy-MM-dd hh:mm:ss.SSSZ}t&quot; %{msec}t &quot;%r&quot; %s %b %D %S" 
             resolveHosts="false"
      />
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"  channelSendOptions="8" >
          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
              <Membership className="org.apache.catalina.tribes.membership.McastService"
                   port="${cluster.prefix}00"
                   />
              <Receiver address="127.0.0.1"
                className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                maxThreads="6" port="${cluster.prefix}${port.prefix}" selectorTimeout="5000" />
         </Channel>
      </Cluster>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true" >
      </Host>
    </Engine>
  </Service>
</Server>

Static Member

<Cluster channelSendOptions="8" channelStartOptions="3" className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
   <Manager className="org.apache.catalina.ha.session.DeltaManager" 
            expireSessionsOnShutdown="false" domainReplication="true"
            notifyListenersOnReplication="true" />
   <Channel className="org.apache.catalina.tribes.group.GroupChannel">

       <Membership className="org.apache.catalina.tribes.membership.McastService"
                   port="${cluster.prefix}00"
                   domain="test-domain"/>

       <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
           <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
       </Sender>
       <Receiver address="127.0.0.1"
          className="org.apache.catalina.tribes.transport.nio.NioReceiver"
          maxThreads="6" port="${cluster.prefix}${port.prefix}" selectorTimeout="5000" />
       <Interceptor className="interceptors.DisableMulticastInterceptor" />
       <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
       <Interceptor className="org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor">
          <Member className="org.apache.catalina.tribes.membership.StaticMember"
             port="${cluster.prefix}74"
             host="127.0.0.1"
             domain="test-domain"
             uniqueId="{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}" />
       </Interceptor>
       <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor" />
     </Channel>
     <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"     
            filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" />
     <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
package interceptors;

import org.apache.catalina.tribes.group.ChannelInterceptorBase;
import org.apache.catalina.tribes.ChannelException;
import org.apache.catalina.tribes.Channel;

public class DisableMulticastInterceptor extends ChannelInterceptorBase { 
     @Override
     public void start(int svc) throws ChannelException {
        svc = (svc & (~Channel.MBR_TX_SEQ)); super.start(svc); 
     }
}

Sicherheit

Lösche Tomcat Version Numer in Fehlerreports des Tomcats

cd node74
mkdir -p lib/org/apache/catalina/util
vi lib/org/apache/catalina/util/ServerInfo.properties
bin/restart.sh

lib/org/apache/catalina/util/ServerInfo.properties

server.info=Apache Tomcat
server.number=
server.built=Mar 7 2014 02:18:35
tomcat_administration/start.1456849259.txt.gz · Zuletzt geändert: 2016/03/01 16:20 von peter_rossbach1