Hace aproximadamente 1 año estoy liderando un proyecto de migración de APIS para un Front end de Facturación.
Las APIs al principio fuimos contra la Base, y cuando vimos que los tiempos claramente no eran los esperados ( luego supimos que unos de los requerimientos de las APIS era que su performance por request no deberían superar los 0.1 seg) tuvimos que implementar una solución de Elastic Search.
Partimos de un esquema de arquitectura que nos permitiese no solo la carga Online de manera escalable, si no que ademas pudiesemos hacer cargas de datos históricos, nosotros los llamamos "Cargas Iniciales", para que el usuario pueda ver su histórico de Facturación.
En ese tiempo descubrimos una serie de cuestiones y experiencias con ES que me pareció interesante compartirlo con uds.
* El modelado de ES a nivel de cluster es simplemente caprichoso. No existe una receta que nos indique cuál es el mejor modelado. Si podemos saber que los indices , cuando son muy grandes, requieren una gran cantidad de Yardas para que performe ( una yarda se desempeña de manera optima con hasta 10G de información. Nosotros llegamos a un esquema de más de 100 yardas).
El modelado iterativo sucederá inevitablemente ; para ello tener en claro los modelos de Procesos de Cargas, ya que lo tendremos que rehacer varias veces a nuestro cluster hasta que la performance sea la esperada.
* Rootear es fundamental. Los tiempos se mejoran mucho si se agrega este parámetro. Puede haber indicio de como armemos nuestros indices no lo necesitan. Pero si necesitan velocidad en cientos de gigas, esto es necesario
* El Scroll es una herramienta que no debemos olvidar.Para hacer consultas paginadas donde se necesita recolectar cientos de datos , pero no queremos penalizar la performance, hay que usarlo.
* Programar OO y TDD ayuda, y mucho. Code Reviews tambien. ES es una herramienta poderosa. Pero Armar las consultas pueden ser por demás engorrosas y muchas veces poco elegantes. El esquema de builders que utiliza no es el mas bello. Por lo que conviene ser prolijo a la hora de diseñar, y conocer claramente que escenarios queremos soportar.
* Las modificaciones no son baratas: tratemos siempre de entender claramente los escenarios funcionales. Si bien un modelo iterativo es el que mas me agrada, una falla de concepción del requerimiento del usuario impacta muchas veces en rehacer el indice, o por que no todo el elastic. Tener claro los conceptos ( para tener claros los test ) tendrá un claro impacto en nuestro ES. Saber cuantos usuarios lo usaran , cuanto volumen aproximado, cual es la consulta que mas nos importa son "hints" importantísimos para poder hacer un modelo en el cual las modificaciones no nos peguen de lleno y nos hagan re hacer la infraestructura.
* Juniors... con cuidado!. Parece tan simple usar elastic, parece fácil, pero no. Requiere idealmente que los desarrolladores sean maduros para encarar el uso de la herramienta. Desde la concepción Funcional del problema hasta donde implementar la solución es fundamental tener a alguien que pueda entender desde la infraestructura hasta los vericuetos funcionales del problema. Esto que menciono, tan abstracto, es lo que realmente lo hace facil y escalable. Cualquier falla en esto implicará que los diseños no sean los mejores, que los refactors sean en extremo costosos. Creo igualmente que esto en un punto aplica a cualquier proyecto. Tener un buen "counselor" en esto es casi menester. Si no, deberemos saber que haremos multiples refactors hasta lograr la implementación que responda a nuestros requerimientos siempre será cuestión de varias iteraciones.
* Migrar de Elastic , de versiones , sobre todo en productivos; con mucho cuidado. Es factible migrar datos de un Elastic a otro ( nos toco hacerlo de una versión 1.4 a una versión 1.7 ) . Hay que tener mucho cuidado con la situación de datos que vienen online y el pisado de datos que vienen desde el "otro" Elastic. Concurrencia es un gran Issue y riesgo a tener en cuenta.
Este es el enfoque desde un equipo que se luchó/lucha para lograr tener productivo un esquema con ES como motor de datos.
Si alguien tiene otras experiencias , con gusto escuchare. Si me acuerdo mas diatribas sobre lo mismo , Tambien lo volcaré.
Gracias por Pasar.
Tratando de Ser Paciente con esta Pasión
Hola! ante todo no pretendo aburrirlos con una introducción!
Soy simplemente un desarrollador que , si encuentro un tema interesante sobre el que me parece que pueda aportar mi experiencia, trataré de sumar , tratando de hacer alguna breve reseña al respecto.
Gracias por leer!
lunes, 21 de diciembre de 2015
lunes, 30 de noviembre de 2015
Pensar en patrones esta mal al inicio de un problema.
Siempre defendi los patrones de diseño. Para mi programar sin patrones de diseño es como querer ser mecánico de autos, sin haber hecho cursos al respecto. Que quiero decir ? Es posible que logres arreglar el auto, pero seguramente no será la mejor solución o serán soluciones fruto de la intuición y la experiencia en ese modelo ( a veces esto es mejor, pero estamos hablando de adivinar soluciones, intuir soluciones, vs entender el diagnostico y resolverlo basado en conceptos adquiridos).
Claramente con cosas nuevas te encontraras con nuevas situaciones las cuales quizás por aplicar soluciones ya vistas hagas entrar un circulo en un cuadrado, pero a la larga tendrás otros problemas. ( El que tuvo autos usados , donde mecánicos de la experiencia se los han arreglado.. sabe de lo que hablo ).
Los patrones te dan eso; que puedas pensar varios tipos de soluciones al respecto y encontrar de acuerdo a tu conocimiento del contexto, la llave, el destornillador adecuada que mejor convenga.
Espera un poquito; mi titulo dice "Pensar en patrones esta mal al inicio de un problema", como es entonces ? Por que la contradicción ?
No hay contradicción si sos un desarrollador TDD. Cuando arrancas un problema bajo el concepto "red, green, refactor" , tu único objetivo es lograr que la suites de problemas a los que pensás resolver estarán ok en la medida que vos puedas pasar de red a green, sin pre conceptos y sin arbitrariedades y , por sobre todas las cosas sin " por las dudas ". Tu única meta es que los test pasen.
OK. Es por eso que concluyo que pensar en patrones antes de implementar los test te sesgan a escenarios donde quizás estas haciendo por las dudas, entonces estas desarrollando cosas que quizás solucionen problemas que nunca ocurran, ó abriras puertas a escenarios que nunca se den; esto implica perdida de tiempo
Creo que el buen criterio seria aplicar la idea de patrones una vez que todos tus test pasan al estado "green", recién ahí empezás a pensar en que patron se adecua a la solución implementada. En ese momento, quizás el momento de la piedra libre a tus cualidades de razonamiento ( la parte divertida ) dadas las situaciones de problemas que investigaste para plantear tus escenarios de test, entendés por que será mejor un command, que un strategy ó un state pattern. Por que claramente usarías una factory o un builder, ó por que recién ahora conviene un mediator en lugar de un Facade, como presupusiste.
Buscar ser un eficiente TDD developer te llevará sin duda a ser un mejor Pattern oriented developer. Pensar para que vas usar el auto , te lleva ver como lo diseñas. Pensar algo que sirve por default para todas las soluciones no solo te cierra posibles contextos en los cuales quedes desajustado, si no que te lleve a implementar complejidades innecesarias que solamente te lleven a test innecesarios; Esta es la situación donde los que "desacreditan" TDD tienen razón para protestar por la productividad. Si hacemos cosas de mas , claramente le robamos tiempo a las cosas que si son necesarias.
La economía de recursos no implica malos diseños , implica Mejores diseños, es por eso que resolver los problemas con las ideas y herramientas adecuadas depende mucho de como se implemente mas alla de saber, ahora comparando con el ajedrez, cómo mover las piezas.
Claramente con cosas nuevas te encontraras con nuevas situaciones las cuales quizás por aplicar soluciones ya vistas hagas entrar un circulo en un cuadrado, pero a la larga tendrás otros problemas. ( El que tuvo autos usados , donde mecánicos de la experiencia se los han arreglado.. sabe de lo que hablo ).
Los patrones te dan eso; que puedas pensar varios tipos de soluciones al respecto y encontrar de acuerdo a tu conocimiento del contexto, la llave, el destornillador adecuada que mejor convenga.
Espera un poquito; mi titulo dice "Pensar en patrones esta mal al inicio de un problema", como es entonces ? Por que la contradicción ?
No hay contradicción si sos un desarrollador TDD. Cuando arrancas un problema bajo el concepto "red, green, refactor" , tu único objetivo es lograr que la suites de problemas a los que pensás resolver estarán ok en la medida que vos puedas pasar de red a green, sin pre conceptos y sin arbitrariedades y , por sobre todas las cosas sin " por las dudas ". Tu única meta es que los test pasen.
OK. Es por eso que concluyo que pensar en patrones antes de implementar los test te sesgan a escenarios donde quizás estas haciendo por las dudas, entonces estas desarrollando cosas que quizás solucionen problemas que nunca ocurran, ó abriras puertas a escenarios que nunca se den; esto implica perdida de tiempo
Creo que el buen criterio seria aplicar la idea de patrones una vez que todos tus test pasan al estado "green", recién ahí empezás a pensar en que patron se adecua a la solución implementada. En ese momento, quizás el momento de la piedra libre a tus cualidades de razonamiento ( la parte divertida ) dadas las situaciones de problemas que investigaste para plantear tus escenarios de test, entendés por que será mejor un command, que un strategy ó un state pattern. Por que claramente usarías una factory o un builder, ó por que recién ahora conviene un mediator en lugar de un Facade, como presupusiste.
Buscar ser un eficiente TDD developer te llevará sin duda a ser un mejor Pattern oriented developer. Pensar para que vas usar el auto , te lleva ver como lo diseñas. Pensar algo que sirve por default para todas las soluciones no solo te cierra posibles contextos en los cuales quedes desajustado, si no que te lleve a implementar complejidades innecesarias que solamente te lleven a test innecesarios; Esta es la situación donde los que "desacreditan" TDD tienen razón para protestar por la productividad. Si hacemos cosas de mas , claramente le robamos tiempo a las cosas que si son necesarias.
La economía de recursos no implica malos diseños , implica Mejores diseños, es por eso que resolver los problemas con las ideas y herramientas adecuadas depende mucho de como se implemente mas alla de saber, ahora comparando con el ajedrez, cómo mover las piezas.
jueves, 12 de febrero de 2015
Ejemplo de como funciona el Kill -3 (QUIT) para procesos Java
Esto me parecio interesante de compartir:
Dada esta clase Stopping.java ( meterlo todo en un unico archivo, más facil para probar este ejemplo.):
import java.util.Timer;
import java.util.TimerTask;
class CanStop extends Thread {
private volatile boolean stop = false;
private int counter = 0;
public void run() {
while (!stop && counter < 10000) {
System.out.println(counter++) ;
try{
Thread.sleep(1000);
} catch (Exception e){
System.out.println(e);
}
}
if (stop)
System.out.println("Detected stop");
}
public void requestStop() {
stop = true;
}
}
public class Stopping {
public static void main(String[] args) {
final CanStop stoppable = new CanStop();
stoppable.start();
try{
Thread.sleep(20000);
} catch (Exception e){
System.out.println(e);
}
new Timer(true).schedule(new TimerTask() {
public void run() {
System.out.println("Requesting stop");
stoppable.requestStop();
}
}, 350);
}
}
Uds si la ejecutan , contara hasta 20 y se detendrá ( javac Stopping.java para compilar y luego para ejecutar java Stopping ), de paso el ejemplo de como detener un hilo desde afuera.. de manera muuuy simple.
Ahora, a lo nuestro; en otra consola ( esto es en un unix , el contexto de la mayoría de procesos java )... mientras se ejecuta el proceso de Stopping, pueden hacer:
ps -fea | grep Stopping
Que tiro en mi caso? :
711670932 29342 28674 0 12:41PM ttys001 0:00.16 /usr/bin/java Stopping
les va a tirar el pid del Proceso y luego
kill -3 29342
y van a ver el dump del proceso corriendo..
0
1
2
3
4
5
6
7
8
9
10
2015-02-12 12:41:12
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.45-b08 mixed mode):
"Thread-0" prio=5 tid=0x00007fce5a005000 nid=0x4f03 waiting on condition [0x000000011beb5000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at CanStop.run(Stopping.java:11)
"Service Thread" daemon prio=5 tid=0x00007fce5a813800 nid=0x4b03 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=5 tid=0x00007fce5a813000 nid=0x4903 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=5 tid=0x00007fce59804800 nid=0x4703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=5 tid=0x00007fce5a800800 nid=0x4503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=5 tid=0x00007fce5a00a000 nid=0x3103 in Object.wait() [0x000000011b6f3000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007aaa85568> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000007aaa85568> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)
"Reference Handler" daemon prio=5 tid=0x00007fce5a007000 nid=0x2f03 in Object.wait() [0x000000011b5f0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007aaa850f0> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x00000007aaa850f0> (a java.lang.ref.Reference$Lock)
"main" prio=5 tid=0x00007fce5900c800 nid=0x1903 waiting on condition [0x000000010d366000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at Stopping.main(Stopping.java:28)
"VM Thread" prio=5 tid=0x00007fce5904d000 nid=0x2d03 runnable
"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007fce59018000 nid=0x2503 runnable
"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007fce59803000 nid=0x2703 runnable
"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007fce59803800 nid=0x2903 runnable
"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007fce59018800 nid=0x2b03 runnable
"VM Periodic Task Thread" prio=5 tid=0x00007fce59830000 nid=0x4d03 waiting on condition
JNI global references: 109
Heap
PSYoungGen total 76800K, used 2642K [0x00000007aaa80000, 0x00000007b0000000, 0x0000000800000000)
eden space 66048K, 4% used [0x00000007aaa80000,0x00000007aad14828,0x00000007aeb00000)
from space 10752K, 0% used [0x00000007af580000,0x00000007af580000,0x00000007b0000000)
to space 10752K, 0% used [0x00000007aeb00000,0x00000007aeb00000,0x00000007af580000)
ParOldGen total 174592K, used 0K [0x0000000700000000, 0x000000070aa80000, 0x00000007aaa80000)
object space 174592K, 0% used [0x0000000700000000,0x0000000700000000,0x000000070aa80000)
PSPermGen total 21504K, used 2551K [0x00000006fae00000, 0x00000006fc300000, 0x0000000700000000)
object space 21504K, 11% used [0x00000006fae00000,0x00000006fb07dcb0,0x00000006fc300000)
11
12
13
14
15
16
17
Interesante cuando uno esta probando procesos concurrentes en java..
Suscribirse a:
Comentarios (Atom)