Geeks With Blogs

News
Séptimo Cielo Alfredo Delsors Blog

Supongamos que tenemos una aplicación Web utilizando una colección in-memory que cambia ocasionalmente pero que se utiliza muy a menudo. La colección se cargaría desde tablas Azure en el arranque de la aplicación, utilizando el evento Application_Start de global.asax, y se actualizaría cuando la aplicación actualizara la tabla, de forma que las consultas podrían realizarse sobre la colección en memoria.

Si vamos a desplegar la en Azure habrá que tener presente que se ejecutará más de una instancia de la aplicación en cada momento y en este caso el mecanismo descrito no sirve, las instancias no comparten una única colección.

Una opción para solucionar el problema sería utilizar Windows Azure AppFabric Caching para almacenar la colección. Cuando desde alguna instancia se modificara el valor de la colección, se actualizaría en la cache distribuida que comparten todas las instancias. Si las consultas van a ser muy frecuentes a lo mejor resulta que la factura que habremos de pagar para poder utilizar esta caché acaba siendo demasiado elevada, teniendo en cuenta que cada consulta contará como una transacción.

Pensando en que la comunicación entre los endpoints internos es gratis, una alternativa podría ser mantener la información en tablas de Azure, leer su contenido con el mismo evento anterior y comunicar los cambios que se produzcan en cada instancia al resto de instancias utilizando el endpoint interno HTTP disponible en los Web Roles de Azure.

Para hacerlo habría que seguir los siguientes pasos:

1.   Definir un endpoint interno HTTP en las propiedades del Web Role, por ejemplo InternalHttpEndpoint

 

2.   Añadir un nuevo servicio WCF al Web Role, por ejemplo NotificationService.svc

3.   Deshabilitar multiple site bindings en el web.config:

<serviceHostingEnvironment multipleSiteBindingsEnabled="false">

4.   Añadir un método en el nuevo servicio para recibir notificaciones desde las otras instancias del Rol.

namespace Service {

[ServiceContract]

public interface INotificationService {

    [OperationContract(IsOneWay = true)]

    void Notify(Information info);

}}

5.   Declarar una clase que herede de System.ServiceModel.Activation.ServiceHostFactory y sobreescribir el método CreateServiceHost para hospedar el endpoint interno.

public class InternalServiceFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var internalEndpointAddress = string.Format(
			"http://{0}/NotificationService.svc",
			RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["InternalHttpEndpoint"].IPEndpoint);

        ServiceHost host = new ServiceHost(
			typeof(NotificationService), 
			new Uri(internalEndpointAddress));

        BasicHttpBinding binding = new BasicHttpBinding(SecurityMode.None);

        host.AddServiceEndpoint(
			typeof(INotificationService), 
			binding,
			internalEndpointAddress);

        return host;
    }
}

Nota: se puede utilizar SecurityMode.None porque los endpoints internos son privados a las instancias del servicio, no son accesibles desde el exterior y por lo tanto completamente seguros.

6.   Editar el markup del servicio pulsando con el botón derecho del ratón sobre el fichero svc y seleccionando "View markup" para añadir la factoría anterior como la factoría que debe utilizarse para crear instancias del servicio.

<%@ ServiceHost Language="C#" Debug="true" Factory="Service.InternalServiceFactory" Service="Service.NotificationService" CodeBehind="NotificationService.svc.cs" %>

7.   Ahora se pueden notificar los cambios a otras instancias como sigue:

var current = RoleEnvironment.CurrentRoleInstance;

var endPoints = current.Role.Instances
                    .Where(instance => instance != current)
                    .Select(instance => instance.InstanceEndpoints["InternalHttpEndpoint"]);

foreach (var ep in endPoints)
{
    EndpointAddress address = new EndpointAddress(
		String.Format("http://{0}/NotificationService.svc",
		ep.IPEndpoint));

    BasicHttpBinding binding = new BasicHttpBinding(SecurityMode.None);

    var factory = new ChannelFactory<INotificationService>(binding);

    INotificationService instance = factory.CreateChannel(address);

    instance.Notify(changedinfo);
}

Si el número de consultas sobre la colección puede llegar a ser muy grande, el coste de implementación de esta aproximación puede resultar rentable.

Posted on Saturday, January 29, 2011 7:40 PM Azure | Back to top


Comments on this post: Como aprovechar los endpoints internos disponibles en los Web Roles de Azure?

# re: How to leverage the internal HTTP endpoint available on Azure web roles?
Requesting Gravatar...
Great!

But It won't work. There is a known issue with de load balancer that adds the 20000 port: http://social.msdn.microsoft.com/Forums/en/windowsazure/thread/fea38c47-cd6e-4e6a-a49d-aeab0f0dc686

This is really crap. BUT you can make it work ignoring the port:

EndpointAddress address = new EndpointAddress(
String.Format("http://{0}/NotificationService.svc", ep.IPEndpoint.Address));

Good luck
Left by Christian on Aug 10, 2011 2:08 PM

# re: How to leverage the internal HTTP endpoint available on Azure web roles?
Requesting Gravatar...
Internal endpoints are not load balanced...
Left by Alfredo on Aug 11, 2011 1:23 PM

Your comment:
 (will show your gravatar)
 


Copyright © Alfredo Delsors | Powered by: GeeksWithBlogs.net | Join free