Wow, c'est une question simple, à laquelle un grand nombre de réponses possibles. La partie la plus explicite de votre question demande s'il est plus évolutif de s’interfacer directement avec votre base de données ou via un service Web. Cette réponse est simple: interrogez directement la base de données. Le fait de passer par le service Web ajoute beaucoup de temps de latence, ce qui est totalement inutile pour le code fonctionnant derrière un pare-feu (dans l’ensemble). Un service Web, par exemple, nécessite un composant pour recevoir une demande, la désérialiser, interroger la base de données, sérialiser une réponse et la renvoyer. Donc, si votre code fonctionne entièrement derrière un pare-feu, évitez les problèmes et interrogez directement la base de données.
Rendre un site Web évolutif va toutefois bien au-delà de la question que vous avez posée initialement. Alors pardonnez-moi si je suis sur une tangente ici, mais j'ai pensé que cela pourrait être utile étant donné que vous avez mentionné Facebook en particulier.
Je vous recommanderais de lire le travail et les outils construits par Brad Fitzpatrick (fondateur de LiveJournal et maintenant chez Google). Lorsque j'ai travaillé avec lui à Six Apart, voici certaines des choses que j'ai apprises de lui et de l'architecture de LiveJournal qui l'a rendu si évolutif.
Utilisez des tables de base de données étroites plutôt que larges . Ce qui était fascinant, c’était d’apprendre ce qui motivait cette architecture, qui créait un système facile et rapide à utiliser.mis à niveau. Si vous utilisez des tables étendues, ou des tables pour lesquelles chaque champ ou propriété est une colonne de la table, le moment venu de mettre à niveau le schéma de base de données, par exemple en ajoutant une nouvelle colonne, le système devra alors verrouiller la table pendant que le schéma le changement est mis en œuvre. En cas de fonctionnement à grande échelle, cela signifierait qu'une simple modification du schéma de la base de données pourrait entraîner une panne importante de la base de données. Ce qui craint évidemment. D'autre part, une table étroite stocke simplement chaque propriété individuelle associée à un objet sous la forme d'une seule ligne dans la base de données. Par conséquent, lorsque vous souhaitez ajouter une nouvelle colonne à la base de données, il vous suffit d'insérer des enregistrements dans une table, ce qui est une opération non verrouillable. Ok, c’est un peu d’arrière-plan. Voyons comment ce modèle se traduit dans un système fonctionnel tel que LiveJournal.
Supposons que vous souhaitiez charger les 10 dernières entrées de journal sur le blog d'une personne et supposons que chaque entrée de journal possède dix propriétés. Dans une disposition de table large classique, chaque propriété serait corrélée à une colonne sur une table. Un utilisateur interroge ensuite la table une fois pour récupérer toutes les données dont il a besoin. La requête renvoie 10 lignes et chaque ligne contient toutes les données nécessaires (par exemple, les entrées SELECT * FROM ORDER BY date LIMIT 10). Dans une disposition de table étroite, les choses sont toutefois légèrement différentes. Dans cet exemple, il y a en fait deux tables: la première table (la table A) stocke les critères simples que l'on voudrait rechercher, par exemple l'id de l'entrée, l'id de l'auteur, la date de l'entrée, etc. Une seconde table (table B) stocke ensuite toutes les propriétés associées à une entrée. Cette deuxième table a trois colonnes: entry_id, key et value. Pour chaque ligne de la table A, il y aurait 10 lignes dans la table B (une ligne pour chaque propriété). Par conséquent, pour extraire et afficher les dix dernières entrées, il vous faudrait 11 requêtes. La première requête vous donne la liste des ID d'entrées, puis les dix requêtes suivantes extraient les propriétés associées à chacune des entrées renvoyées dans la première requête.
"Sainte moly!" vous dites, "comment sur Terre peut-il être plus évolutif?!" C'est totalement contre-intuitif, n'est-ce pas? Dans le premier scénario, nous avions juste une requête de base de données, mais dans la deuxième solution "plus évolutive", nous avons 11 requêtes de base de données. Ça n'a aucun sens. La réponse à cette question repose entièrement sur le point suivant.
Utilisez Memcache généreusement. Au cas où vous ne le sauriez pas, memcache est un système de mise en cache réseau distribué, sans état, à faible latence. Il est utilisé par Facebook, Google, Yahoo et pratiquement tous les sites Web populaires et évolutifs de la planète. Brad Fitzpatrick l'a inventé en partie pour aider à compenser la surcharge de la base de données inhérente à la conception d'une base de données à tables étroites. Jetons un coup d'oeil au même exemple que discuté dans # 1 ci-dessus, mais cette fois, introduisons memcache.
Commençons lorsqu'un utilisateur visite pour la première fois une page et que rien ne se trouve dans le cache. Vous commencez par interroger la table A qui renvoie les identifiants des 10 entrées que vous souhaitez afficher sur la page. Pour chacune de ces entrées, vous interrogez ensuite la base de données pour récupérer les propriétés associées à cette entrée, puis l'utilisation de ces propriétés constitue un objet avec lequel votre code peut s'interfacer (par exemple, un objet). Vous cachez ensuite cet objet (ou une forme sérialisée de cet objet) dans memcache.
La deuxième fois que quelqu'un charge la même page, vous commencez de la même manière: en interrogeant le tableau A pour connaître la liste des ID d'entrée que vous souhaitez afficher. Pour chaque entrée, vous allez d'abord dans memcache et dites: "avez-vous l'entrée #X dans le cache?" Si oui, alors memcache vous renvoie l'objet d'entrée. Sinon, vous devez interroger à nouveau la base de données pour en extraire les propriétés, constituer l'objet et le cacher dans memcache. La plupart du temps, la deuxième fois que quelqu'un visite la même page, il n'y a qu'une requête dans la base de données. Toutes les autres données sont ensuite extraites directement de memcache.
En pratique, ce qui a fini par se produire dans LiveJournal est que la plupart des données du système, en particulier les moins volatiles, ont été mises en cache dans memcache et que les requêtes supplémentaires de la base de données nécessaires à la prise en charge du schéma de table étroit ont été complètement compensées.
Cette conception a fait résoudre le problème lié à l' assemblage d' une liste des postes associés à tous vos amis dans un ruisseau, ou « mur » beaucoup, beaucoup plus facile.
Ensuite, envisagez de partitionner votre base de données. Le modèle présenté ci-dessus fait apparaître un autre problème: vos tables étroites auront tendance à être très grandes / longues. Et plus ces tables ont de lignes, plus les autres tâches administratives deviennent difficiles. Pour compenser cela, il peut être judicieux de gérer la taille de vos tables en les partitionnant de façon à ce que les clusters d'utilisateurs soient desservis par une base de données et qu'un autre groupe d'utilisateurs soit desservi par une base de données distincte. Cela répartit la charge sur la base de données et optimise l'efficacité des requêtes.
Enfin, vous avez besoin d'index géniaux. La rapidité de vos requêtes dépendra en grande partie de la qualité de l'indexation des tables de votre base de données. Je ne passerai pas trop de temps à discuter de ce qu'est un index, sauf à dire que c'est un peu comme un système de catalogue de cartes géant qui permet de trouver plus efficacement des aiguilles dans une botte de foin. Si vous utilisez mysql, je vous recommande d'activer le journal de requête lent pour surveiller les requêtes dont le traitement prend beaucoup de temps. Lorsqu'une requête apparaît sur votre radar (par exemple parce qu'elle est lente), déterminez quel index vous devez ajouter au tableau pour l'accélérer.
"Merci pour tout ce bon arrière-plan, mais bon Dieu, c'est beaucoup de code que je vais devoir écrire."
Pas nécessairement. De nombreuses bibliothèques ont été écrites pour faciliter l’interface avec memcache. Encore d'autres bibliothèques ont codifié le processus complet décrit ci-dessus; Data :: ObjectDriver in Perl est une telle bibliothèque. Pour les autres langues, vous devrez faire vos propres recherches.
J'espère que vous avez trouvé cette réponse utile. Ce que j’ai constaté le plus souvent, c’est que l’évolutivité d’un système dépend souvent de moins en moins du code, et de plus en plus d’une stratégie / conception technique saine de stockage et de gestion des données.