Consulta web service

Hola a todos

Tengo una consulta que hacerles

N número de PCs > 100, consumen un web service, básicamente lo que envían es un archivo con n número de líneas (el archivo lo convierto a un arreglo de bytes porque creo no se pueden pasar archivos (java.io.File) o almeno Yo no sé cómo), el punto es que estos datos que se envían una vez que llegan de lado del servidor son procesados y luego se insertan a una BD.
Tengo una hora pico en la que muchos clientes están haciendo uso del web service y no todos los datos se están insertando en la BD.

En lo que quiero que me apoyen es en saber cómo determinar que está sucediendo para que no se inserten los datos

He pensado que transparente para mí el programa se comporta como si se hubiera implementado con hilos y simplemente cuando llega una petición si puede la atiende sino la ignora o algo así.

Tengo identificado que hay registros en la BD que se insertan intercalados es decir cada archivo tiene un identificador único este ID se inserta como parte de un campo dentro de la BD y noto que hay veces en que aparecen de la siguiente forma:

Por ejemplo archivo: 1, 2 y 3
CAD_N_Consecutivo | CAD_N_ID_Archivo |….
5000 | 1 |…
5001 | 3 |…
5002 | 2 |…
5003 | 1 |…
5004 | 2 |…

La arquitectura física es: un servidor de BD(servidor dedicado) un servidor de aplicaciones(servidor dedicado) y las PCs distribuidas en la Ciudad.

