miércoles, 23 de abril de 2014

Usando Apache Commons DBCP V2 en Tomcat 7

El componente por defecto para el manejo del pool de conexiones a base de datos en Tomcat 7 es DBCP v1.4, que si bien tiene varias mejoras de estabilidad con respecto a la versión que usa Tomcat 6, igual padece problemas de concurrencia, que se evidenciarán con alta carga de threads solicitando conexiones al pool, ya que el DBCP tiene que sincronizar el acceso al pool. Esto ha sido una fuente de problemas y cuellos de botella en Tomcat, más crítico en la v6 que en la v7.

A partir de Tomcat 7 hay un componente de Connection Pooling alternativo, Tomcat JDBC Pool, que provee acceso concurrente al pool y varias otras mejoras, sin embargo no viene configurado por defecto (ni siquiera en Tomcat 8) y es un proyecto relativamente nuevo. Su guía de configuración:

http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html

El viejo proyecto Apache DBCP se renovó de forma importante el 2014 con su versión 2.0, que ahora usa el nuevo Apache Commons Pool, con mejoras de escalabilidad y desempeño, apoyándose en el paquete java.util.concurrent, requiere Java 7. Esta versión es el nuevo pool por defecto en Tomcat 8, y dice resolver los problemas de concurrencia de las versiones 1.2 y 1.4.

En Tomcat 7 se puede reemplazar el uso del DBCP v1.4 por el v2.0, es necesario añadir los siguientes JARs a la carpeta /lib de Tomcat:

commons-dbcp2-2.0.jar
commons-pool2-2.2.jar
commons-logging-1.1.3.jar

Los proyectos respectivos para descargar (en sus últimas versiones) cada JAR son:

http://commons.apache.org/proper/commons-dbcp/
http://commons.apache.org/proper/commons-pool/
http://commons.apache.org/proper/commons-logging/

En la definición del pool de conexiones en META-INF/context.xml de la WebApp se debe indicar el atributo factory, para que use el nuevo pool DBCP 2:



<Resource auth="Container" name="jdbc/dinamica" type="javax.sql.DataSource"> factory="org.apache.commons.dbcp2.BasicDataSourceFactory"
initialSize="3" maxIdle="10" maxWait="3000" maxTotal="100"
username="postgres" password="basica"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost/demodb"/>



El atributo maxActive ahora se llama maxTotal, esto requirió un cambio en la clase dinamica.SysInfo del framework Dinámica, para poder reportar correctamente en su página de estatus (/action/test) la información de los pools, sin importar si utilza DBCP v1.4 o DBCP v2. El resto es transparente para las WebApps.

Ahora puede utilizar la tecnología -supuestamente- superior de DBCP v2 en un producto solido como Tomcat 7, sin esperar a que salga Tomcat 8 o recurrir a un componente menos probado con el Tomcat JDBC Pool (por algo tampoco es el pool manager por defecto en Tomcat 8).

Los pools de conexiones concurrentes son "la nueva tendencia" en este tipo de componentes, porque hace tiempo que junto con sus ventajas también introdujeron el problema de la sincronización para acceder al pool, creando cuellos de botella. Hay varios productos de diversa calidad que ya usan esta técnica, facilitada desde hace pocos años por el paquete java.util.concurrent de Java SE, pero adolecen de un problema básico en relación a Tomcat, no vienen preparados para ser configurados como un Factory de DataSources, un reemplazo a lo "plugin" para el pool manager por defecto de Tomcat 7. El Apache DBCP v2 si puede ser usado de esa manera, como lo mostramos arriba.

Existe en este nuevo ecosistema de Pool Managers un producto que destaca, se llama HikariCP, y su documentación es muy interesante, aunque lamentablemente no provee configuración nativa como un Resource en Tomcat 7:

http://brettwooldridge.github.io/HikariCP/

Actualización del 26/04/2014

El autor de HikariCP nos proveyó de una versión de desarrollo (HikariCP-1.3.7-SNAPSHOT.jar) que incluye el DataSource Factory que permite usar este componente dentro de Tomcat 7 de forma transparente a las aplicaciones.

<Resource name="jdbc/dinamica" auth="Container" type="javax.sql.DataSource"
factory="com.zaxxer.hikari.HikariJNDIFactory"
username="postgres" password="basica"
driverClassName="org.postgresql.Driver"
jdbcUrl="jdbc:postgresql://localhost/demodb"/>

Lo malo es que no es compatible en cuanto a los nombres de los atributos, así que requiere nuevos atributos para indicar máximo de conexiones, tamaño inicial del pool, etc. Esto también supone un problema ya que no se puede monitorear este pool vía JMX con las facilidades de diagnóstico del framework Dinámica, y no tenemos planes de soportarlo en el corto plazo, además carece de atributos tan básicos y útiles como numActive y numIdle, que te dan de inmediato una radiografía del uso del pool. De todos modos el experimento con HikariCP ha sido positivo, en la medida que este producto vaya madurando y cumpla su promesa de estabilidad y velocidad, será una alternativa importante para mejorar el desempeño de un servidor Tomcat 7. Nuestro agradecimiento a Brett Wooldridge, el creador de HikariCP, por su rápido apoyo para implementar el soporte a Tomcat 7.

Saludos,
El Team Dinámica

No hay comentarios: