Archivo de la etiqueta: robustez

Akka por ejemplos. Sobre supervisión, bus de eventos, …

Esta es la segunda entrega de Akka por ejemplos. La primera trató sobre cual es el funcionamiento de la cola de mensajes de un actor, que es un router y como se envían mensajes entre actores.

Ahora se tratarán temas como el control de fallos y la supervisión de actores, el bus de eventos de Akka y sobre los ‘Dead Letters’

Entrada anterior: Akka por ejemplos

Sin más vamos con los ejemplos.

Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures


Control de fallos: Supervisión y monitorización.

[Supervisión padre-hijo en Akka]

[Supervisión padre-hijo en Akka]

En Akka la robustez a fallos se basa en la supervisión de actores con jerarquía padre-hijo. El actor que delega tareas en los actores que crea es el que ‘supervisa‘ y decide que hacer cuando se produce un fallo en alguno de sus hijos.

Se crea así una jerarquía en forma de árbol en la que la que los actores padres supervisan a los actores hijos. El actor ‘user‘ de Akka será el padre de primera generación de actores que hayamos creado.

Esto es realmente lo que te da la robustez (‘resilence‘)  que un sistema reactivo necesita. Esta robustez se pierde cuando se intenta en vez de tener esta jerarquía, ir a un esquema con una mentalidad más tradicional de inyección de dependencias y se cae en la tentación de inyectar actores a otros actores.

Cuando un actor falla y se produce una excepción, su supervisor puede hacer, o bien reiniciar el actor, parar el actor, escalar la excepción o absorber la excepción y continuar con la ejecución.

El sistema de supervisión de Akka permite tener la posibilidad de diferente respuesta del supervisor dependiendo del tipo de excepción y si esta afecta a todos los actores supervisados o sólo al que ha fallado. Esto junto con lo anterior permite implementar fácilmente patrones,  por ejemplo de tipo ‘circuit breaker‘, si uno de los actores falla.

Akka tiene la posibilidad de establecer eventos o disparadores en el ciclo de vida de un actor. Por ejemplo antes de crearlo, antes y después de reiniciarlo y cuando se para.

Ademas del concepto de supervisión, en Akka existe el de monitorización. Cualquier actor, puede ‘monitorizar‘ a cualquier otro, lo haya creado o no. El primero obtiene un mensaje ‘Terminated‘ cuando el monitorizado ha terminado. Esto permite modificar su comportamiento o cambiar su estado. En los ejemplos siguientes el actor supervisor también hace de ‘monitor‘ de sus hijos.

Para poder mostrar con ejemplos como es el comportamiento de las diferentes estrategias a seguir, he creado en el proyecto dos actores: ActorNoTypedDummyCheckLifeCycle y ActorNoTypedLetItCrash.

ActorNoTypedDummyCheckLifeCycle se utiliza para comprobar los eventos que se disparan y por los ‘estados‘ que pasa un actor cuando es supervisado con diferentes estrategias. Concatena en un atributo ‘state‘ los diferentes pasos por los ‘hooks‘ del ciclo de vida de un actor:

  • Método ‘aroundPreStart‘: Primer evento que se dispara cuando se inicia un actor. Sólo se ejecuta cuando se inicia un actor por primera vez.
  • Método ‘preStart’: Se lanzan cuando se inicia un actor o después de que se haya reiniciado.
  • Método ‘aroundPreRestart’: Cuando un actor va a ser reiniciado, se dispara antes de parada el actor.
  • Método ‘preRestart‘: También se ejecuta antes de parar el actor cuando va a ser reiniciado. La llamada es después de la del método ‘aroundPreRestart
  • Método ‘postStop‘: Evento que se llama, o bien cuando se para el actor, o bien antes de reiniciarlo (en este último caso justo después de que se llame al método ‘preRestart‘)
  • Método ‘postRestart‘: Se lanza después de reiniciar el actor.
  • Método ‘aroundPostStop‘: Se realiza la llamada justo antes de parar definitivamente el actor.

El actor ActorNoTypedLetItCrash es el que creará y hará de supervisor de ActorNoTypedDummyCheckLifeCycle. En su constructor,  permite definir por parámetro la estrategia de supervisión. Su comportamiento será en de hacer de proxy en el envío de mensajes a  ActorNoTypedDummyCheckLifeCycle hasta que este el actor hijo se pare o cuando el mismo se haya reiniciado.

