La semaine dernière au CHAR(10) conférence, nous avons eu un atelier sur "Cloud Databases". Pour le dire simplement :que faire lorsque les exigences du cas d'utilisation dépassent les ressources disponibles dans le serveur de base de données.
C'était un sujet principal de toute la conférence, et plusieurs solutions ont été illustrées au cours de la journée. Un thème commun a été qu'aucune solution ne convient à tous les cas d'utilisation et que chaque solution a son coût; vous devez donc choisir la solution que votre cas d'utilisation peut vous permettre.
Un autre point commun (bien qu'implicite) a été l'accent mis sur les solutions "de haut niveau", c'est-à-dire :connecter plusieurs serveurs de base de données à un niveau supérieur pour émuler un seul serveur avec des ressources plus importantes.
Un avantage évident est que vous n'avez pas besoin de modifier le code PostgreSQL bien examiné ; un inconvénient est qu'en utilisant plusieurs serveurs de base de données avec leurs chronologies indépendantes, vous perdez certaines propriétés utiles. Deux exemples :la perte partielle de la sémantique transactionnelle génère des conflits; la pré-analyse de chaque requête en dehors de la base de données introduit des limitations sur les requêtes acceptées.
La discussion était assez intéressante, et lorsque Dimitri Fontaine a mentionné les tablespaces distants, j'ai commencé à m'interroger sur une idée connexe mais distincte, à savoir :si une approche de niveau inférieur au problème de la mise en commun des ressources serait vraiment irréalisable. Avant que je puisse élaborer sur les détails, l'atelier s'est terminé, et je n'ai pu qu'esquisser l'idée à certaines des personnes qui se trouvaient autour du tableau blanc (parmi lesquelles Gabriele Bartolini, Nic Ferrier, Marko Kreen, Hannu Krosing, Greg Smith) ainsi que les bases questions "est-ce que cela semble faisable?" et "est-ce que cela ressemble à quelque chose que vous connaissez déjà ?".
Un bref croquis :une pile d'applications peut être représentée de cette manière
(application) --> (connection) --> (db server) --> (resources)
où les ressources utilisées par la base de données incluent le stockage, la RAM et les processeurs. Le but est de permettre à l'application de commander plus de ressources afin d'augmenter la capacité et la vitesse. Les applications "astucieuses" qui gèrent plusieurs bases de données peuvent être représentées comme
(application) --> (connection) --> (db server) --> (resources) | +---------> (connection) --> (db server) --> (resources)
tandis que les solutions de "mise en commun des connexions" peuvent être représentées comme
(application) --> (connection) --> (db server) --> (resources) | +---------> (db server) --> (resources)
par solutions "de niveau inférieur", je veux dire quelque chose comme
(application) --> (connection) --> (db server) --> (resources) | +---------> (resources)
qui pourrait ressembler à quelque chose de familier, mais ce n'est pas ce que je propose ici. Pour expliquer la différence, je peux augmenter le détail et écrire
(resources) = (virtual resources) --> (physical resources)
pour représenter le fait qu'au niveau le plus bas, vous pouvez avoir une correspondance non triviale entre les objets physiques et les objets virtuels. Par exemple, le stockage SAN ou la répartition RAID peuvent fournir des disques virtuels plus grands en réunissant des disques physiques plus petits. De tels cas pourraient être décrits comme
(application) --> (connection) --> (db server) --> (virt.res.) --> (ph.res.) | +--------> (ph.res.)
Ma proposition est de mutualiser les ressources au niveau du serveur de base de données niveau, afin que nous puissions avoir une "virtualisation" plus efficace en utilisant la connaissance des cas d'utilisation spécifiques pour chaque ressource (CPU, RAM, disque), et en même temps nous pouvons éviter la plupart des difficultés du paradigme transactionnel. L'image serait :
(application) --> (connection) --> (db server) --> (virt.res.) --> (ph.res.) | +--------> (virt.res.) --> (ph.res.)
L'avantage est que nous n'avons pas besoin de gérer tous les cas d'utilisation possibles pour chaque ressource virtuelle; nous devons juste gérer (et optimiser) les cas d'utilisation qui sont réellement nécessaires à PostgreSQL. Par exemple :les WAL doivent toujours être écrits dans un stockage local "non virtualisé", le bgwriter accédera aux ressources locales et distantes (RAM et disque), etc.
Quelques derniers mots sur la fiabilité. Pour fonctionner correctement, l'ensemble du système a besoin de chaque sous-système; les pannes partielles ne sont pas gérées, car cette architecture n'est pas redondante. C'est un système distribué, mais non partagé. Si cette architecture pouvait fournir une évolutivité simple et bon marché via un serveur de base de données virtuel qui est fonctionnellement équivalent à un serveur physique avec des ressources plus importantes, alors une haute disponibilité pourrait être obtenue de manière standard en configurant deux serveurs virtuels identiques dans une configuration Hot Standby.
La qualité du réseau a un impact important sur les performances globales ; cette conception ne peut être utile que si vous disposez d'un ensemble de machines sur le même réseau local, non seulement pour des raisons de vitesse, mais également parce qu'une défaillance du réseau serait en fait une défaillance du système. Même avec ces restrictions, je pense que cette option serait très utile.
Ceci n'est encore qu'un croquis, à utiliser comme référence pour une discussion ultérieure. Prochaines étapes possibles :
- faire une liste détaillée des cas d'utilisation des ressources
- pour décider quelles technologies peuvent être les plus utiles dans chaque cas d'utilisation
- pour estimer les coûts réels de performance/développement