HTTP Anycast : Répartition de charge et failover multisites

Submitted by renchap (non vérifié) on mar, 12/29/2009 - 11:49

Objectif

Réaliser une architecture sécurisée pour un service HTTP, avec les contraintes :

  • Multisites (deux ou plus)
  • Pas d'actif/passif (tous les sites doivent recevoir le traffic)
  • Géolocalisation (les visiteurs doivent arriver sur le site le plus "proche")
  • Pas de lien niveau 2 entre les sites
  • Réalisable avec de l'open source

Solutions possibles

Appliances de loadbalancing

Plusieurs solutions ont été étudiées. La première est l'utilisation d'appliances de loadbalancing, capables de failover et de répartition géographique. Ce genre de solutions est (généralement) très cher, et n'est pas forcément scalable. De plus, toutes ne gèrent pas le failover multisites sans lien L2 entre eux.

Keepalived / CARP

Une seconde solution, classique, est l'utilisation de Keepalived (ou CARP, ou Hearthbeat, ou ...). Ces solutions sont éprouvées et ne nécessitent aucun matériel spécifique, et peuvent être mises en place en utilisant uniquement des logiciels libres. Par contre, il est nécessaire que tous les sites géographiques soient sur le même lien niveau 2, ce qui n'est pas possible dans notre cas.

GeoDNS

Une solution couramment utilisée est le GeoDNS. Le principe est simple : quand une requête DNS arrive sur le serveur autoritaire de la zone, celui-ci géolocalise l'IP source de la requête, et renvoie l'IP du site géographique le plus proche. Cette méthode fonctionne relativement bien et est très répandue, mais souffre de deux défauts.
Premièrement, elle n'est pas précise. En effet, l'IP source de la requête DNS n'est que très rarement celle du client. Celui-ci utilise le plus souvent les serveurs DNS de son FAI, ou des serveurs DNS publics (type OpenDNS ou Google DNS). Ces serveurs peuvent être situés géographiquement loin de l'utilisateur, ou bien utiliser un cache mondial qui fausse totalement les informations de GeoDNS.
De plus, il n'est pas possible de faire du failover réactif avec ce système. Il n'est pas recommandé d'utiliser un Time-To-Live inférieur à 5 minutes, ce qui devient le temps minimal de réponse de notre système. De plus, certains resolver DNS ignorent le TTL, et peuvent mettre 48 heures à se mettre à jour.

Anycast

Une dernière solution est possible : l'anycast. Cette technique est principalement utilisée pour les DNS. En effet, comme une IP peut être annoncée par plusieurs machines, il n'est pas garantit que tous les paquets envoyés par un client arriveront sur la même machine. le DNS utilisant des petits paquets UDP (mode non connecté), cela ne pose pas de problème, une requête DNS n'étant la plupart du temps qu'un paquet émis, et un reçu. Par contre, pour l'HTTP, cela peut être beaucoup plus gênant. En effet, HTTP utilise le protocole TCP, qui est un protocole connecté. La connection TCP nécessite plusieurs paquets, qui doivent avoir une même machine source et destination.

Au final, c'est une solution basée sur Anycast qui va être utilisée, mais en essayant d'éviter les instabilités de connexion exposées ci dessus.

Principe

La solution mise en place se base sur le même principe que Anycast : le failover de l'IP de service (ip-a dans la suite) va se faire via le routage.
Par contre, afin de garantir une stabilité dans la machine qui reçoit la connexion, il ne va pas falloir que les différentes routes vers cette IP aient le même poids.
Note : par convention ici, la route choisie est celle ayant le poids le plus faible

Nous allons avoir deux routes pour ip-a :

  • via LB1, avec une priorité faible
  • via LB2, avec une priorité élevée

Ainsi, tous les paquets à destination de ip-a arriveront sur LB1. Si celui-ci n'est plus accessible, la route doit être supprimée (nous verrons comment par la suite), et tous les paquets à destination de cette IP seront routés (et pris en charge) par LB2.

Avec cette approche, nous perdons le loadbalancing entre les deux sites. Mais il est possible de le conserver en mettant en place une seconde IP pour le service HTTP, ip-b, qui a une route de priorité élevée vers LB1, et de priorité faible sur LB2. Ainsi, la route préférée sera celle vers LB2, et l'IP basculera vers LB1 en cas de problème sur LB2.

Il suffit ensuite de diriger les visiteurs vers ces deux IPs, en utilisant par exemple du Round Robin DNS. On peut également utiliser un serveur DNS autoritaire qui renvoie aléatoirement une des deux IPs lorsqu'il est interrogé. Ces IPs peuvent être mises en cache au niveau des resolvers sans problèmes, vu que les deux servent le même service (sauf si LB1 et LB2 sont down en même temps, évidement).

Cette approche permet de scaler assez facilement en taille. Il est possible d'ajouter facilement des loadbalancers. Si ceux-ci sont dans le même MAN, il faut rajouter une IP pour le service, la configurer sur tous les loadbalancers, et on se retrouve avec 3 routes pour une IP. Si l'on a une situation avec 2 sites sur un continent, et 2 sites sur l'autre, on peut faire avec deux IPs seulement : les deux IPs sont annoncées sur chaque continent, avec une configuration par continent identique à celle présentée au dessus. Si un site d'un continent tombe, l'autre site du continent prend le relais. Si les deux sites du continent tombent, les visiteurs vont arriver sur l'autre continent (fonctionnement moins optimal, mais le service est toujours présent). Par contre, il faut que BGP reconverge dans ce cas, ce qui peut ajouter un délai.

Il n'est pas possible d'effectuer une répartition de charge pondérée et précise entre les différents sites, la répartition se faisant au niveau DNS. Il est possible de le faire au niveau DNS (), mais cela ne sera pas toujours très précis : si une majorité des clients est situé derrière peu de resolvers, la répartition ne sera pas celle voulue.

Matériel

Cette partie est à adapter selon vos besoin, votre volumétrie et l'existant. Pour cet article, j'utilise :

  • Deux sites géographiques, accessibles via un interlan Layer 3 (routé)
  • Deux routeurs supportant le BGP. J'utilise des Cisco, mais un PC avec un Quagga suffit. Dans cet article, je considère que la configuration BGP est fonctionnelle, avec une session iBGP entre eux.
  • Sur chaque site géographique :
    • Un loadbalancer HTTP. J'utilise un serveur avec haproxy, mais le choix est libre. Si c'est un UNIX, cela simplifiera les choses par la suite
    • Un pool de serveurs HTTP

Un petit schéma (n'inclut pas les switchs, et les élements de redondance réseau) :

Suite en cours de rédaction

Fichier attachéTaille
schema_general.png24.28 Ko