Para mostrar el comportamiento de las diferentes estrategias y cual es el ciclo de vida especifico de los actores (cuando se llama a los diferentes ‘hooks‘) he codificado en el proyecto los siguientes ejemplos.

Estrategia de supervisión por defecto

Test: ActorLetItCrashTestDefault.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestDefault test

Si se produce un excepción en un actor hijo, la estrategia por defecto en Akka es la de reiniciar el actor hijo, excepto si es un error irrecuperable:

  •  cuando se ha producido una excepción al inicializar el actor (ActorInitializationException)
  • cuando ya se había parado el actor(ActorKilledException)

Esta estrategia cobra sentido cuando se quiere mantener un sistema estable. La idea subyacente es que cuando se produce un error el sistema debería volver a un estado consistente y esto se consigue reiniciando el estado del actor.

En este ejemplo, los pasos son:

  1. Se envía un primer mensaje ‘state‘ al actor ActorNoTypedLetItCrash. Este hará el reenvío del mensaje al actor hijo (ActorNoTypedDummyCheckLifeCycle) que devolverá la concatenación de los diferentes métodos por los que ha pasado hasta ese momento.
  2. Después se envía un mensaje con una excepción para que el actor hijo provoque la excepción.
  3. Por último se vuelve a enviar un mensaje ‘state‘ para ver por los eventos que se ejecutan cuando se reinicia el actor.
  4. Finalmente para poder ver todo el flujo, se para el actor.

El ejemplo permite comprobar el flujo completo del paso de los diferentes eventos a lo largo de la vida del actor hijo. En este caso con la estrategia de supervisión por defecto, es este:

Se llama al constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPreRestart
     => Llamada a preRestart
      => Llamada a postStop
       => Llamada al constructor (Se vuelve a crear el actor)
        => Llamada a aroundPostRestart
         => Llamada a postRestart
          => Llamada a preStart
           => Llamada a aroundPostStop
            => Llamada a postStop

Estrategia de supervisión: Escalar la excepción

Test: ActorLetItCrashTestEscalate.java

Commando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestEscalate test


¿Qué ocurre cuando se elige una estrategia de supervisión de tipo ‘escalate‘? En este caso la excepción en el actor hijo provoca el error también en el actor supervisor. El comportamiento final depende entonces de la propia estrategia de supervisión de este último.

El ejemplo puede ayudar a verlo más claro. En este caso se configura el supervisor (ActorNoTypedLetItCrash) para que la estrategia de supervisión sea la de escalar la excepción. Cuando se provoca una excepción en el actor supervisado, el resultado es el mismo que si se hubiera producido en el supervisor.

El este caso el supervisor tiene la estrategia de supervisión por defecto, que lo reinicia, volviéndose a crear el actor hijo.

En el test se comprueba este hecho cuando se valida todo el ciclo de vida del actor hijo. Se arranca y después de la excepción, se para, para después volver a arrancar sin reinicio. Esto último provocado porque al reiniciarse actor supervisor, el hijo se para y se vuelve a crear:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop
      => Llamada al constructor (Se vuelve a crear el actor)
       => Llamada a aroundPreStart
        => Llamada a preStart
        => Llamada a aroundPostStop
         => Llamada a postStop

Estrategia de supervisión ‘resume’: ‘Absorber’ la excepción.

Test: ActorLetItCrashTestResume.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestResume test

Si el supervisor adopta una estrategia de ‘resume‘ si se produce un error la excepción no produce ni el reinicio, ni la parada del actor supervisado. Aunque se haya producido el error, sigue levantado a la espera de procesar nuevos mensajes.

El test ayuda a comprender este tipo de supervisión. Se comprueba que cuando se produce una excepción al procesar un mensaje, no se hace ninguna llamada a los métodos del ciclo de vida, ni tampoco se escala la excepción. El siguiente mensaje lo procesa correctamente.

El ciclo de vida del actor supervisado con este tipo de supervisión será:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Estrategia de supervisión ‘stop’: Parar el actor supervisado.

Test: ActorLetItCrashTestStop.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestStop test

En este caso, se para el actor supervisado cuando al procesar un mensaje ocurre una excepción.

