Descargar

Análisis de disponibilidad de un Web

Enviado por [email protected]


    Cuando somos responsables de un Web empresarial, debemos cuidar el nivel de servicio que proporcionamos a nuestros clientes. Normalmente se da la circunstancia de que cuando se cae nuestro Web nos enteramos por una protesta de un cliente o un usuario de negocio.

    Hay veces que contratamos un Hosting y llegamos a un acuerdo de nivel de servicio (SLA). Más habitualmente de lo que me gustaría poder contar, estos niveles de servicio no se respetan.

    Debemos tener la capacidad de medir estos servicios por nuestros propios medios. Hace no mucho, os mostrábamos un tutorial sobre una herramienta profesional que cubre de sobra esta funcionalidad, llamada e-test (Rendimiento de aplicaciones Web).

    A mi personalmente me gusta tener la capacidad de verificar por mis propios medios (y desde mi casa con ADSL) si el sistema funciona bien o mal. Os recomiendo una herramienta llamada WebSupervisor, que puede cubrir esta funcionalidad.

    Si sabéis un poco de Java, es bastante sencillo construir un pequeño programa para este propósito… y con algún valor añadido.

    Vamos a empezar a hacerlo paso a paso. El objetivo es construir el esqueleto de lo que podrá ser una herramienta de monitorización y mostrar algunas notas para poder darle continuidad.

    Creación de la funcionalidad básica

    Creamos un nuevo proyecto en NetBeans 3.6

    Debemos ser consciente que el interfaz de usuario es lo menos importante a la hora de diseñar un programa. Debemos intentar acotar la funcionalidad y hacerla independiente de como sea invocada.

    public String EjecutarTarea() {

    try

    {

    // inicializamos el destino si es necesario

    if(destino == null)

    {

    destino = new URL("http://www.adictosaltrabajo.com/");

    }

    // abrimos la conexión al servidor

    HttpURLConnection enlace = (HttpURLConnection)destino.openConnection();

    String respuesta = " – Codigo: " + enlace.getResponseCode();

    //respuesta += recuperaContenido(enlace);

    return respuesta;

    }

    catch(Exception e)

    {

    return "Error " + e.getMessage() + "n";

    }

    }

    // esta función recupera el texto de la página

    String recuperaContenido(HttpURLConnection enlace)

    {

    try

    {

    String respuesta = "";

    BufferedReader in = new BufferedReader (new InputStreamReader(enlace.getInputStream()));

    String cadena = "";

    while (cadena != null)

    {

    cadena = in.readLine();

    if (cadena != null)

    {

    respuesta+=("n" + cadena);

    }

    }

    in.close();

    return respuesta;

    }

    catch(Exception e)

    {

    return "Error " + e.getMessage() + "n";

    }

    }

    Con la función anterior, tenemos la capacidad de conectarnos a una URL y recuperar el código de retorno, e incluso recuperar el contenido de la página (//respuesta += recuperaContenido(enlace);)

    El diseño inicial no es muy bueno así que tenedlo en cuenta en vuestros desarrollos (esto solo es un tutorial parcial) :

    • La URL esta fija y dentro del código
    • No se gestionan ni propagan excepciones

    Temporizar una función

    Java dispone de una clase para planificar la ejecución de una función de un modo periódico, sin bajar al detalle de los hilos (Threads) Timer

    public void Arrancar()

    {

    java.util.Timer timer = new java.util.Timer();

    // creamos una clase inline

    timer.scheduleAtFixedRate(new TimerTask() {

    public void run() {

    String resultado = EjecutarTarea();

    AddTexto("" + new Date().toString() + resultado );

    }

    }, retardo, periodo);

    }

    Creación del Interfaz de Usuario

    Usando las capacidades de NetBeans, vamos a crear un interfaz sencillo

    NetBeans es un entorno bastante intuitivo, aunque puede costar un poco cogerle el tacto…

    Como primera aproximación podemos obtener el siguiente código

    /*

    * Temporizador.java

    *

    * 1 Julio, 2004

    * El objetivo de este programa es comprobar el estado de una página Web

    *

    * Es un ejemplo parcial …

    */

    import java.util.*;

    import javax.swing.*;

    import java.net.*;

    import java.io.*;

    /**

    *

    * @author Roberto Canales

    */

    public class Temporizador extends javax.swing.JFrame {

    /** Creates new form Temporizador */

    public Temporizador() {

    initComponents();

    }

    /** This method is called from within the constructor to

    * initialize the form.

    * WARNING: Do NOT modify this code. The content of this method is

    * always regenerated by the Form Editor.

    */

    private void initComponents() {

    jScrollPane1 = new javax.swing.JScrollPane();

    jTextArea1 = new javax.swing.JTextArea();

    jMenuBar1 = new javax.swing.JMenuBar();

    jMenu1 = new javax.swing.JMenu();

    jMenuItem2 = new javax.swing.JMenuItem();

    jMenuItem1 = new javax.swing.JMenuItem();

    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

    setTitle("Ejemplo de Temporizador");

    addWindowListener(new java.awt.event.WindowAdapter() {

    public void windowClosing(java.awt.event.WindowEvent evt) {

    exitForm(evt);

    }

    });

    jTextArea1.setPreferredSize(new java.awt.Dimension(640, 480));

    jScrollPane1.setViewportView(jTextArea1);

    getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);

    jMenu1.setText("Menu");

    jMenu1.addActionListener(new java.awt.event.ActionListener() {

    public void actionPerformed(java.awt.event.ActionEvent evt) {

    jMenu1ActionPerformed(evt);

    }

    });

    jMenuItem2.setText("Arrancar");

    jMenuItem2.addActionListener(new java.awt.event.ActionListener() {

    public void actionPerformed(java.awt.event.ActionEvent evt) {

    jMenuItem2ActionPerformed(evt);

    }

    });

    jMenu1.add(jMenuItem2);

    jMenuItem1.setText("Salir");

    jMenuItem1.setToolTipText("Menu principal");

    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {

    public void actionPerformed(java.awt.event.ActionEvent evt) {

    jMenuItem1ActionPerformed(evt);

    }

    });

    jMenu1.add(jMenuItem1);

    jMenuBar1.add(jMenu1);

    setJMenuBar(jMenuBar1);

    pack();

    }

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {

    // TODO add your handling code here:

    Arrancar();

    }

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {

    dispose();

    }

    private void jMenu1ActionPerformed(java.awt.event.ActionEvent evt) {

    // TODO add your handling code here:

    }

    /** Exit the Application */

    private void exitForm(java.awt.event.WindowEvent evt) {

    System.exit(0);

    }

    /**

    * @param args the command line arguments

    */

    public static void main(String args[]) {

    new Temporizador().show();

    }

    // la función Arrancar simplemente crea un temporizador

    // y ejecuta una función periódicamente

    public void Arrancar()

    {

    jMenuItem2.setEnabled(false);

    java.util.Timer timer = new java.util.Timer();

    // creamos una clase inline

    timer.scheduleAtFixedRate(new TimerTask() {

    public void run() {

    String resultado = EjecutarTarea();

    AddTexto("" + new Date().toString() + resultado );

    }

    }, retardo, periodo);

    }

    // la tarea a ejecutar es independiente del interfaz de usuario

    public String EjecutarTarea() {

    try

    {

    // inicializamos el destino si es necesario

    if(destino == null)

    {

    destino = new URL("http://www.adictosaltrabajo.com/avisos");

    }

    // abrimos la conexión al servidor

    HttpURLConnection enlace = (HttpURLConnection)destino.openConnection();

    String respuesta = " – Codigo: " + enlace.getResponseCode();

    //respuesta += recuperaContenido(enlace);

    return respuesta;

    }

    catch(Exception e)

    {

    return "Error " + e.getMessage() + "n";

    }

    }

    // esta función recupera el texto de la página

    String recuperaContenido(HttpURLConnection enlace)

    {

    try

    {

    String respuesta = "";

    BufferedReader in = new BufferedReader (new InputStreamReader(enlace.getInputStream()));

    String cadena = "";

    while (cadena != null)

    {

    cadena = in.readLine();

    if (cadena != null)

    {

    respuesta+=("n" + cadena);

    }

    }

    in.close();

    return respuesta;

    }

    catch(Exception e)

    {

    return "Error " + e.getMessage() + "n";

    }

    }

    // añadimos texto al componente en pantalla

    public void AddTexto(java.lang.String nodo) {

    jTextArea1.append(nodo + "n");

    }

    // Variables declaration – do not modify

    private javax.swing.JMenu jMenu1;

    private javax.swing.JMenuBar jMenuBar1;

    private javax.swing.JMenuItem jMenuItem1;

    private javax.swing.JMenuItem jMenuItem2;

    private javax.swing.JScrollPane jScrollPane1;

    private javax.swing.JTextArea jTextArea1;

    // End of variables declaration

    // inicializamos las variables no gestionadas por el compilador NetBeans 3.6

    private URL destino = null;

    private int retardo = 0; // no esperar

    private int periodo = 2 * 60 * 1000; // ejecutar cada 5 minutos

    }

    Ejecución

    Si ejecutamos el programa, obtenemos la siguiente respuesta… Nuestro Hosting de www.adictosaltrabajo.com es bastante estable.

    Otros usos adicionales

    Si somos un poco hábiles, podemos determinar las dependencias de nuestro sistema Web a otros subsistemas y crear un pequeño JSP/PHP/ASP que sea capaz de probar si tenemos acceso a ellos:

    • LDAP
    • Base de Datos
    • Host transaccional
    • Servidor de Aplicaciones
    • Sistema remoto de ficheros
    • Middleware
    • etc…

    Podríamos también modificar nuestro programa para que, al encontrar un error en la página probada, recorriendo cada una de las rutinas que prueban cada subsistema individualmente, analizase quién lo está produciendo.

    De este modo, cuando se produzca un problema en producción, desde vuestra casa podréis prever errores (siempre y cuando lo que falle no sea el propio servidor Web).

    Con un sistema de estas características (que se puede desarrollar en día) podéis tanto medir la estabilidad del sistema como adelantaros a la llamada del usuario de negocio cabreado porque la aplicación, en medio de una demo, lleva media hora sin funcionar. Además, si cuando se produce un error, mandáis un email a una pasarela SMS, te enterarás sin tener que estar atento al correo.

    Otra mejora puede consistir en monitorizar al mismo tiempo un Web muy estable (como google) y solo considerar los datos como válidos cuando esté último de una respuesta correcta ….  ya que sería una pena que lo que fallase fuera nuestra configuración local ;-))

    • Enlace ADSL
    • Red Inalámbrica
    • Configuración TCP/IP
    • Desconexión de algún cable (que pasa muy habitualmente)

    Conclusiones

    Muchos sabréis que hay un montón de causas por las que fallan las aplicaciones y normalmente es por falta de procedimientos organizativos a la hora de operar sistemas:

    • Lagunas de memoria en programas (normalmente construidos por nosostros).
    • Cambios de contraseñas en un turno que se aplican al rea-rrancar en otro.
    • Caducidad de certificados digitales.
    • Modificaciones aparentemente inocuas del LDAP.
    • Llenado de los discos o espacio de tablas de base de datos.
    • Borrado accidental de ficheros/campos.
    • Falta de pruebas automáticas de regresión funcional
    • Y un largo etc …..

    Ampliando este ejemplo un poquito, las posibilidades son interesantes:

    • Obtener una gráfica de disponibilidad
    • Enviar un correo electrónico cuando el código de retorno la petición cambie
    • Analizar el contenido HTML para verificar que no cambia… o es sustituido (nos han jaqueado)
    • Asegurarnos que nuestras fuentes de contenido (sindicado o alimentado por autores) funcionan correctamente

    Determinar la disponibilidad, rendimiento y capacidad de los sistemas, requiere de práctica y técnica.

    Adquirir una herramienta puede ser muchas veces más interesante que construirla aunque puede ser un negocio rentable (o un buen proyecto de fin de carrera con salida comercial) para la demanda creciente de estos servicios …..

    Roberto Canales Mora

    www.adictosaltrabajo.com