TP étude de performances

imt

1. Objectif

L’objectif de ce TP est de vous faire travailler sur deux études de performances :

  • TP vert : la comparaison de performances entre REST, gRPC et GraphQL

  • TP bleu : l’étude de performance d’un load balancer

Votre travail sur ce TP sera à intégrer dans votre rapport. J’attends aussi un rendu de code pour ce TP. Attention la séance va passer vite !

2. TP vert - Comparaison de performances REST/gRPC/GraphQL

2.1. Tests de performances

Vous avez déjà codé vos TP avec différentes API : REST, gRPC, et GraphQL. L’idée ici est de venir vérifier nos attentes en termes de performances entre REST, gRPC et GraphQL. Pour cela vous allez devoir réfléchir à des benchmarks permettant de tester et comparer les performances de chaque solution de façon équitable et juste.

Je vous rappelle par exemple que :

  • gRPC est sensé être plus efficace que REST et GraphQL car il utilise HTTP/2 mais comment le vérifier et à partir de quelle taille de requête/réponse cela est vrai ?

  • GraphQL est plus difficile à mettre en cache que REST en toute logique, comment vérifier cette baisse de performance potentielle ?

  • Si un client n’a besoin que d’une partie de l’information, GraphQL doit avoir de meilleures performances que REST, comment le vérifier ?

  • etc.

Vous pouvez imaginer toute sorte de comparaisons pour mener à bien ces tests, par exemple :

  • comparaison avec différentes requêtes GET, POST

  • comparaison avec des requêtes plus ou moins lourdes

  • comparaison face à un grand nombre de requêtes

Tip
vous pouvez créer pour ces tests de performances des services jouets dont le but est de mettre à l’épreuve les différentes solutions (retour de requête très lourd etc.). Vous pouvez cependant commencer par tester des services écrits pour nos TP précédents.
Important
pour faire un grand nombre de requêtes par seconde vous pouvez utiliser une bibliothèque qui fera des requêtes asynchrones comme par exemple (mais sans doute d’autres) https://github.com/spyoungtech/grequests

2.2. Rendus

Je vous demande de :

  • concevoir des scripts Python (ou un autre langage) pour ces tests de performance

  • me faire un rendu de vos codes avec les instructions pour rejouer vos tests (un déploiement Docker sera plus simple pour moi)

  • un petit descriptif dans le rapport de la mise en place de vos tests et de l’analyse de vos résultats

3. TP bleu - Etude de performance de NGINX

L’objectif de ce tutoriel est de déployer au moyen de conteneurs Docker plusieurs instances de notre service Movie et de configurer et déployer Nginx qui va nous permettre de répartir les requêtes entre les différentes instances de Movie. Vous allez ensuite coder un script de pour tester les performances de la solution mise en place.

Vous pouvez utiliser votre service Movie REST dans ce TP.

3.1. Conteneur pour le service Nginx

Clonez ou téléchargez le zip du repo GitHub suivant : https://github.com/IMTA-LOGIN/tp-perfs

Nous n’allons pas rentrer dans le détail de la configuration de nginx ici mais vous pouvez jeter un oeil au fichier nginx.conf dans lequel sont précisées les adresses des services pour lesquels nous allons faire un load balancing. Comprenez pour le moment que nous aurons 4 instances du service movie. Notez aussi que notre service nginx écoute le port 8000.

Voici le contenu du fichier Dockerfile pour le service nginx

FROM nginx
WORKDIR /app
ADD ./nginx.conf /app/
ADD ./nginx-default-container.conf /etc/nginx/nginx.conf

Notez que pour construire le conteneur nous utilisons l’image de base nginx disponible sur Docker Hub ce qui nous permet de ne pas nous soucier de l’installation de nginx nous même : https://hub.docker.com/_/nginx/

Nous créons ici encore le répertoire de travail de notre conteneur /app dans lequel est copié le fichier nginx.conf. Le fichier nginx-default-container.conf est quand à lui copié à la place du fichier de configuration de base dans /etc/nginx sur le conteneur.

3.2. Déploiement de nos conteneurs

Voici maintenant le contenu du fichier docker-compose.yaml mis à jour :

version: "3.9"
services:
  movie1:
    build: ./movie/
    ports:
      - "5001:5001"
  movie2:
    build: ./movie/
    ports:
      - "5002:5001"
  movie3:
    build: ./movie/
    ports:
      - "5003:5001"
  movie4:
    build: ./movie/
    ports:
      - "5004:5001"
  nginx:
    build: ./nginx/
    ports:
      - "8000:8000"

Les différentes instances de notre service movie sont nommées movie1 movie2 movie3 et movie4. Toutes ces instances fonctionnent en interne sur le port 5001 et nous précisons donc une association de ports pour interroger nos conteneurs sans conflits 5001 5002 5003 et 5004. Notre service nginx quand à lui écoute le port 8000 qui est conservé aussi pour le conteneur.