En el ejemplo se fuerza esta situación. Si se provoca una excepción en el actor supervisado se comprueba que el actor no se vuelve a reiniciar. De hecho si se le vuelve a enviar un mensaje de estado, este se envía a la cola de ‘Dead Letters‘ porque la referencia al actor ya no apunta a un actor válido.

El ciclo de vida del actor es el siguiente:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Los mismos pasos que con la estrategia ‘resume‘. Pero en este caso no ha sido necesario parar el actor en el test porque ‘muere‘ después de provocarse la excepción.

Bus de eventos interno de Akka

Test: PublishSimpleSuscribeTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.PublishSimpleSubcribeTest test

Akka poseé un bus interno que permite el envío de mensajes siguiendo el patrón publicador-suscriptor. Un ‘publicador‘ envía un mensaje sin saber quien van a ser los receptores. Los actores que quieran recibir ese tipo de mensajes deberán suscribirse a esa publicación.

[Bus de eventos de Akka]El paradigma cambia. En vez de enviar un mensaje a un actor concreto, es decir, “(Por favor) haz esto”, cuando se publica un mensaje en el bus se está diciendo “(A quien pueda interesar) ha ocurrido esto

En este caso el ejemplo muestra un uso sencillo del bus de Akka para mostrar este patrón.

Se levantan dos actores suscriptores (del tipo ActorNoTypedLogEvent) que se suscribirán a mensajes de tipo Integer. La implementación de este actor es sencilla: registra los mensajes del tipo a los que está suscrito y si se le envía un mensaje ‘lastMessage‘ devolverá el último mensaje que ha registrado.

En el test después de levantar a los dos suscriptores se envía un mensaje al bus de Akka. Después se comprueba que el mensaje le ha llegado a ambos.

Dead letters

Test: DeadLettersTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.DeadLettersTest test

Un ‘dead letter‘ se produce cuando no se ha podido entregar un mensaje a un actor. Un caso típico es cuando el actor receptor del mensaje ya no existe. El ‘dead letter‘ contiene el mensaje enviado, la referencia al actor que lo envía y la del que lo iba a recibir.

Por defecto Akka informa en el log de la aplicación los dead letters que se producen (esto es configurable). También pública esta información a través del bus de eventos de Akka, lo que permite que una aplicación tenga la posibilidad de una gestión específica de estos mensajes perdidos.

En el ejemplo para poder provocar un dead letter se crea un actor del tipo ActorNoTypedDummy pararlo para a continuación enviarle un mensaje. Este mensaje ‘se pierde‘ y es recogido como ‘dead letter‘.

Por otra parte en el ejemplo se está utilizando un actor del tipo ActorNoTypedLogEvent configurado para que suscriba en el bus de eventos de Akka los mensajes del tipo DeadLetter.

Cuando se manda un mensaje de ‘lastMessage‘ al actor ActorNoTypedLogEvent este devolverá la información del mensaje perdido en forma de DeadLetter.

Como comprobación final del test se validará la información contenida en el objeto DeadLetter: el mensaje y la referencia al actor receptor.


Hasta aquí este segundo artículo de Akka por ejemplos. El próximo y último artículo de esta serie será sobre actores tipados.

Espero que os sirva.

M.E.

Pruebas de robustez y rendimiento, sobre cache y simple cache en PHP y más…

(más => simular concurrencia, modelo de actores, de “pull request”,…)

[Robustez y rendimiento]“Este artículo trata sobre la importancia de las pruebas de robustez y de rendimiento y su relación directa con la calidad del software, y lo importante que es medir y representar los datos en una gráfica.

Un caso práctico, un sistema de cache PHP simpe basado en almacenamiento en ficheros. En teoría lento ¿verdad? ¿pero lo has comprobado?”

Introducción, Cache…

Cachear no es que sea nuevo, pero si está de rabiosa actualidad. El cacheo es una técnica fundamental dentro de los paradigmas de escalabilidad y rendimiento que se están implementando en la actualidad. Sus ventajas son claras a la hora de evitar tráfico en los cuellos de botella de una arquitectura, típicamente la base de datos. Las arquitecturas con cache compartida (con sistemas como Memcached o a otro nivel Redis) y colas de mensajes pasan a ser “la nueva forma” de hacer las cosas.

