La gestion efficace de l’espace disque dans PostgreSQL est une préoccupation constante pour les administrateurs de bases de données. C’est là qu’intervient le processus de “vacuum”, une fonctionnalité puissante et complexe qui peut jouer un rôle déterminant dans la performance et la stabilité de votre base de données PostgreSQL. Cependant, comme toute arme à double tranchant, le vacuum apporte à la fois des avantages considérables et des défis potentiels.
Le principal reproche que l’on peut adresser au système de vacuum (et à l’auto-vacuum par extension) est sa consommation importante de ressources. C’est l’une des raisons majeures évoquées par les grandes entreprises qui optent pour un autre SGBD, comme Uber, qui a migré vers MySQL pour remplacer PostgreSQL.
OrioleDB nous propose une approche novatrice de la gestion de la fragmentation (bloat) et de l’espace disque de vos tables PostgreSQL. La principale promesse de ce nouveau moteur développé par la société Oriole est d’éliminer le besoin de vacuum régulier et de longues périodes de maintenance pour nos bases de données.
Cette innovation s’articule autour de journaux d’annulation au niveau de la ligne et du bloc, ainsi que de la fusion automatique des pages. Les journaux d’annulation au niveau des lignes et des blocs offrent un contrôle plus précis, permettant une gestion plus efficace des modifications de données. La fonction de fusion automatique des pages travaille en arrière-plan pour regrouper les données fragmentées, améliorant ainsi encore davantage l’efficacité du système. Le moteur est actuellement disponible en version bêta sur le site d’OrioleDB.
Dans cet article, je vais vous montrer comment installer OrioleDB et réaliser un test comparatif entre une instance classique et une instance OrioleDB en termes d’espace disque occupé. Je vais utiliser notre agent AllDB de supervision des bases de données pour générer des graphiques de la consommation d’espace disque.
Installation d’OrioleDB :
Pour pouvoir tester le nouveau moteur, il nous faut l’installer. Pour cela, deux solutions s’offrent à nous. On peut choisir de le compiler nous-mêmes à partir du code source fourni par Oriole, ou on peut choisir d’utiliser le conteneur Docker mis à notre disposition.
Pour des raisons de rapidité de mise en place, j’ai choisi d’utiliser le conteneur fourni.
Pour commencer, j’installe Docker sur ma machine.
root@ip-172-44-2-190:~$ sudo apt-get update (...) Reading package lists... Done root@ip-172-44-2-190:~$ sudo apt-get install ca-certificates curl gnupg Reading package lists... Done (...) No VM guests are running outdated hypervisor (qemu) binaries on this host. root@ip-172-44-2-190:~$ sudo install -m 0755 -d /etc/apt/keyrings root@ip-172-44-2-190:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg root@ip-172-44-2-190:~$ sudo chmod a+r /etc/apt/keyrings/docker.gpg root@ip-172-44-2-190:~$ echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update Hit:1 http://eu-west-3.ec2.archive.ubuntu.com/ubuntu jammy InRelease Hit:2 http://eu-west-3.ec2.archive.ubuntu.com/ubuntu jammy-updates InRelease (...) No VM guests are running outdated hypervisor (qemu) binaries on this host.
Pour tester que mon installation fonctionne correctement, je peux démarrer l’image hello-world par défaut de Docker.
root@ip-172-44-2-190:~$ sudo docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 719385e32844: Pull complete Digest: sha256:4f53e2564790c8e7856ec08e384732aa38dc43c52f02952483e3f003afbf23db Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
Docker est correctement installé, nous pouvons à présent aller récupérer l’image Oriole depuis les dépôts (repositories). J’ai choisi de récupérer l’image “latest” de la version 14, avec laquelle je vais effectuer mes tests.
root@ip-172-44-2-190:~# docker pull orioledb/orioledb:latest-pg14 latest-pg14: Pulling from orioledb/orioledb 7264a8db6415: Pull complete 4e0888d8a332: Pull complete 4b0510894ae7: Pull complete dc5da57566a1: Pull complete 9611602787a1: Pull complete 8f68f9452236: Pull complete 5c92ed25d025: Pull complete 11bb162cfe7a: Pull complete 6f375d990892: Pull complete 6ac166496e68: Pull complete Digest: sha256:4d408916e929ff0bcea11fee91ca5e69b0929be1afa58b5dbbcddcce340089ef Status: Downloaded newer image for orioledb/orioledb:latest-pg14 docker.io/orioledb/orioledb:latest-pg14
On vérifie que notre image est bien présente, et on l’éxecute :
root@ip-172-44-2-190:~# docker image ls --all REPOSITORY TAG IMAGE ID CREATED SIZE orioledb/orioledb latest-pg14 cd7f629f705e 10 days ago 270MB hello-world latest 9c7a54a9a43c 4 months ago 13.3kB
root@ip-172-44-2-190:~# docker run -e POSTGRES_PASSWORD=password cd7f629f705e The files belonging to this database system will be owned by user "postgres". This user must also own the server process. The database cluster will be initialized with locale "en_US.utf8". The default database encoding has accordingly been set to "UTF8". The default text search configuration will be set to "english". Data page checksums are disabled. fixing permissions on existing directory /var/lib/postgresql/data ... ok creating subdirectories ... ok selecting dynamic shared memory implementation ... posix selecting default max_connections ... 100 selecting default shared_buffers ... 128MB selecting default time zone ... UTC creating configuration files ... ok running bootstrap script ... ok performing post-bootstrap initialization ... sh: locale: not found 2023-09-21 09:51:08.177 UTC [30] WARNING: no usable system locales were found ok syncing data to disk ... ok Success. You can now start the database server using: pg_ctl -D /var/lib/postgresql/data -l logfile start initdb: warning: enabling "trust" authentication for local connections You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. waiting for server to start....2023-09-21 09:51:09.294 UTC [36] LOG: OrioleDB public beta 2 started 2023-09-21 09:51:09.295 UTC [36] LOG: starting PostgreSQL 14.9 OrioleDB public beta 2 PGTAG=patches14_16 alpine:3.18+clang-15 build:2023-09-10T16:41:50+00:00 on x86_64-pc-linux-musl, compiled by Alpine clang version 15.0.7, 64-bit 2023-09-21 09:51:09.300 UTC [36] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" 2023-09-21 09:51:09.316 UTC [37] LOG: database system was shut down at 2023-09-21 09:51:08 UTC 2023-09-21 09:51:09.316 UTC [38] LOG: orioledb background writer started 2023-09-21 09:51:09.323 UTC [36] LOG: database system is ready to accept connections done server started /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* waiting for server to shut down...2023-09-21 09:51:09.350 UTC [36] LOG: received fast shutdown request .2023-09-21 09:51:09.353 UTC [36] LOG: aborting any active transactions 2023-09-21 09:51:09.354 UTC [38] LOG: orioledb bgwriter is shut down 2023-09-21 09:51:09.357 UTC [36] LOG: background worker "logical replication launcher" (PID 44) exited with exit code 1 2023-09-21 09:51:09.357 UTC [39] LOG: shutting down 2023-09-21 09:51:09.360 UTC [39] LOG: orioledb checkpoint 1 started 2023-09-21 09:51:09.601 UTC [39] LOG: orioledb checkpoint 1 complete 2023-09-21 09:51:09.631 UTC [36] LOG: database system is shut down done server stopped PostgreSQL init process complete; ready for start up. 2023-09-21 09:51:09.712 UTC [1] LOG: OrioleDB public beta 2 started 2023-09-21 09:51:09.764 UTC [1] LOG: starting PostgreSQL 14.9 OrioleDB public beta 2 PGTAG=patches14_16 alpine:3.18+clang-15 build:2023-09-10T16:41:50+00:00 on x86_64-pc-linux-musl, compiled by Alpine clang version 15.0.7, 64-bit 2023-09-21 09:51:09.764 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 2023-09-21 09:51:09.764 UTC [1] LOG: listening on IPv6 address "::", port 5432 2023-09-21 09:51:09.770 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" 2023-09-21 09:51:09.778 UTC [49] LOG: database system was shut down at 2023-09-21 09:51:09 UTC 2023-09-21 09:51:09.778 UTC [50] LOG: orioledb background writer started 2023-09-21 09:51:09.785 UTC [1] LOG: database system is ready to accept connections 2023-09-21 09:54:23.633 UTC [68] FATAL: role "root" does not exist 2023-09-21 09:56:09.884 UTC [51] LOG: orioledb checkpoint 2 started 2023-09-21 09:56:10.100 UTC [51] LOG: orioledb checkpoint 2 complete
Notre serveur est correctement démarré. Nous pouvons maintenant nous y connecter à partir d’un autre terminal et préparer le cas de test. Pour ce faire, nous allons créer une nouvelle base de données sur laquelle nous effectuerons un test de charge avec pg_bench.
root@ip-172-44-2-190:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11c0860b7abc cd7f629f705e "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5432/tcp funny_hellman root@ip-172-44-2-190:~# docker exec -it 11c0860b7abc bash 11c0860b7abc:/# su - postgres 11c0860b7abc:~$ psql psql (14.9 OrioleDB public beta 2 PGTAG=patches14_16 alpine:3.18+clang-15 build:2023-09-10T16:41:50+00:00) Type "help" for help.
postgres=# create database pg_bench; CREATE DATABASE postgres=# \c pg_bench You are now connected to database "pg_bench" as user "postgres". pg_bench=# CREATE TABLE test ( pg_bench(# id integer primary key, pg_bench(# value1 float8 not null, pg_bench(# value2 float8 not null, pg_bench(# value3 float8 not null, pg_bench(# value4 float8 not null, pg_bench(# ts timestamp not null pg_bench(# ); CREATE TABLE pg_bench=# CREATE INDEX test_value1_idx ON test (value1); CREATE INDEX pg_bench=# CREATE INDEX test_value2_idx ON test (value2); CREATE INDEX pg_bench=# CREATE INDEX test_value3_idx ON test (value3); CREATE INDEX pg_bench=# CREATE INDEX test_value4_idx ON test (value4); CREATE INDEX pg_bench=# CREATE INDEX test_ts_idx ON test (ts); CREATE INDEX
Notre environnement de test est prêt. Afin de pouvoir comparer les performances avec une instance PostgreSQL plus traditionnelle, j’ai également installé une version legacy en local sur la machine que j’utilise. J’ai créé la même table et les mêmes index que dans mon conteneur Docker. Pour réaliser ce test, j’ai repris le script pg_bench de test fourni par Oriole.
11c0860b7abc:~$ cat test.sql \set id random(1, 10000000) INSERT INTO test VALUES(:id, random(), random(), random(), random(), now() - random() * random() * 1800 * interval '1 second') ON CONFLICT (id) DO UPDATE SET ts = now();
Ce petit script de test permet de lancer des insertions successives de données dans notre table de test. Il est conçu pour maximiser les chances de fragmentation à mesure que nous insérons des données dans notre table, car les doublons de clé primaire entraînent la mise à jour d’anciennes lignes. Cela devrait donc nous permettre de constater la différence d’espace disque entre une version standard de PostgreSQL et la version du moteur développée par Oriole.
Résultats des test :
Mes tests sont réalisés sur une machine Amazon EC2 de type “large”, équipée de 7 gigaoctets de RAM et de 2 unités de traitement central (CPU).
Voici la capture d’écran de l’occupation de l’espace disque pour le premier test, celui concernant l’instance OrioleDB :
On peut observer que la progression de la taille de l’instance est régulière et très modérée. Pendant le test, j’ai surveillé l’utilisation de la RAM de la machine, qui atteignait un pic à 95 % et demeurait relativement stable pendant toute la durée du test. Conformément à la promesse du moteur, aucun processus d’autovacuum n’a été constaté pendant le processus.
En comparaison, le graphique de la base de données non Oriole présente une nette différence :
On observe notamment de nombreux pics et chutes fréquents dus aux vacuums organisés régulièrement. Le tracé n’est pas linéaire.
De plus, en surveillant les valeurs d’utilisation CPU, à la différence d’Oriole où les valeurs étaient constantes car il était toujours en train d’ajouter des données, les moments de vacuum de la base provoquent d’importantes montées de charge, suivies de chutes lorsque ces processus sont terminés sur notre instance de base.
Conclusion :
Sur le blog d’OrioleDB, les graphiques affichés sont le résultat de l’injection de 80 gigaoctets de données dans leur base de données à l’aide de pg_bench. Cependant, lorsque l’on examine les spécifications de la machine qu’ils ont utilisée pour leurs tests, on se rend compte qu’elle n’est pas à la portée de toutes les bourses. La machine utilisée comprend en effet 72 CPU et dispose d’un total de 144 Go de RAM, une configuration que très peu de personnes, principalement en raison du coût élevé de ce type de matériel, pourraient envisager pour leur infrastructure.
Oriole fonctionne, comme nous l’avons vu sur les graphiques que j’ai commentés précédemment. Cependant, il s’agit d’un outil conçu pour les architectures de très grande envergure et les besoins importants en termes d’entrées/sorties de données. Les gains ne sont pas aussi significatifs sur des machines de plus petite taille, qui correspondent davantage à la réalité de nombreuses entreprises actuelles.
Continuez votre lecture sur le blog :
- Containeriser PostgreSQL avec Docker ! (Emmanuel RAMI) [ContainerPostgreSQL]
- Pyrseas et Postgresql : Comparer facilement des schémas de base de données (Sarah FAVEERE) [PostgreSQL]
- Cybertec Migrator : une alternative à ora2pg ? (Sarah FAVEERE) [OraclePostgreSQL]
- pg_recursively_delete : Simplifier les suppressions récursives (Sarah FAVEERE) [PostgreSQL]
- Comparatif des gestionnaires de VIP dans un cluster Patroni : épisode 1 (KEEPALIVED) (David Baffaleuf) [ContainerPostgreSQL]