Mostrando las entradas con la etiqueta tomcat. Mostrar todas las entradas
Mostrando las entradas con la etiqueta tomcat. Mostrar todas las entradas

miércoles, abril 16, 2008

Multiples instancias de Tomcat

Para correr multiples instancias de Tomcat en el mismo servidor.

Tengo un Tomcat instalado en un RHEL5 en /opt/apache-tomcat-5.5.23 con una liga simbólica de /opt/tomcat5
Dentro de esta instalación en /opt/tomcat5/conf/server.xml tengo configurados varias aplicaciones. Teniendo varias desventajas.
  • Si una aplicación consume muchos recursos, todas las demás bajan de rendimiento.
  • Si una aplicación congela el JVM, las demás dejan de funcionar también.
No es práctico tener una instancia para cada aplicación, sobre todo cuando estas son pequeñas soluciones.

Ahora estoy desarrollando para Tomcat 6 y no quise migrar todas la aplicaciones ya configuradas y probadas en Tomcat 5.5.

Cree un directorio nuevo /var/tomcat y extraje el último Tomcat 6 en /var/tomcat/apache-tomcat-6.0.16
Cree otro directorio, exclusivo para mi instancia lo llamé serverB (pensando en que luego habrá un serverA y un serverC) y cree el siguiente árbol.

|-- conf
| |-- server.xml
| |-- tomcat-users.xml
| `-- web.xml
|-- logs
| `-- catalina.out
|-- temp
|-- webapps
`-- work


Ahora viene lo bueno.
Para correr la instancia y que no choque con la que ya está corriendo, hay que cambiar algunos puertos.

<Service name="Catalina">
<Connector port="8082" URIEncoding="UTF-8" />

<!-- Define an AJP 1.3 Connector on port 8020 -->
<Connector port="8020" enableLookups="false" redirectPort="9972" protocol="AJP/1.3"
URIEncoding="UTF-8" />

Creamos un script de arranque,
run

#!/bin/sh -e
JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun-1.5.0.11"
JAVA_OPTS="-Xmx800m -Xms800m"
#CATALINA_HOME=/opt/tomcat5
CATALINA_HOME=/var/tomcat/apache-tomcat-6.0.16
CATALINA_BASE=/var/tomcat/serverB
export JAVA_HOME JAVA_OPTS CATALINA_HOME CATALINA_BASE

# -p preserves the environment (for $JAVA_HOME etc.)
# -s is required because tomcat's login shell is /bin/false
su -p -s /bin/sh tomcat -c "$CATALINA_HOME/bin/catalina.sh start"


y un script de parada
stop

#!/bin/sh -e
JAVA_HOME="/usr/lib/jvm/java-1.5.0-sun-1.5.0.11"
JAVA_OPTS="-Xmx800m -Xms800m"
CATALINA_HOME=/var/tomcat/apache-tomcat-6.0.16
CATALINA_BASE=/var/tomcat/serverB
export JAVA_HOME JAVA_OPTS CATALINA_HOME CATALINA_BASE

su -p tomcat -c "$CATALINA_HOME/bin/catalina.sh stop"


Ahora tenemos otro Tomcat corriendo en el mismo servidor con puertos diferentes. Creamos un workerb en /etc/httpd/conf/worker.properties apuntando al puerto 8020.

worker.workerb.port=8020
worker.workerb.host=localhost
worker.workerb.type=ajp13
worker.workerb.lbfactor=1


y listo!

sábado, julio 15, 2006

Java Studio Creator 2 y Tomcat 5.5

Uno de los mejores IDE para JSF es el nuevo Java Studio Creator 2 (JSC). Es muy fácil
crear aplicaciónes con una arquitectura muy similar a swing. JSC trae el Java
System Application Server 8.x Platform Edition para las pruebas durante el desarrollo.
Pero usualmente utilizo el Tomcat, pasé una tarde completa tratando de hace deploy
y me encontraba con este error.
Cannot create JDBC driver of class '' for connect URL 'null'
Seguí todas las instrucciones que mencionan en la página de Sun.
  1. Exportar el proyecto como War para JDK 1.4.1
  2. Incorporar las librerías jstl.jar y standard.jar JSTL 1.1
  3. Configurar el JNDI Datasource en Tomcat 5.5 (how-to)
  4. Si estamos usando MySQL u otro DBMS copiar su correspondiente jdbc driver o connector en /commons/lib
  5. Listo! es todo y ahora a probarlo en http://localhost:8080/app-name
Pues parece sencillo, pero el punto 3 tiene sus truquitos.

Imaginemos que tenemos una BD de nombre lamparas con un usuario lamparas y password lamparasdata. En el server.xml de tomcat el JDBC quedaría así:

<Resource name="jdbc/lamparas" auth="Container"
type="javax.sql.DataSource" username="lamparas" password="lamparasdata"
removeAbandoned="true" logAbandoned="true"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/lamparas?autoReconnect=true"
maxActive="8" maxIdle="4" />

Luego copiaríamos el WAR a al directorio /webapps
Tomcat lo descomprime y lo instala, nos aseguramos que en el web.xml (web descriptor) se encuentre la siguiente definición. El web.xml estará en
...
<resource-ref>
<description>Creator generated DataSource Reference</description>
<res-ref-name>jdbc/lamparas</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
...
Arrancamos la aplicación y funcionará normalmente hasta que algún componente que haga binding a un elemento de la BD se presente y entonces nos mostrará el error anterior.

Después de muchas horas de intentos fallidos, Saurondor me sugirió incluir en un Context la configuración del jdbc en server.xml yo le comenté que no me parecía la solución correcta pues entonces perdería toda practicidad hacer deploy con el WAR si de todas formas tengo que modificar el server.xml (que ya lo hice una vez, ¿no?). Para variar los errores con JSF son crípticos y en realidad no sabes lo que está pasando, pero parece ser que no encuentra la definicion del Datasource en server.xml por que le regresa valores nulos, con la configuración de arriba supuestamente la definición es global, pero no la lee.

Sin más que intentar y apunto del hartazgo le puse los tags de Context y sus parámetros. Lo intenté así y funcionó, respiré profundo y me dije que no volvería a desechar algo que parezca obvio.

La configuración final quedó así:

<Context path="/lamparasweb" docBase="lamparasweb" debug="5" reloadable="true"
crossContext="true">
<Resource name="jdbc/lamparas" auth="Container"
type="javax.sql.DataSource" username="lamparas" password="lamparasdata"
removeAbandoned="true" logAbandoned="true"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/lamparas?autoReconnect=true" maxActive="8" maxIdle="4" />
</Context>

*Actualización 5 mayo 2007
Vicente David comenta que podemos incluir esta información dentro de nuestro proyecto. Esto es muy útil cuando no tenemos acceso a los archivos de configuración del server logrando así una independencia en la configuración.

Con sólo incluir los datos dentro de un archivo llamado context.xml en META-INF. META-INF es un directorio con información de la aplicación que se lee cuando el WAR está siendo descomprimido. Es decir, sólo funcionará este método cuando estemos desplegando la applicación desde un WAR.

META-INF/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/lamparas" auth="Container"
type="javax.sql.DataSource" username="lamparas"
password="lamparasdata" removeAbandoned="true" logAbandoned="true"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/lamparas?autoReconnect=true" maxActive="8"
maxIdle="4" />
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>META-INF/context.xml</WatchedResource>
</Context>