Está presente también en las tendencias actuales de arquitecturas basadas en microservicios. Algunas siguen la máxima “cache everything” (“Cachea todo lo que se mueva..” 🙂 )

Y a otro nivel, también hay un debate abierto con la movilidad y en el que ha entrado de lleno Linus Torvalds (1). Defiende que añadir más procesamiento en paralelo (más cores a los procesadores de los móviles) no es la solución y que las caches grandes son eficientes.

El cache también tiene sus problemas intrínsecos complejos. Por ejemplo, la invalidez de los valores cacheados. Si no se hace correctamente se puede trabajar con datos ‘antiguos’ y perder información. Problema antiguo… Martin Fowler (2), ha hecho famosa la cita de Phil Karlton

“There are only two hard things in Computer Science: cache invalidation and naming things.”

El caso práctico, cache simple en PHP

El objetivo de este post no es tan ambicioso como para meterse de lleno en este problema. En su tiempo para el post “Dar valor a los tweets: Interés, difusión, audiencia,… trasteando con el API de Twitter” necesitaba una librería para cachear los resultados del api de Twitter. Me decanté la librería php-cache de Emilio Cobos, me pareció sencilla, fácil de utilizar y configurar y suficiente para lo que necesitaba. Desde entonces llevo usándola también en otros proyectos.

El almacenamiento en memoria es lo más rápido para una cache. Esto, que en Java es sencillo de implementar, basta con almacenar el valor en un atributo estático de una clase para que este accesible en todos los hilos de ejecución, en PHP es necesario usar extensiones externas al core de PHP o utilizar memoria compartida. Esto último honestamente no creo que sea lo más se adecue dentro de este contexto en donde lo que busqué es la máxima sencillez.

[Cache]La finalidad de la librería es tener un sistema de cache sencillo sin necesidad de instalación de extensiones como apc ni ni servicios como memcache. Tan sólo es necesario que el usuario del apache tenga permisos de escritura, cosa que es lo más común. Por esto es ideal para “alojamientos compartidos” de páginas web.

Su funcionamiento similar a otras librerías de este tipo. Está basada en la serialización de las variables, y su almacenaje en ficheros de texto. El código fuente es sencillo, ordenado y muy fácil de seguir.

Después de decirme a usarla y ver como funcionaba, me surgieron dos dudas. En su momento, en anteriores proyectos, tuve problemas de concurrencia en PHP cuando más de un proceso leía/escribía en el mismo fichero a la vez. Además que el acceso a cache tuviera acceso a disco «¿cuánto estaba penalizada la velocidad este motivo?»

Estas dos preguntas fueron la excusa para adentrarme en el mundo de las pruebas de rendimiento y de robustez. Otra pata importante dentro del desarrollo que aporta valor a la calidad del software. El resultado de todo esto está reflejado en lo que viene a continuación.

Adelanto que propuse unos cambios en el código y Emilio Cobos a tenido a bien aceptar mi ‘pull request‘, por lo tanto he pasado a ser un humilde, pero a la vez orgulloso contribuidor de php-cache.

Pruebas de robustez, concurrencia lectura/escritura de una clave de la cache

php-cache utiliza para cada clave de la cache un fichero donde almacena el valor «serializado«. Para probar la concurrencia cuando varios procesos leen/escriben en una misma clave de la cache diseñe dos test.

El primero de ellos, robustness-rw.test.php, lanza 10 procesos concurrentes, simulando 10 clientes ejecutando las mismas operaciones a la vez. Cada uno de ellos graba un valor en una clave de la cache y a continuación obtiene el valor de la misma clave de la cache. Estas dos operaciones las realiza cada proceso 50 veces (un total de 500 operaciones de escritura/lectura en total) cambiando cada vez el valor grabado de 3 posibles.

El valor obtenido de la cache tiene que ser igual a alguno de los tres valores posibles. Si es diferente o es nulo el valor se considera como invalido.

El segundo de los test de robustez, robustness-rw2.test.php es similar al anterior. En este caso además de guardar y obtener el valor se realiza una tercera operación de borrado de la clave de la cache. En este caso, el valor obtenido de la cache tiene que ser igual a alguno de los tres valores posibles o nulo. En cualquier otro caso se considera como inválido.