He pensado que puede ser la comunicación entre los servidores es decir el tráfico en la red, que se estén provocando bloqueos muy grandes en la tabla, alguna deficiencia en el programa java (seria mi responsabilidad :( ) o que los planetas no están bien alineados jajaj

En un ambiente aislado los archivos ‘suben’ sin problema completitos

He pensado que una solución sería implementar el método synchronized de lado del servidor

De antemano gracias a cualquier ayuda o comentario

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Es muy difícil saber así ( en

Es muy difícil saber así ( en un foro ) que puede estar sucediendo, pero yo revisaría primero que todos las peticiones lleguen al servidor y que el servidor le responda al cliente de regreso. Para ello podrías escribir logs en ambos lados y ver que se reciban.

Si todas las conexiones llegan, entonces debes de revisar tu programa. ¿El servidor lo hiciste tu mismo o estas usando un servidor de aplicaciones? En términos generales no deberías de ponerle   a tu código porque estas deberías de estar usando un método sin estado del lado del servidor y no un método de un solo objeto con variables compartidas. Si hiciste el servidor tu mismo puede ser que en la implementación te este fallando como atender cada cliente. Si estas usando un servidor de aplicaciones la probabilidad de estos errores son menos pues un servlet container te debe de ayudar a manejar cada cliente de forma correcta.

Es poco lo que te puedo decir, pero primero revisa si te llegan todas las conexiones. :(

Suerte

Imagen de ezamudio

consejos generales

Como dice Oscar, es difícil saber sin más detalle, pero en general los consejos son los mismos que para cualquier aplicación concurrente:

  • No guardes estado en los componentes involucrados en el web service
  • Trata de que tus componentes sean puros singletons, no deberías necesitar instanciar componentes en cada petición
  • Maneja pool de conexiones a base de datos
  • De ser posible, maneja pool de procesos que tienes que realizar
  • Evita que tus operaciones a base de datos hagan bloqueo si no es necesario, configura muy bien la transaccionalidad
  • Evita al máximo tener que usar  . De ser absolutamente necesario, identifica muy bien tus secciones críticas y utiliza los candados más apropiados en cada una.

Bueno, de hecho consultar un

Bueno, de hecho consultar un mismo WS al mismo tiempo es crear varios hilos de ese servicio... te recomiendo ir de atras hacia adelante, podrias poner una traza en el resguardo de datos, en le procesamiento de datos y finalmente en la obtencion de datos, ahi puedes checar donde no se rompio e proceso

Por lo que creo el servidor de DB sigue sano y no hay sospechas de que se haya caido y tampoco el Servidor de tu WS porqe puedes seguir usando e WS.... verifica que la conexion con la DB no se este cerrando (si como dice enrique puedes meterle un pool estaria genial)... un consejo general, nunca gnores las excepciones as que si por ahi tienes ignorada alguna "al menos pintala"

ah jijos, no se me ocurre algo mas que no se haya dicho!
mientras intenta lo mencionado y a ver que pasa

OK

el servidor es JBoss 4.2.1
si uso un pool de conexiones para la BD

me late que el tema va mas por el lado de hilos pero hare una prueba con la implementacion de pool de procesos que recomienda zamudio

todos mis errores estan atrapados y pintados

de antemano muchas gracias

Imagen de ezamudio

threadpool

usando jboss tal vez no necesites hacer tu propio threadpool, pero sí sería bueno que revises parámetros del web service o web server (el tomcat de jboss), a ver cuántas peticiones simultáneas acepta; si dejas log de cada petición que entra, puedes contarlas en hora pico para saber cuántas recibes por minuto o hasta por segundo, y ver si tienes suficientes conexiones en el pool de base de datos (qué pasa si no?)

Imagen de luxspes

Si estas usando select max, deja de hacerlo

No se que base de datos estes usando, pero es importante que para los incrementales no uses Select MAX(), no solo por que es muy ineficiente (bloquea toda la tabla) , si no por que cuando no es ineficiente (no la bloquea, en cuyo caso, varios registros acaban con el mismo id, y si tienes logica para que cuando el id ya exista haga update en ves de insert, podrias estar "perdiendo por sobreescritura" tus registros), entonces produce numeros repetidos.

Si estas en Oracle o Postgres, usa secuencias. Si no, entonces usa el campo autoincremental de tu tipo de base de datos (SQLServer y otras) o pon una tabla foliadora (con 2 campos: NombreIncremental y UltimoValor) y lleva con ella el control. Si usas la tabla foliadora, utiliza select for update para evitar incrementales repetidos.

Si por otro lado estas llevando el control del incrementa sin apoyo de la base de datos (a puro codigo Java) probablemente si tendras que meterte con rollos del syncronized (te recomiendo que no lo hagas, por que equivocarse es muy facil, es mejor dejarle esa chamba a la base de datos, solo evita el select max y estaras bien)

Imagen de ezamudio

tips prácticos

Como pediste en la ayuda en el otro foro donde ya estabas desviando el tema, aquí hay algunos tips prácticos, sin llegar a consultoría, primero porque es imposible sin ver todo el código y segundo porque a ver quién te da consultoría gratuita:

1. La clase Procesador como que sobra, no? Lo único que hace es internamente crear un ProcesadorDAO, a menos que lo de   sea mucho código que omitiste.
2. Por qué  ? No es más fácil simplemente  ?

Si entendí bien, entonces esa variable   contiene muchísimos datos. Si se llega a invocar tu método es porque ya pasó la decodificación del SOAP-XML y todo eso. Si el procesamiento de esos datos es muy intensivo de CPU, base de datos, tarda mucho, etc, por qué no lo haces asíncrono? Es decir que el cliente invoque el método y en ese momento solamente le devuelves una especie de ticket, un número secuencial que identifique su operación, pero hasta ese momento la operación consiste únicamente en generar el ticket y ponerlo en status "en proceso", y echar a andar un Thread aparte donde se haga el procesamiento de datos.

Tienes entonces que agregar otro método a tu servicio, para consultar el status de un ticket. Y el procesamiento de datos debe de actualizar el status del ticket como último paso (ponerle si quedó completo, si quedó incompleto, si tronó por alguna razón, si hubo un error por el que no se pudieron procesar los datos, etc). Y ese nuevo método simplemente revisa el ticket y devuelve su status.

Mis dos

Mis observaciones:

synchronized se utiliza cuando se quiere obtener acceso sincronizado a un recurso.

Como en el código que muestras no tienen ningún recurso compartido ( entiendase una variable de instancia o de clase ) entonces no tiene ningún caso ponerle synchronized a nada. Cada thread es un hilo de ejecución, y aunque este fuera el único objeto en tu aplicación cada invocación corre es su propio hilo sin molestar a los otros.

Es decir:

 

Si tuvieras una sola instancia de "Algo" y 500 hilos ejecutando "algo.metodo()" ningúno se estorbaría pues las variables que estén dentro del método son unicas por thread.

Entonces lo unico que lograrías al marcar el método como synchronized es que de los 500 threads, solo uno se ejecutara a la vez lo cual sería terrible e innecesario ( considerando que cada ejecución tomara 1 segundo serían 500 segundos para procesar la ultima petición , entonces NO LO HAGAS )

Login
Estás creando un login y luego enviado los datos, esto puede o no tener sentido dependiendo de tu aplicación, pero si te es posible haz una sola invocación pasando el login junto con los datos y revisa que no estés enviando datos innecesarios. Así le podrias reducir de golpe y porrazo a la mitad el numero de peticiones que se le hace a tu servicio. Pero de nuevo esto depende de la naturaleza de tu app.

Para revisar lo que se te está perdiendo vas a tener que revisar los logs y con algun script ver si esos datos se te estan perdiando antes de llegar al servidor o una vez que llegaron y tu no los puedes guardar.

Inserción
Si a tu tabla le insertas > 1.5 M de registros diarios, quiere decir que a la semana > 10M y en total ...pffff pues tu sabrás! pero sería mucho más eficiente crear una tabla de paso donde se inserten los dato y cada día se copien a la tabla correcta, así en vez de tener que ir a insertar al registro 10,000,000 o 20,000,000 iria a insertar a lo mucho al registro 1,500,000.

Ok es un tip

1. lo de Procesador no, no sobra es un pinche monstruo de operaciones y validaciones
2. jajaj si es la costumbre de una mala maña

Ok 'tons' segun entiendo deberia hacer un thread dentro del programa y entonces ese thread digamos interno afectaria al thread que me cree el servidor supongo

De cualquier forma gracias

Nota para @ezamudio; cuando escribi que no hay que ser despectivos es porque la neta comentarios como "Los programadore novatos" si es medio despectivo, desde mi punto de vista siplemente diria "si puedes ayudar pues hazlo y no eches en cara o evidencies ", pero bueno ese es otro tema.

Imagen de ezamudio

novato es un insulto?

No sabía que novato era un insulto. Yo lo uso para la gente que es nueva en algo. Cuando empecé a programar era un programador novato y en aquél entonces enojarme porque alguien me llamara novato hubiera sido una respuesta inapropiada pues no había falsedad en la declaración.

Ahora, es un hecho que hay errores de novatos, y pues así hay que llamarles. Por ejemplo, en Java, no distinguir entre tipos nativos y objetos, es un error de novato (ya sea novato en la programación o novato en Java). Si la palabra "novato" no te gusta, puedes sustituirla mentalmente por "neófito", para el caso es lo mismo.

Lo que se puede tomar como un insulto es que a un programador con experiencia le digan que cometió un error de novato. Pero si yo cometo un error de novato y alguien me lo dice, pues... no deja de ser menos cierto si no me lo dice. Y un programador con experiencia no está exento de cometer errores de novato, y luego son hasta más difíciles de encontrar porque ya uno está buscando problemas muy complejos y resulta ser algo bien simple.

En javaMexico.org no tenemos manera de saber si alguien es novato o tiene 50 años de experiencia programando, porque no viene nada de eso en el perfil de usuario. Solamente se puede inferir por los comentarios de cada quién. En fin, si te ofendiste porque te llamdé novato, no lo tomes como un insulto; no tengo manera de saber si eres novato o si tienes mucha experiencia.

...hubiera sido una respuesta

...hubiera sido una respuesta inapropiada pues no había falsedad en la declaración

Ja ajjaja no manches me hiciste el día! jajajaja Te oiste bien ministerio público Lo que viene siendo falsedá en la declaración del inculpadoooO

Ehem

Pero sí, no te fijes en ese tipo de "detallitos" sino en lo esencial, es cierto que sobra el calificativo, pero tampoco es como para desviar el tema ( una vez maaaaaaas @Rodrigo, como va esa gráfica de desviación de tema? )

:)

Yo cometi un error de novatos

Yo cometi un error de novatos que me hizo perder dia y medio... estaba buscando entre cosas de no tan novatos y sucedio lo que dice enrique:

Y un programador con experiencia no está exento de cometer errores de novato, y luego son hasta más difíciles de encontrar porque ya uno está buscando problemas muy complejos y resulta ser algo bien simple.

Finalmente pudo haber sido el NPE y si, efectivamente valide todo excepto un campo y ese fue lo que hizo valer chetos todo... bueno me sigo apurando en la chamba!!!

esto es de lo que hablo

Imagen de ezamudio

Thread

Lo del thread es más o menos así:

Primero que nada, necesitas un Runnable (puede ser tu Procesador, solamente hazlo Runnable):

 

 

Ahora, el chiste está en la manera en que implementas el Procesador:

 

Y con eso, tienes lo siguiente:

1. Una operación larga que se puede invocar de manera separada al método web
2. Un método web que genera un ticket y lo devuelve al usuario para que tenga una respuesta rápida, en vez de dejarlo esperando a que termine una operación larga
3. Un método web para que el usuario pueda revisar cómo va su operación larga (nomás diles que no se manchen consultando 10 veces por segundo, no tiene caso).

La operación larga (en la clase Procesador) primero pone el ticket en status de que está siendo procesado y comienza a hacer toda su talacha. Si ocurre un error durante el proceso, pues termina y marca el ticket como incompleto (tú sabes si además de todo eso hay que hacer rollback, etc; esto realmente lo intercalarás con el código que ya tienes). Si el proceso termina bien, le pones un status de OK. Y eso es todo.

Con esto, tienes una ventaja adicional: Si el proceso es tan intensivo que solamente debería haber uno a la vez, entonces puedes agregar una validación al principio del método que inicia el proceso, para validar que si existe ya un proceso en status 1, devuelves mejor un error, algo así:

 

El método   debe simplemente buscar si hay tickets con status 1:  . De esa forma solamente permitirás que haya un proceso de esos largos ejecutándose a la vez.

Imagen de benek

Flames

Nota para hugo.garcía:
Lo digo con la mejor intención, ten cuidado con los reclamos, podrían generar más problemas que el "detalle" inicial que incluso pudo ser malentendido. Lo digo porque estuve revisando el otro tema y me di cuenta de que @ezamudio ni siquiera fue el que hizo el comentario de "programador novato" (muy independientemente de si es verdad o no, que tampoco tiene nada de malo).

Si Enrique fuera gandalla, ya ni te hubiera explicado o respondido después de reclamarle por algo que ni siquiera hizo.

Hay que tomar en cuenta el valor real de las respuestas, quizá no se hable blandito en este sitio, pero de que el contenido aporta valor, ¡lo hace!

Saludos.

@benek: En realidad no se lo

@benek: En realidad no se lo reclama a Enrique, más bien le responde porque lo dice ( Enrique le pregunta "¨juay de rito" y Hugo le contesta... bernabe le pego a muchilanga y etc. etc. ) Es decir era una explicación más que un reclamo.

Imagen de benek

Malentendidos

Yo lo decía por esto: "Nota para @ezamudio; cuando escribi que no hay que ser despectivos es porque la neta comentarios como "Los programadore novatos" si es medio despectivo". Pero pude haberlo malentendido.

Ya se hizo una maraña de malentendidos, mejor sigamos con lo técnico. :-)

Saludos.

no manchen

No hagan esto mas grande

Oscar tiene razon no es un reclamo para enrique y ademas despectivo no es sinonimo de insulto; obvio novato, neofito, rookie, etc no es un insulto

En fin no quise molestar a nadie

Por mi parte seria todo sobre apreciaciones

Imagen de ezamudio

regresando al tema...

Hugo, sería bueno que armes un ambiente de pruebas unitarias para ver si tu Procesador funciona bien fuera del web service. Arma lo necesario para correr un proceso sin que tenga que ser en el web service, en un ambiente de pruebas, y veas si ahí jala todo bien, o si también se pierden algunos datos. En caso que se pierdan, será más fácil que averigües por qué se pierden esos datos, llenando de logs y println el código, corriendo todo con debugger, etc.

Si no se pierden datos cuando lo ejecutas así, entonces puede ser alguna cosa de concurrencia, aunque no necesariamente algo en tu web service, sino de concurrencia a nivel base de datos. Esa tabla donde metes tus millones de registros, se está leyendo constantemente por otras aplicaciones? Hay otras aplicaciones escribiendo en ella además de tu servicio?

de hecho ya le hice pruebas

Le hice pruebas unitarias con todo y el webservice a un servidor de Desarrollo le hice pruebas de estres con jmeter y anda bien el asunto es que los DBAs se aferran a que el problema es la aplicacion

Esa tabla solo la consultamos nosotros pero en si la BD donde esta es enome y a cada rato es consultada tanto por los desarrolladores(2) como lo DBAs(2) entonces yendo a la teoria creo que hay bloqueos a veces a nivel de la BD

Si hay varias paginas web haciendo consultas y escrituras, ademas de jobs

Lo unico que puedo decir a favor de la BD es que periodicamente le dan mantenimiento, los execution plan de las consultas estan optimizadas.

Entonces yo quiero descartar que no es toda mi respondabilidad la perdida de informacion

Imagen de ezamudio

logs

Si te vas a pelear con los DBA's debes llevar documentación. Me refiero a que entonces tu operación debe generar un log de CADA DATO que inserta, antes y después, y al final poner un total, y mostrarle eso al DBA. Si tu log dice que tu aplicación insertó un millón de registros, y por cada registro dice "voy a insertar el registro 1" y luego "ya inserté el registro 1", y al final "registros insertados: 1000000", y no tuviste ningún error, entonces ellos tienen que demostrar por qué solamente tienen 900mil registros nuevos. Y además identificar una muestra aleatoria de esos 100mil perdidos y buscarlos en tu log, para ver si encuentran algún patrón. Puede ser un error de esos supermarcianos que sólo ocurren en producción bajo ciertas circunstancias... en conclusión, un Bugfoot.

db

ehcache consultas :)
Si estas haciendo una transaccion e incertando todas las lineas en la misma o haces un insert commit por cada una ?