2015-07-22 1 views
0

J'ai écrit "app" que je souhaite distribuer aux clients en tant que service. La plus grande partie de la logique "app" se trouve du côté de la base de données (PostgreSQL) et sa vitesse/disponibilité dépend principalement du serveur de base de données. L'application peut être exposée en tant qu'API REST (node.js) qui interroge principalement la base de données pour certaines données, puis la renvoie au format JSON. Il devrait donc y avoir une instance de base de données distincte (serveur) pour chaque client afin de rendre les applications client "indépendantes". Lorsque le client achètera un plan, il "recevra" le serveur de base de données (qui ne lui est pas directement exposé) depuis le cloud (Amazon RDS, heroku PG ou autre).Architecture évolutive de Load Balancer et du service API REST constitué de nombreuses bases de données

Le problème est comment exposer l'API REST à chaque client. Normalement, il devrait y avoir un serveur Web distinct pour chaque client qui se connecterait à une base de données unique. Mais cela signifie que je devrais gérer N bases de données et N serveurs Web pour chaque client, en plus de mettre à l'échelle chaque serveur Web (horizontalement) pour les besoins des clients (pour gérer plus de demandes par seconde). Donc, mon idée est de créer un serveur web évolutif unique (comme l'application Heroku unique) qui gérera les demandes de tous les clients. Ainsi, le flux ressemblerait à ceci:

  1. client fait la demande à l'API REST (serveur web) avec son API_TOKEN
  2. L'une des instances de serveur web (serveur web est mis à l'échelle) reçoit cette demande.
  3. L'adresse de base de données du client/les informations d'identification sont "révélées" sur la base de API_TOKEN
  4. Le serveur Web demande à la base de données du client, reçoit le résultat et renvoie les données.

Le problème est que les connexions de base de données doivent être regroupées sur des instances de serveur Web (pour le rendre plus rapide). Lorsqu'il y aura 1000 clients, il sera alors possible que l'instance de serveur Web unique ait des connexions de base de données x * 1000 ouvertes, où x est le nombre de requêtes parallèles par client. D'autre part, si je change de serveur web, le client unique peut frapper par exemple i1 puis i2 puis i3 puis i4 (où iX est l'instance de serveur web sélectionnée par l'équilibreur de charge). Il ne sera pas efficace car il va "ouvrir" le pool de connexion à la même base de données sur 4 instances de serveur Web différentes. Si ces 4 requêtes suivantes ne touchent que i1, elles peuvent tirer parti du pool de connexions qui serait "ouvert" lors de la première requête (et les requêtes suivantes utiliseraient une connexion déjà ouverte).

J'ai deux questions:

  1. Est-ce une bonne idée d'architecture? Peut-être existe-t-il d'autres approches/services standards pour atteindre mon objectif? Est-il possible de configurer l'équilibreur de charge pour le rendre si intelligent qu'il pourrait transmettre certaines demandes du même client à la même instance de serveur Web (pour profiter du pool de connexions de base de données sur cette instance) tout en maintenant toutes les demandes distribuées dans toutes les instances, aussi uniformément que possible (Par exemple, s'il y avait 10 clients c1, c2, c3, c4 ... et 4 serveurs Web instances w1, w2, w3, w4 et que chaque client faisait des requêtes x, il pouvait transférer c1 | c2 à w1, c3 | c4 à w2, c5 | c6 | c7 à w3 et c8 | c9 | c10 à w4)? Quel équilibreur de charge (je connais HAPROXY, NGINX et certains Amazon Elastic Load Blanacer).

Répondre

1

Il y a une option pour nginx d'avoir un équilibrage de charge d'envoyer un client à serveur Web basé sur IP: http://nginx.org/en/docs/http/load_balancing.html#nginx_load_balancing_with_ip_hash, donc il semble liek ce que vous voulez pour 2).

Et il y a des discussions serveral sur la base de données par client à SO:

What are the advantages of using a single database for EACH client?

https://serverfault.com/questions/107731/one-database-vs-multiple-databases

+0

Pour 2) hachage ip est pas une option - j'identifier les clients par leur api_key/CLIENT_ID uniques passé dans un en-tête ou une chaîne de requête par exemple ('POST/some/rest/method? clientId = 1234'). Ce que je cherche, c'est quelque chose comme l'équilibrage dynamique de la charge pondérée. Par exemple, si le client avec l'ID 1234 fait la première requête et qu'il est renvoyé à l'instance i1, le poids de ce client (1234) par exemple i1 devrait être augmenté pour encourager l'équilibreur de charge à transmettre également les requêtes suivantes à i1. Bien sûr, si i1 est "épuisé" de connexions alors le client 1234 devrait être transféré à l'instance suivante (moins conns?) – user606521

+0

@ user606521 Si vous voulez juste équilibrer les clients entre les serveurs, quelle est la différence entre utiliser client_id et ip_address pour cela? Vous ne devriez pas utiliser ip comme une clé pour vous connecter à votre système, vous l'utilisez simplement pour fournir plus ou moins de distribution aléatoire des clients entre les serveurs. – dbf

+0

Mais l'API REST sera exposée à d'autres utilisateurs (clients clients), donc il y aura peut-être 1000 requêtes en même temps provenant d'IP différentes. Je pense aussi juste à créer un sous-domaine unique pour un client (ie client1234.myservice.com) - peut-être que certains équilibreurs de charge peuvent utiliser ces informations? – user606521