Los dos test están el directorio test repositorio principal de la librería ya que estaban incluidos en el ‘pull requestaceptado. En el README.md del directorio test está explicado más en profundidad lo que hacen y como se lanzan.

[Logo GitHub] Repositorio GitHub Cache.php

Simulando los clientes concurrentes, esquema basado en el modelo de actores

¿Cómo simular los clientes/peticiones concurrentes? Hay que tener en cuenta que el soporte multihilo no viene habilitado en una instalación tipo de PHP. El esquema que he seguido para simular la concurrencia he seguido en el paradigma de “modelo de actores”.

El script principal (actor principal) se encarga de lanzar los demás actores (procesos secundarios). En este caso son procesos PHP, en realidad una copia del mismo test que tiene un comportamiento diferente si “actúa” como actor secundario. Los secundarios se encargan cada uno de de hacer las 50 peticiones de escritura/lectura o escritura/lectura/borrado en una misma clave común.

Una vez lanzado los actores secundarios, el principal espera a que todos terminen para recoger los resultados y calcular la información estadística de los errores que se hayan podido producir.

Los mensajes entre el actor principal (el proceso) y el resto de actores (los procesos secundarios) los he montado utilizando también la librería php-cache.

Este es el flujo seguido:

[Concurrencia utlinzando modelo de actores]

  1. El proceso principal crea los actores pesándoles como parámetro una clave auxiliar de la cache (diferente para cada proceso) en la que escribirán el resultado. Los actores secundarios una vez hayan terminado su trabajo escriben en esa clave de la cache sus resultados.
  2. El proceso/actor principal se encarga de preguntar el estado de los actores lanzados, comprobando si existe la clave auxiliar en la cache que ha asignado a cada proceso.
  3. Una vez haya leído todas las claves auxiliares (todos los procesos hijos han terminado) calcula las estadísticas y muestra los resultados.

Los mensajes son inmutables, los actores secundarios sólo escriben en la clave asignada y el principal sólo lee las claves que ha asignado.

Resultado de los test de robustez y modificación del código

Al lanzar los test de robustez comprobé que en estos casos extremos de concurrencia la librería podía devolver la lectura de datos corruptos.

Hice una pequeña modificación en el código. Ahora siempre que se almacena un valor de una clave se escribe en un archivo temporal. Si la escritura es correcta, el fichero temporal se renombrará al definitivo utilizando la función rename de PHP. Esta función, es atómica si se realiza en el mismo sistema de ficheros. Este es el caso ya que se trabaja en el mismo directorio.

Volviendo a lanzar los test con este cambio ya no se obtienen datos corruptos y tanto la lectura se ejecutan sin errores.

Después de hacer un ‘fork‘ del repositorio y propuse los cambios lanzado un ‘pull request‘. Esta petición ha sido aceptada y los esta modificación está ya en el repositorio oficial de php-cache en GitHub

Pruebas de rendimiento. Mini benchmark

php-cache es una librería basada en lectura/escritura de ficheros, así que su velocidad depende de lo rápido que sea el acceso a disco y su velocidad de lectura.

En el repositorio de GitHub he subido un pequeño script (benchmark.test.php) que permite realizar medidas del acceso a un valor de la cache y cual sería el tiempo medio por respuesta.

Además como referencia se calcula el valor medio que se tarda en recuperar el objeto de su representación en cadena cuando sus datos están en memoria sin acceder a disco. Es decir, el valor teórico ideal que se alcanzaría si el coste de tiempo de acceso a disco fuera cero.

La información que devuelve el test es tanto el coste real como el teórico, número de peticiones realizadas, tiempo total y las estadísticas con datos sobre la media de milisegundos que ha tardado en hacer una petición y el cálculo de las peticiones por segundo.

… Dibujando y sacando conclusiones

Las conclusiones se pueden pueden ver de las siguientes gráficas:

En la primera (Gráfica 1) se muestra la información de los datos de las peticiones por segundo de los dos procesos, el real y el teórico. Si se observa con atención, para objetos de poco peso el  valor del  número de peticiones es  muy dispar entre las dos gráficas. Sin embargo, según va aumentando el peso del objeto guardado en cache, los dos valores se acercan hasta que casi el valor real es igual al ideal … Pero « ¿por qué puede pasar esto?»