Une chose très importante est que Docker compose gère un serveur de noms qui permet aux conteneurs de se connaître les uns les autres. Ainsi le service nginx connait les services movie1`etc. C’est pour cette raison que nous avons ces adresses dans le fichier `nginx.conf :

upstream loadbalancer{
    server movie1:5001;
    server movie2:5001;
    server movie3:5001;
    server movie4:5001;
}

Reconstruisons notre déploiement avec la commande

docker-compose build

Puis lançons le déploiement

docker-compose up

Vous deviez voir tous les services se lancer de cette façon :

Creating seance5_movie4_1 ... done
Creating seance5_nginx_1  ... done
Creating seance5_movie3_1 ... done
Creating seance5_movie1_1 ... done
Creating seance5_movie2_1 ... done
Attaching to seance5_movie4_1, seance5_movie2_1, seance5_movie1_1, seance5_nginx_1, seance5_movie3_1
nginx_1   | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1   | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
movie4_1  | Server running in port 5001
movie4_1  |  * Serving Flask app 'movie' (lazy loading)
movie4_1  |  * Environment: production
movie4_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie4_1  |    Use a production WSGI server instead.
movie4_1  |  * Debug mode: off
movie4_1  |  * Running on all addresses.
movie4_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie4_1  |  * Running on http://172.19.0.2:5001/ (Press CTRL+C to quit)
nginx_1   | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx_1   | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
nginx_1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
nginx_1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
nginx_1   | /docker-entrypoint.sh: Configuration complete; ready for start up
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: using the "epoll" event method
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: nginx/1.21.4
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: OS: Linux 5.4.0-92-generic
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker processes
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 31
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 32
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 33
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 34
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 35
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 36
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 37
nginx_1   | 2022/01/09 11:18:06 [notice] 1#1: start worker process 38
movie2_1  | Server running in port 5001
movie2_1  |  * Serving Flask app 'movie' (lazy loading)
movie2_1  |  * Environment: production
movie2_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie2_1  |    Use a production WSGI server instead.
movie2_1  |  * Debug mode: off
movie2_1  |  * Running on all addresses.
movie2_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie2_1  |  * Running on http://172.19.0.3:5001/ (Press CTRL+C to quit)
movie3_1  | Server running in port 5001
movie3_1  |  * Serving Flask app 'movie' (lazy loading)
movie3_1  |  * Environment: production
movie3_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie3_1  |    Use a production WSGI server instead.
movie3_1  |  * Debug mode: off
movie3_1  |  * Running on all addresses.
movie3_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie3_1  |  * Running on http://172.19.0.6:5001/ (Press CTRL+C to quit)
movie1_1  | Server running in port 5001
movie1_1  |  * Serving Flask app 'movie' (lazy loading)
movie1_1  |  * Environment: production
movie1_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie1_1  |    Use a production WSGI server instead.
movie1_1  |  * Debug mode: off
movie1_1  |  * Running on all addresses.
movie1_1  |    WARNING: This is a development server. Do not use it in a production deployment.
movie1_1  |  * Running on http://172.19.0.4:5001/ (Press CTRL+C to quit)

Le téléchargement des images de base depuis Docker Hub peut prendre un peu de temps, c’est normal, mais une fois téléchargé vous n’aurez plus à le refaire.

Vous pouvez tester le fonctionnement de vos services movie avec les url suivantes dans votre navigateur :

http://localhost:5001/json
http://localhost:5002/json
http://localhost:5003/json
http://localhost:5004/json
http://localhost:8000/json

Les 3 premières requêtes vont partir vers les services movie dans les conteneurs qui exposent leurs ports respectifs 5001, 5002, 5003, et 5004. La dernière requête part vers nginx qui relaye la requête à l’un des 4 services dans les conteneurs.

3.3. Tests de performances

C’est maintenant à vous de jouer ! Le but de ce TP est d’étudier les performances de NGINX. Vous pouvez laisser libre cours à votre imagination pour écrire des scripts Python (ou autre) qui mettent à l’épreuve le load balancing.

Vous pouvez :

Tip
pour faire un grand nombre de requêtes par seconde vous pouvez utiliser une bibliothèque qui fera des requêtes asynchrones comme par exemple (mais sans doute d’autres) https://github.com/spyoungtech/grequests

3.4. Rendus

Je vous demande de :

  • concevoir des scripts Python (ou un autre langage) pour ces tests de performance

  • me faire un rendu de vos codes avec les instructions pour rejouer vos tests

  • un petit descriptif dans le rapport de la mise en place de vos tests et de l’analyse de vos résultats