Sur un VPS, les bases de données ne tombent pas en panne bruyamment. Elles cassent la tirelire. D’abord c’est « le site semble lent », puis « il nous faut une instance plus grosse », et enfin quelqu’un découvre en silence que vous payiez pour de la RAM que votre base ne savait pas utiliser efficacement et pour des IOPS que vous n’avez jamais testés.
Voici la réalité du VPS : voisins bruyants, crédits de burst, latence de stockage incohérente et plafond budgétaire strict. Dans ce monde, « vitesse par euro dépensé » n’est pas une capture d’écran de benchmark. C’est la capacité à garder la latence p95 prévisible pendant que votre directeur financier vous tient en laisse.
Ce que « vitesse par euro dépensé » signifie réellement sur un VPS
On parle de « performance » comme si c’était un chiffre unique. Sur un VPS, c’est un ensemble d’arbitrages et de modes de défaillance. Si vous voulez du meilleur rapport vitesse/prix, vous devez définir quel type de « vitesse » vous achetez :
- Latence prévisible (p95/p99), pas seulement le débit moyen.
- Efficacité par vCPU quand le CPU est médiocre et partagé.
- Amplification d’écriture et comportement fsync quand le stockage est le facteur limitant.
- Charge opérationnelle : à quelle fréquence vous réveillez quelqu’un parce que la maintenance a pris du retard.
MariaDB et PostgreSQL peuvent tous deux être rapides. La différence est dans leur comportement quand le VPS est médiocre. PostgreSQL a tendance à être plus transparent sur le travail nécessaire (visibilité, VACUUM, WAL). MariaDB/InnoDB peut être étonnamment indulgent pour des charges OLTP majoritairement en lecture, mais il peut aussi cacher des problèmes jusqu’au jour où ça casse.
La réponse courte et tranchée (avec réserves)
Si vous êtes sur un VPS modeste et que vous voulez maximiser le rapport vitesse/prix pour un SaaS OLTP typique (beaucoup de petites lectures/écritures, jointures simples, nombreuses sessions concurrentes), PostgreSQL l’emporte généralement sur le long terme parce qu’il reste cohérent sous des charges désordonnées et fournit de meilleurs outils pour diagnostiquer et contrôler le système.
Si votre charge est majoritairement en lecture, schéma simple, et que vous avez besoin de bonne performance avec peu de réglages, MariaDB peut coûter moins cher sur du petit matériel — surtout quand la majorité des données chaudes tiennent dans le InnoDB buffer pool et qu’il n’y a pas forte contention d’écriture.
La réserve importante : chez de nombreux fournisseurs VPS, la variabilité de la latence du stockage domine. Dans ce cas, la « base de données la plus rapide » est celle que vous pouvez configurer pour éviter les blocages synchrones sans sacrifier l’intégrité. PostgreSQL a des valeurs par défaut orientées intégrité ; MariaDB peut être réglé pour devenir terriblement rapide en relâchant la durabilité, ce qui peut être acceptable — jusqu’au jour où ce ne l’est plus.
Règle empirique : si vous misez l’avenir de l’entreprise sur une base de données « sans histoire », choisissez PostgreSQL. Si vous misez sur l’optimisation des coûts et que vos exigences de durabilité sont négociables, MariaDB peut être la voiture de course moins chère.
Blague #1 : Un VPS, c’est comme un espace de coworking : le café est correct, le Wi‑Fi est « partagé », et quelqu’un exécute toujours un mineur crypto deux bureaux plus loin.
Faits et histoire qui influencent encore vos réglages
Ce ne sont pas des faits de trivialités. Ils expliquent pourquoi certains réglages existent, pourquoi les valeurs par défaut semblent conservatrices, et pourquoi les migrations ressemblent parfois à un déménagement pendant un ouragan.
- Le MVCC de PostgreSQL (contrôle de concurrence multi‑version) est central depuis les années 1990. C’est la raison pour laquelle les lectures ne bloquent pas les écritures, et pourquoi VACUUM est une vraie préoccupation opérationnelle.
- InnoDB est devenu le moteur par défaut de MySQL à la fin des années 2000 parce qu’il apportait transactions, verrouillage au niveau ligne et récupération après crash nécessaires en production.
- MariaDB a été forké de MySQL après l’acquisition de Sun par Oracle. Cet événement explique pourquoi le « remplacement drop‑in » a été un argument commercial et pourquoi certaines incompatibilités persistent.
- La réplication PostgreSQL a mûri autour du WAL (write‑ahead log). L’histoire de la réplication est liée au WAL, fsync et réglages de checkpoint — essentiels au « rapport vitesse/prix » sur des disques lents.
- Le query cache de MySQL a été retiré (et la situation de MariaDB varie selon la version). Cette histoire explique pourquoi vous verrez des conseils anciens qui sont désormais nuisibles à la concurrence.
- Le planificateur de PostgreSQL privilégie la justesse plutôt que des « astuces ingénieuses ». Il n’aura pas toujours le plan le plus rapide, mais il est explicable, et ça compte à 3 h du matin.
- Le doublewrite buffer d’InnoDB existe parce que des écritures partielles de page arrivent. Sur un stockage VPS instable, cette protection peut vous sauver — au prix d’un surcoût d’écriture.
- PostgreSQL a intégré les extensions (comme pg_stat_statements) comme outils opérationnels de première classe. Cela change considérablement l’expérience de débogage quotidienne.
Où les VPS nuisent aux bases de données (et pourquoi cela change le choix)
1) Le stockage est le percepteur
Sur un VPS, vous pouvez acheter plus de vCPU et plus de RAM, et la base de données restera bloquée sur un fsync. Le point n’est pas « SSD vs HDD ». Le point est la latence tail : quelques syncs lents par seconde peuvent ruiner votre p99. PostgreSQL et MariaDB reposent tous deux sur des journaux d’écriture (WAL / redo logs). Au premier accroc du périphérique de logs, votre base devient un système de mise en file avec des sentiments.
2) Le « steal » CPU existe
La virtualisation peut voler des cycles CPU (littéralement exposés comme steal time). Si votre instance est bon marché, les threads de la base peuvent s’exécuter par à-coups. Cela pénalise PostgreSQL quand vous avez trop de connexions actives et beaucoup de context switches. Ça pénalise MariaDB quand les threads de purge/flush ne suivent pas et que des pages sales s’accumulent.
3) La mémoire est à la fois de l’or et un piège
La RAM est le multiplicateur de performance le moins cher — jusqu’à ce que vous la surengagiez. PostgreSQL utilise de la mémoire par connexion pour les tris/hachages ; MariaDB utilise aussi des buffers par thread, mais le buffer pool d’InnoDB est le levier principal. Sur de petits VPS, un mauvais réglage mémoire peut déclencher du swap, et alors vous mesurez le sous‑système VM Linux, pas la base.
4) La gigue réseau fausse la vitesse perçue
Beaucoup de rapports « base lente » sont en réalité une variance réseau entre l’app et la base. PostgreSQL et MariaDB réagissent de façon similaire : la requête est rapide ; la requête n’est pas. Si votre app et votre DB ne sont pas co‑localisées, « vitesse par euro » devient « latence par regret ».
MariaDB sur un VPS : où il excelle
Quand MariaDB gagne sur le coût
- OLTP majoritairement en lecture avec beaucoup de petites recherches point (clé primaire / index).
- Schémas simples où vous n’utilisez pas de fonctionnalités SQL complexes.
- Équipes avec habitude MySQL qui peuvent l’exploiter sans réglages « créatifs ».
- Charges avec motifs d’accès prévisibles où le buffer pool garde les pages chaudes en mémoire.
Les réglages qui importent (et pourquoi)
Sur un VPS, la performance MariaDB vit et meurt avec InnoDB :
- innodb_buffer_pool_size : faites‑le suffisamment grand pour contenir votre working set chaud. S’il est trop petit, vous payez des IOPS de lectures aléatoires. S’il est trop grand, le noyau commence à reprendre agressivement et vous obtenez des blocages.
- innodb_flush_log_at_trx_commit : la valeur par défaut est la plus sûre (1). L’abaisser (2 ou 0) achète de la vitesse en acceptant une perte de données en cas de crash. Ce n’est pas une optimisation gratuite, c’est une décision business.
- innodb_log_file_size / innodb_redo_log_capacity : des logs plus gros réduisent la pression de checkpoint et lissent les écritures. Trop gros rallonge le temps de recovery ; trop petit provoque des checkpoints fréquents et tape sur le stockage.
- innodb_io_capacity : indiquer à InnoDB ce que votre stockage peut réellement faire évite qu’il soit soit paresseux soit frénétique.
Où MariaDB peut vous faire perdre de l’argent en silence
MariaDB peut sembler rapide pendant qu’il accumule de la dette : pages sales qui s’accumulent, retard de purge, réplication en retard « acceptable » jusqu’à un failover, ou une table chaude qui devient un festival de mutex. Vous ne le voyez pas toujours jusqu’au précipice.
En outre, les divergences entre versions et forks comptent. Une configuration VPS stable pour une version majeure peut devenir étrange après une mise à jour, surtout autour des choix d’optimiseur et des valeurs par défaut.
PostgreSQL sur un VPS : où il excelle
Quand PostgreSQL gagne sur le coût
- Charges mixtes : lectures, écritures, requêtes analytiques légères et « le produit veut des rapports » dans la même base.
- Requêtes complexes où la qualité du plan et les options d’indexation comptent.
- Clarté opérationnelle : statistiques intégrées et culture d’introspection.
- Maintenabilité à long terme : sémantiques prévisibles, moins de « ça dépend du moteur ».
Les réglages qui importent (et pourquoi)
Le tuning PostgreSQL sur VPS consiste surtout à : (1) éviter le surengagement mémoire, (2) lisser WAL/checkpoints, (3) maintenir VACUUM en bonne santé.
- shared_buffers : pas « aussi grand que possible ». Sur Linux, trop grand peut affamer le cache du système de fichiers et nuire. Habituellement 15–25 % de la RAM est un départ sensé sur un VPS.
- work_mem : par tri/hash, par nœud, par requête. Si vous le mono augmentez héroïquement, votre machine OOMera comme un vilain.
- effective_cache_size : indique au planificateur quel cache est probablement disponible (cache OS + shared_buffers). Ça n’alloue pas de mémoire, mais ça change les plans.
- checkpoint_timeout, max_wal_size, checkpoint_completion_target : ces réglages peuvent transformer des « pics de latence périodiques » en « ennuyeux ». L’ennui, c’est bien.
- autovacuum settings : autovacuum est votre colocataire qui nettoie. Si vous le désactivez, vous apprécierez l’ambiance jusqu’à ce que les poubelles débordent.
Où PostgreSQL peut gaspiller votre budget
Le principal piège coûteux est la gestion des connexions. Des milliers de connexions clientes sur un petit VPS feront dépenser Postgres en context switches et mémoire, pas en exécution de requêtes. Si vous n’utilisez pas de pooler, vous achèterez une instance plus grosse juste pour héberger des connexions inactives. Ce n’est pas « scaler ». C’est subventionner de mauvais choix.
Blague #2 : Désactiver autovacuum parce qu’il « utilise du CPU » revient à enlever le détecteur de fumée parce qu’il est bruyant.
Une citation qui colle à la production
Werner Vogels (CTO d’Amazon) a dit : « Everything fails all the time. »
Mode d’emploi pour un diagnostic rapide
Quand la performance chute sur un VPS, votre travail n’est pas de deviner. Votre travail est de localiser le goulet d’étranglement rapidement, puis de décider si vous êtes CPU-bound, mémoire-bound, I/O-bound, ou victime de contention et mise en file.
Première étape : confirmer la forme du symptôme
- Pattern de pics de latence : périodique (checkpoints, vacuum, sauvegardes) vs soutenu (saturation I/O, contention de verrous).
- Périmètre : une requête/table vs tout le système.
- Temps de récupération : secondes (burst) vs heures (dette de maintenance).
Deuxième étape : décider quel est le limiteur principal
- Stockage : iowait élevé, temps fsync longs, IOPS faibles, files d’attente disque longues.
- CPU : user/sys élevé, steal élevé, run queue > cœurs.
- Mémoire : swap, thrash du page cache, kills OOM, ratés du working set important.
- Verrouillage/contention : attentes sur locks, contentions sur buffers, trop de connexions.
Troisième étape : choisir la bonne « classe de correctif »
- Si storage-bound : lisser checkpoints/WAL/redo, éviter les fsync storms, réduire les lectures aléatoires via cache/indexation, envisager un volume séparé pour les logs.
- Si CPU-bound : réduire la concurrence, corriger les requêtes lentes, ajouter des index, éviter les fonctions par ligne, tuner le parallélisme prudemment.
- Si mémoire-bound : dimensionner correctement les buffers, réduire work_mem / buffers par thread, implémenter du pooling, arrêter le swap.
- Si contention-bound : réduire la durée des transactions, éviter les lignes chaudes, ordonner les verrous, revoir le niveau d’isolation, améliorer les index, regrouper les écritures.
Plus de 12 tâches pratiques : commandes, sorties, décisions
Voici les tâches que vous exécutez réellement sur un VPS quand vous essayez d’acheter de la vitesse avec de l’ingénierie plutôt qu’avec la carte bancaire. Chaque tâche inclut une commande réaliste, un schéma de sortie, ce que signifie la sortie, et la décision à prendre.
Task 1: Check CPU steal and iowait (is the VPS lying to you?)
cr0x@server:~$ mpstat -P ALL 1 5
Linux 6.1.0 (vps01) 12/29/2025 _x86_64_ (4 CPU)
12:00:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
12:00:01 AM all 22.10 0.00 6.12 18.33 0.00 0.55 8.40 44.50
...
Signification : %steal autour de 8 % signifie que vos « 4 vCPU » ne sont pas toujours disponibles. %iowait proche de 18 % indique que les stalls de stockage dominent.
Décision : Ne touchez pas SQL en premier. Commencez par lisser I/O (WAL/checkpoints/redo) et réduisez les écrivains concurrents. Si le steal reste élevé, envisagez une autre classe/provider VPS avant d’acheter plus de cœurs.
Task 2: Find disk queueing and latency (the “why is p99 awful” check)
cr0x@server:~$ iostat -x 1 5
Linux 6.1.0 (vps01) 12/29/2025 _x86_64_
Device r/s w/s rkB/s wkB/s await aqu-sz %util
vda 85.0 60.0 3400.0 5200.0 22.5 1.80 98.0
...
Signification : await 22.5ms et %util 98 % indiquent un stockage saturé avec une file persistante (aqu-sz ~1.8).
Décision : Vous êtes I/O-bound. Priorisez la réduction de la fréquence des fsync, augmentez le cache hit rate, et éliminez les écritures inutiles (index, logs verbeux). Envisagez de déplacer WAL/redo sur un stockage plus rapide si possible.
Task 3: Confirm filesystem and mount options (barriers, atime, discard)
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /var/lib
/dev/vda1 ext4 rw,relatime,errors=remount-ro
Signification : ext4 avec relatime est normal. Si vous voyez des options exotiques ou des systèmes de fichiers réseau, arrêtez et reconsidérez vos choix de vie.
Décision : Restez basique. Si atime est activé (au lieu de relatime/noatime), envisagez noatime pour les charges de lecture lourdes. Évitez de « tuner » les options de montage sans les comprendre ; la base de données gère déjà la logique de durabilité.
Task 4: Detect swapping and memory pressure
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 8.0Gi 6.9Gi 120Mi 180Mi 1.0Gi 420Mi
Swap: 2.0Gi 1.6Gi 420Mi
Signification : Vous swappez beaucoup ; « available » est faible. La latence de la base deviendra non linéaire.
Décision : Réduisez les réglages mémoire maintenant (work_mem/shared_buffers pour Postgres ; buffer pool + buffers par thread pour MariaDB). Envisagez d’ajouter de la RAM seulement après avoir confirmé que vous n’avez pas une fuite mémoire due à des tempêtes de connexions.
Task 5: Check per-process memory and OOM kills
cr0x@server:~$ dmesg -T | tail -n 8
[Mon Dec 29 00:10:12 2025] Out of memory: Killed process 2113 (postgres) total-vm:5242880kB, anon-rss:3100000kB, file-rss:0kB, shmem-rss:0kB
[Mon Dec 29 00:10:12 2025] oom_reaper: reaped process 2113 (postgres), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Signification : Le noyau a tué un backend PostgreSQL. C’est dangereux pour l’intégrité si ça arrive au mauvais moment, et cela va certainement ruiner votre lundi.
Décision : Corrigez la configuration mémoire et mettez en place du pooling immédiatement. Ne blâmez pas le planificateur de requêtes ; c’est une discipline de capacité de base.
Task 6: PostgreSQL—find top queries by total time (stop guessing)
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT queryid, calls, total_exec_time::bigint AS total_ms, mean_exec_time::numeric(10,2) AS mean_ms, rows, left(query, 80) AS q FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;"
queryid | calls | total_ms | mean_ms | rows | q
----------+-------+----------+---------+------+-----------------------------------------------
91230123 | 12000 | 980000 | 81.67 | 120 | SELECT * FROM orders WHERE user_id=$1 ORDER BY created_at DESC LIMIT $2
11223344 | 1500 | 410000 | 273.33 | 1 | UPDATE inventory SET qty=qty-$1 WHERE sku=$2
...
Signification : Vous avez un petit nombre de « heavy hitters ». La première requête a probablement besoin d’un index composite. La update peut être une contention sur une ligne chaude.
Décision : Optimisez les 1–3 requêtes principales avant de toucher aux réglages globaux. Les indexes et réécritures de requêtes battent « plus de shared_buffers » la plupart du temps.
Task 7: PostgreSQL—check what you’re waiting on (locks vs I/O vs CPU)
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT wait_event_type, wait_event, count(*) FROM pg_stat_activity WHERE state='active' GROUP BY 1,2 ORDER BY 3 DESC;"
wait_event_type | wait_event | count
-----------------+---------------------+-------
IO | DataFileRead | 12
Lock | relation | 4
LWLock | buffer_content | 3
Signification : Majoritairement en attente de DataFileRead = manque de cache (ou beaucoup de lectures aléatoires). Quelques waits de verrou indiquent de la contention, mais ce n’est pas le problème dominant.
Décision : Augmentez le cache hit rate via indexation, réduction du bloat (vacuum) et dimensionnement adéquat de shared_buffers/effective_cache_size. Pour les waits de lock, raccourcissez les transactions et évitez les patterns de hotspot.
Task 8: PostgreSQL—measure cache hit ratio, but don’t worship it
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT datname, blks_hit, blks_read, round(100.0*blks_hit/nullif(blks_hit+blks_read,0),2) AS hit_pct FROM pg_stat_database WHERE datname='appdb';"
datname | blks_hit | blks_read | hit_pct
---------+----------+-----------+---------
appdb | 92000000 | 7800000 | 92.17
Signification : 92 % n’est pas terrible, mais sur un VPS avec stockage médiocre, ces 8 % peuvent encore être votre p99.
Décision : Si vous ne pouvez pas améliorer index/requêtes, ajoutez de la RAM (ou réduisez la taille du dataset) pour améliorer le hit rate. Vérifiez aussi les scans séquentiels sur les grandes tables.
Task 9: PostgreSQL—spot autovacuum debt and bloat candidates
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT relname, n_live_tup, n_dead_tup, last_autovacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 5;"
relname | n_live_tup | n_dead_tup | last_autovacuum
----------------+------------+------------+--------------------------
events | 8200000 | 1900000 | 2025-12-28 21:14:09+00
sessions | 1500000 | 420000 | 2025-12-28 22:05:51+00
...
Signification : Le nombre de tuples morts est élevé ; vacuum accuse du retard. Cela augmente les I/O aléatoires, nuit aux index et peut créer un risque de wraparound si négligé trop longtemps.
Décision : Tondez autovacuum par table (scale factors, cost limits) et planifiez des maintenances pour vacuum/analyze intensifs si nécessaire. Sur un petit VPS, la « dette de vacuum » devient « dette budgétaire ».
Task 10: MariaDB—inspect InnoDB buffer pool behavior
cr0x@server:~$ sudo mariadb -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool%';"
+---------------------------------------+-----------+
| Variable_name | Value |
+---------------------------------------+-----------+
| Innodb_buffer_pool_pages_total | 524288 |
| Innodb_buffer_pool_pages_free | 1200 |
| Innodb_buffer_pool_read_requests | 980000000 |
| Innodb_buffer_pool_reads | 22000000 |
+---------------------------------------+-----------+
Signification : Les pages libres sont rares (pool « plein », normal). Reads vs read_requests indique à quelle fréquence vous manquez le cache. Un Innodb_buffer_pool_reads élevé est coûteux sur du stockage VPS.
Décision : Si les misses sont élevés par rapport au volume de requêtes, augmentez le buffer pool (si la RAM le permet) ou corrigez les index et réduisez les scans de table.
Task 11: MariaDB—check redo log pressure and flushing
cr0x@server:~$ sudo mariadb -e "SHOW GLOBAL STATUS LIKE 'Innodb_log_waits'; SHOW GLOBAL STATUS LIKE 'Innodb_os_log_fsyncs';"
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| Innodb_log_waits | 842 |
+------------------+-------+
+---------------------+--------+
| Variable_name | Value |
+---------------------+--------+
| Innodb_os_log_fsyncs| 520000 |
+---------------------+--------+
Signification : Innodb_log_waits > 0 signifie que des sessions attendent de l’espace redo log ou la progression du flush — classique goulot d’écriture.
Décision : Augmentez la capacité redo (selon les paramètres de version), ajustez le flush, et réduisez la rafale de transactions. Si le stockage est lent, ne tradez la durabilité que si le business l’accepte.
Task 12: MariaDB—confirm what durability level you’re actually running
cr0x@server:~$ sudo mariadb -e "SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'; SHOW VARIABLES LIKE 'sync_binlog';"
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_flush_log_at_trx_commit| 1 |
+-------------------------------+-------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 1 |
+---------------+-------+
Signification : Les deux à 1 signifient durabilité forte (fsync par commit et par groupe de binlog selon la config). Cela coûte des IOPS mais protège l’intégrité.
Décision : Si vous avez besoin de vitesse et pouvez accepter un risque, vous pouvez relaxer l’un des deux. Si vous ne savez pas expliquer le risque à un non‑technique, laissez‑les à 1 et optimisez ailleurs.
Task 13: Detect excessive connections (PostgreSQL)
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT state, count(*) FROM pg_stat_activity GROUP BY state ORDER BY count(*) DESC;"
state | count
--------+-------
idle | 320
active | 25
null | 2
Signification : Des centaines de connexions idle gaspillent de la mémoire et augmentent la charge de gestion.
Décision : Ajoutez un pooler (ou corrigez le pooling côté app). Réduisez max_connections et imposez la discipline. Sur VPS, les connexions idle sont un luxe.
Task 14: Detect replication lag (both worlds) before it ruins failover
cr0x@server:~$ sudo mariadb -e "SHOW SLAVE STATUS\G" | egrep 'Seconds_Behind_Master|Slave_IO_Running|Slave_SQL_Running'
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 37
Signification : 37 secondes de lag. Pas catastrophique, mais si vous faites un failover pendant un incident, vous choisissez perte de données ou downtime.
Décision : Investiguer les rafales d’écriture, le disque lent, et les transactions longues. Envisagez semi‑sync ou un meilleur hardware pour les réplicas si le RPO compte.
Task 15: Check fsync timing pain indirectly (PostgreSQL checkpoint stats)
cr0x@server:~$ sudo -u postgres psql -d appdb -c "SELECT checkpoints_timed, checkpoints_req, round(checkpoint_write_time/1000.0,1) AS write_s, round(checkpoint_sync_time/1000.0,1) AS sync_s FROM pg_stat_bgwriter;"
checkpoints_timed | checkpoints_req | write_s | sync_s
------------------+-----------------+---------+--------
120 | 85 | 980.4 | 210.2
Signification : Un sync_time élevé implique que le stockage lutte lors des checkpoints ; cela se traduit par des pics de latence visibles par les utilisateurs.
Décision : Augmentez max_wal_size, ajustez checkpoint_completion_target, et réduisez les écritures en rafale. Si possible, séparez le WAL sur un volume mieux adapté.
Trois mini‑récits du monde corporate (anonymisés, plausibles, douloureux)
1) Incident causé par une mauvaise hypothèse : « Plus de RAM = plus rapide »
Une entreprise avait une petite flotte de VPS hébergeant un monolithe et sa base. La base était MariaDB. Le trafic a crû, et l’équipe a fait ce que font les équipes sous pression : ils ont doublé la RAM et se sont déclarés vainqueurs. Les graphiques allaient mieux pendant environ une semaine.
Puis une campagne marketing est arrivée. La latence a grimpé jusqu’à des timeouts. Les serveurs applicatifs allaient bien. Le CPU allait bien. La base avait beaucoup de mémoire. Tout le monde regardait le dashboard comme s’il leur devait des excuses.
L’hypothèse erronée était simple : « S’il y a de la RAM libre, la base doit pouvoir l’utiliser. » Ils avaient augmenté la RAM mais conservé une taille de InnoDB buffer pool conservatrice héritée, et la charge avait changé. Les lectures manquaient désormais le cache et frappaient le disque. La nouvelle RAM est devenue surtout cache du système de fichiers et « libre », tandis que la base payait toujours des I/O aléatoires sur un volume de stockage bruyant.
Pire, il y avait un effet de second ordre : plus de RAM signifiait un plus grand backlog potentiel de pages sales et des working sets plus gros, ce qui rendait les rafales plus pénalisantes quand les threads de flush prenaient du retard. Quand la campagne est arrivée, le comportement de flush d’InnoDB a généré des stalls périodiques qui se sont alignés parfaitement avec le pic de trafic.
La correction n’a pas été héroïque. Ils ont dimensionné correctement le buffer pool, validé les paramètres de capacité I/O, et rejoué la charge pour confirmer la stabilisation du p99. La leçon coûteuse : sur VPS, la RAM n’est performance que si la base est configurée pour l’utiliser.
2) Optimisation qui s’est retournée contre eux : « On augmente work_mem »
Une autre organisation faisait tourner PostgreSQL sur un VPS 2 vCPU / 8 GB. Les requêtes de reporting étaient lentes, et quelqu’un a proposé d’augmenter work_mem « pour que les tris se fassent en mémoire ». Ils l’ont monté agressivement, parce que les requêtes étaient lourdes et que les plaintes des utilisateurs étaient plus lourdes encore.
Pendant un jour, les rapports ont hurlé. Puis tout le système est devenu étrange. Pics aléatoires. Autovacuum a commencé à prendre du retard. Le noyau a commencé à swapper. L’app a vu des 502 intermittents. Vous connaissez le schéma : tout ressemble à un problème réseau quand l’hôte est en feu.
Le retour de bâton était prévisible : work_mem est par opération, par requête, par backend. Sous concurrence, Postgres alloue volontiers bien plus que la RAM physique, et Linux répond par du swap. Pas du petit swap. Le genre qui fait sentir un VPS comme s’il tournait sur une clé USB dans un tiroir.
La correction a impliqué de baisser work_mem, d’ajouter un pooler pour limiter la concurrence, et de réécrire quelques rapports pour pré‑agréger. Ils ont aussi appris à benchmarker avec une concurrence réaliste. Les benchmarks mono‑utilisateur sont la manière la plus sûre d’acheter le mauvais serveur.
3) Pratique ennuyeuse mais correcte qui a sauvé la mise : « Nous avons maintenu vacuum et sauvegardes »
Un petit SaaS faisait tourner PostgreSQL sur un VPS modeste avec une réplique en lecture. Ils n’avaient pas d’infrastructure fancy, mais ils avaient de la discipline : autovacuum était réglé par table pour les données très volatiles, et ils avaient des maintenances programmées pour les pires cas. Chaque changement de schéma venait avec un plan d’index et un rollback.
Un après‑midi, la latence du stockage sur le primaire s’est dégradée. Pas une panne complète — juste assez pour créer la misère. Les checkpoints mettaient plus de temps, le WAL flushait plus lentement, et la latence applicative augmentait. L’équipe avait deux avantages : ils savaient à quoi ressemblait le « normal », et leur système n’accumulait pas de dette de maintenance.
Parce que le vacuum n’était pas en retard, les tables n’étaient pas gonflées, donc le système n’amplifiait pas les lectures inutilement. Parce que les sauvegardes étaient testées, ils pouvaient faire des changements sans peur. Parce que la réplication était surveillée, ils savaient que la réplique était saine et pouvait servir temporairement des lectures.
L’incident a tout de même fait mal, mais il n’est pas devenu une catastrophe de plusieurs jours. La « pratique ennuyeuse » n’était pas une astuce secrète de performance. C’était juste refuser de laisser la base devenir une décharge. Sur un budget VPS, la propreté est de la performance.
Erreurs courantes : symptômes → cause racine → correctif
1) Symptom: periodic 2–10 second latency spikes
Cause racine : checkpoints (PostgreSQL) ou flushs agressifs (InnoDB) provoquant des I/O synchrones en rafale ; parfois des sauvegardes concurrents pour le disque.
Fix : Lisser les écritures : augmenter la capacité WAL/redo, ajuster la cadence des checkpoints, s’assurer que les sauvegardes utilisent un throttling ou tournent en hors‑pic. Confirmer avec iostat await/%util et les stats du bgwriter Postgres.
2) Symptom: “CPU is low but everything is slow”
Cause racine : latence stockage ou waits de locks. Le CPU semble inactif parce que les threads attendent.
Fix : Vérifier iowait, queue disque et événements d’attente DB. Pour les locks, identifier les bloqueurs et raccourcir les transactions.
3) Symptom: Postgres gets slower over days/weeks without code changes
Cause racine : dette de vacuum/analyze, bloat table/index, statistiques de planificateur obsolètes.
Fix : Ajuster autovacuum (surtout les scale factors) pour les tables à fort churn ; surveiller les tuples morts ; planifier vacuum/analyze ; envisager le partitionnement pour les données très volatiles.
4) Symptom: MariaDB replication lag grows during peak writes
Cause racine : le replica I/O ne suit pas (coût des fsync redo/binlog, disque lent), ou des transactions longues retardent l’application.
Fix : Réduire la pression fsync, s’assurer que le stockage du replica est adéquat, éviter les transactions géantes, et surveiller le taux d’application. Si votre plan de failover suppose zéro lag, cessez de faire cette supposition.
5) Symptom: high load average but modest CPU usage
Cause racine : la file exécutable contient des tâches bloquées en I/O non interruptible (état D). La moyenne de charge les inclut.
Fix : Confirmer avec iostat et états de processus. La solution est le stockage, pas plus de vCPU.
6) Symptom: sudden OOM kills after “tuning for speed”
Cause racine : explosion mémoire par connexion (Postgres work_mem, maintenance_work_mem ; buffers sort/join MariaDB) combinée à trop de connexions.
Fix : Mettre en place du pooling, réduire max_connections, et fixer les paramètres mémoire en fonction du pire cas de concurrence.
7) Symptom: inserts slow, selects fine (PostgreSQL)
Cause racine : latence fsync WAL, trop d’index, ou synchronous_commit mal adapté au hardware.
Fix : Réduire le nombre d’index, grouper les écritures, tuner WAL/checkpoints, envisager async commit seulement si acceptable, et s’assurer que le WAL ne concurrence pas les lectures aléatoires.
8) Symptom: “We upgraded instance size and got nothing”
Cause racine : le goulot est le stockage ou la contention de verrous ; plus de CPU/RAM ne change rien.
Fix : Mesurez iowait, await et waits de locks d’abord ; puis dépensez.
Listes de contrôle / plan étape par étape
A. Choisir le moteur pour le rapport vitesse/prix (checklist décisionnelle)
- Besoin de SQL complexe, diagnostics clairs et comportement prévisible ? Choisissez PostgreSQL.
- Principalement OLTP simple, équipe MySQL‑native, dataset chaud tient dans le buffer pool ? MariaDB est un bon choix coût‑efficace.
- Qualité du stockage inconnue ou inconsistante ? Favorisez PostgreSQL si vous voulez une forte cohérence sans tentations « rapides mais risquées » ; sinon vous pouvez vous coincer en tunant.
- Nombre de connexions élevé et app bavarde ? PostgreSQL avec un pooler ; MariaDB est aussi sensible, mais Postgres vous punira plus directement.
B. Baseline d’un nouveau VPS (faire avant d’accuser la base)
- Vérifier le steal CPU et la latence de stockage au repos et sous charge.
- Confirmer le système de fichiers, les options de montage et l’espace libre.
- Mettre en place des métriques de base : CPU, iowait, disk await, connexions DB, lag de réplication.
- Exécuter un benchmark de concurrence réaliste (pas un client, pas une requête).
C. Plan de tuning PostgreSQL pour VPS (sûr et efficace)
- Implémenter du pooling de connexions ; limiter les sessions actives.
- Fixer shared_buffers de façon conservatrice ; définir effective_cache_size réalistement.
- Définir work_mem modestement ; vérifier la concurrence maximale avant d’augmenter.
- Tuner checkpoint/WAL pour réduire les pics de latence.
- Valider que autovacuum suit le rythme ; tuner par table pour les données à fort churn.
- Ajouter des index uniquement quand ils rapportent ; chaque index coûte à l’écriture.
D. Plan de tuning MariaDB pour VPS (InnoDB d’abord, bon sens d’abord)
- Dimensionner innodb_buffer_pool_size sur votre working set chaud, en laissant une marge pour l’OS.
- Assurer que la capacité redo est suffisante ; éviter les innodb_log_waits.
- Définir innodb_io_capacity en fonction de la réalité, pas de l’optimisme.
- Être explicite sur les réglages de durabilité ; ne pas les relaxer par accident.
- Surveiller le lag de réplication et la longueur de l’historique de purge (selon version/outillage).
- Auditer les index : supprimer ceux ajoutés « au cas où ».
E. La checklist « ne pas acheter plus gros tout de suite »
- Vous avez identifié les requêtes principales et mesuré leur impact.
- Vous avez confirmé si les waits sont I/O, locks ou CPU.
- Vous avez éliminé le swap et les tempêtes de connexions.
- Vous avez lissé le comportement des checkpoints/flushs.
- Vous avez validé que la réplication et les sauvegardes ne concourent pas avec la production.
FAQ
1) Lequel est plus rapide sur un VPS bon marché : MariaDB ou PostgreSQL ?
Ça dépend de la forme de la charge, mais PostgreSQL offre souvent une performance plus prévisible sur des charges mixtes. MariaDB peut être plus rapide pour de l’OLTP simple majoritairement en lecture quand le buffer pool couvre le working set.
2) Quel est le plus gros goulot VPS pour les deux ?
La variabilité de la latence du stockage. Pas la bande passante — la latence. Le comportement WAL/redo fsync rend les petits stalls visibles par les utilisateurs.
3) Dois‑je placer WAL/redo sur un disque séparé ?
Si votre fournisseur VPS propose un volume séparé avec des caractéristiques de performance indépendantes, oui, cela peut aider. Si c’est le même pool sous‑jacent, vous ajoutez peut‑être juste de la complexité.
4) Est‑il sûr de relaxer la durabilité pour gagner de la vitesse ?
Parfois. Mais « sûr » est une politique business, pas un réglage de base de données. Si vous pouvez tolérer de perdre la dernière seconde de transactions après un crash, vous pouvez acheter de la vitesse. Si vous ne le pouvez pas, optimisez ailleurs.
5) Pourquoi PostgreSQL a besoin de VACUUM et MariaDB pas (aussi visiblement) ?
Le MVCC de PostgreSQL laisse des tuples morts jusqu’à ce que vacuum récupère l’espace et maintienne la visibilité. InnoDB gère undo/redo et purge différemment. Les deux nécessitent de la maintenance ; PostgreSQL rend juste la chose plus difficile à ignorer.
6) Comment savoir si j’ai besoin d’un pooler pour PostgreSQL ?
Si vous avez des centaines de connexions principalement inactives ou des rafales de churn de connexions, vous avez besoin de pooling. Sur un petit VPS, c’est l’un des meilleurs upgrades « rapport vitesse/prix » que vous puissiez faire sans dépenser en matériel.
7) Sur quels indicateurs dois‑je alerter en premier ?
Disk await/%util, iowait, utilisation du swap, connexions actives, lag de réplication, et événements d’attente DB (pour Postgres). Alertez sur les tendances, pas seulement sur des seuils.
8) Puis‑je me sortir d’un mauvais stockage VPS uniquement par du tuning ?
Vous pouvez réduire les dégâts — lisser les écritures, augmenter le cache hit rate, réduire la concurrence — mais vous ne pouvez pas vaincre la physique et les voisins bruyants indéfiniment. Parfois, le bon tuning est de changer de fournisseur ou de classe de stockage.
9) Pour le rapport vitesse/prix, dois‑je scaler verticalement ou ajouter une réplique ?
Si les lectures dominent, une réplique apporte souvent plus que la montée en vertical. Si les écritures dominent et que vous êtes I/O-bound sur WAL/redo, une montée en vertical (ou un meilleur stockage) gagne généralement en premier.
10) Lequel est plus facile à diagnostiquer sous pression ?
Typiquement PostgreSQL. Les outils d’introspection et la visibilité des waits sont meilleurs par défaut, et l’histoire performance est plus simple à raisonner quand vous êtes fatigué.
Prochaines étapes réalisables cette semaine
- Mesurez votre réalité VPS : lancez mpstat et iostat pendant une période lente et une période chargée. Si iowait et await sont élevés, arrêtez de prétendre que votre goulot est la syntaxe SQL.
- Trouvez les requêtes principales : utilisez pg_stat_statements (Postgres) ou slow query log/performance schema tooling (MariaDB) et corrigez les pires coupables d’abord.
- Éliminez le swap : redimensionnez les paramètres mémoire et implémentez le pooling. Le swap transforme un « VPS bon marché » en « panne coûteuse ».
- Lissez les écritures : ajustez checkpoints (Postgres) ou flushing/log (MariaDB) pour réduire les pics, puis vérifiez avec des stats et des graphiques de latence.
- Rendez la maintenance ennuyeuse : la santé d’autovacuum (Postgres) et la santé des logs/flush d’InnoDB (MariaDB) ne sont pas « plus tard ». C’est le loyer.
Si vous voulez le meilleur rapport vitesse/prix, traitez la base de données comme un système de production, pas comme une bibliothèque magique. Mesurez. Changez une chose. Mesurez encore. Ce n’est pas seulement une vertu d’ingénierie — c’est la mise à niveau de performance la moins chère que vous puissiez acheter.