Para poder poner un poco de luz en el asunto he creado la Gráfica 2. Se muestra la velocidad en MB por segundo en obtener el objeto. Una de las líneas es la velocidad de las peticiones reales, otra es como sería el calculo ideal y la línea amarilla es la velocidad que tarda en leer de fichero, es decir el tamaño del objeto dividido por la diferencia de los dos tiempos (real menos teórico).

Se puede observar, que mientras las velocidades de los procesos teórico y real tienden a ser constantes, la velocidad de lectura crece. En proporción, cuanto más grande es el objeto menos tarda en leerlo.

Con los objetos más grandes, al ser el proceso de lectura mucho más rápido que el proceso de «des-serialización«, el peso del primero pasa a ser despreciable en comparación con el segundo. Es la velocidad del proceso más lento (la «des-serialización«) la que marca la velocidad al obtener un valor de la cache.

La librería php-cache también tiene la posibilidad de guardar los datos en «crudo» sin serializar para almacenar cadenas, por ejemplo, para cachear la salida html directamente. Las siguientes gráficas (Gráficas 3 y 4) son los datos obteniendo un valor de la cache en «crudo«. Muestran mejor a la conclusión que quiero llegar.

En este caso la velocidad de lectura aumenta según lo hace el tamaño del objeto a leer y tiende a un máximo.

Y vuelvo a repetir «¿Por qué pasa esto?» Sorprendente, …o no tanto.  La respuesta es que el sistema operativo viene al rescate y entra en acción el buffer cache del disco (3).

El acceso a disco es mucho más lento que el acceso a memoria. El buffer cache del disco del sistema operativo sirve de colchón amortiguador de esta diferencia de velocidades de acceso. Mantiene en memoria (cache, …su cache) aquellos datos que leen la misma parte del disco varias veces durante periodos relativamente cortos de tiempo. Con respecto a este punto también he hecho pruebas realizando un sleep de dos segundos entre peticiones y la velocidad era la misma por lo que el los datos se conservaban en el buffer.

Recordar que este buffer no realiza cache de archivos, pero sí de bloques. Cuantos más bloques del fichero están en cache más rápido será la lectura y también añadir que el buffer de lectura de disco es transparente y lo gestiona el sistema operativo.

Resumiendo, cuanto mayor sea el tamaño del objeto a cachear y mayor sea el número de lecturas, php-cache pasa de ser un sistema cache basado en disco, «a priori» lento, para convertirse de «facto» en un sistema de cache basado en memoria y pasar a ser rápido. Y recordemos que estas circunstancias, objetos grandes y costosos de calcular con cierta carga de lectura, son precisamente una de las razones por las que se valora adoptar un sistema de cache.

Conclusiones

Siempre que se evite la optimización prematura evitando complicar innecesariamente el software  (optimizar es un vicio, cuando se empieza no se sabe como parar), las pruebas de robustez y de rendimiento pueden ser unas herramientas muy útiles.

Permiten valorar como se comportará el producto que estás desarrollando o como lo hará el que estás pensando en adoptar… Sabemos que en muy pocas ocasiones los errores que surgen en un entorno de producción son reproducibles,  pero que duda cabe que estas pruebas dan un plus de confianza en el software desarrollado. Y puede, como en este caso concreto, que te lleves una sorpresa para bien y se comporte mucho mejor de lo que en un principio podías esperar.

Otra conclusión, siempre que se mide se debe dibujar. Es importante reflejar los datos en un gráfico. Esto ayuda a vislumbrar una tendencia en los datos y obtener respuestas.

Y por último romper una lanza en favor de PHP. En algún sitio he leído que si «PHP fuera un arma se podía comparar con la manguera que pones al escape del coche para intentar suicidarte«…

No pienso así, PHP es un lenguaje al que tengo especial cariño y su simplicidad y potencia está demostrada con esta clase php-cache. Con unas pocas líneas tienes un sistema de cache muy competente y fiable que puedes usar sin problemas en proyectos sencillos y en el que puedes almacenar un montón de valores en la cache… tantos como espacio tengas en el disco duro.

Espero que os sirva.

M.E.

Referencias

  1.  [Linus: The whole «parallel computing is the future» is a bunch of crock] (highscalability.com)
  2. [TwoHardThings] (martinfowler.com)
  3. [El Buffer Cache] (tldp.org)