Programa de Disponibilidad de un Web

0
23617

Análisis de disponibilidad de un Web

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("https://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("https://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 …..

Sobre el
Autor ..

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad