Proposer des services connectés fait souvent partie du coeur de métier de notre travail. Nécessitant parfois d’importantes ressources de calcul, de présentation, de communication, on se retrouve rapidement à instancier des systèmes informatiques. Un ajout de service pour l’intranet, une interface web, des APIs et des bases de données,… et ce très facilement, que ce soit via des machines virtuelles ou des conteneurs.

RTE, responsable du transport de l’électricité sur le territoire Français, propose une ressource en ligne indiquant la criticité du réseau. Elle est estimée plusieurs jours à l’avance. Si le réseau se trouve très contraint par une demande supérieure à la production, des coupures temporaires peuvent être réalisées. L’entreprise recommande déjà de diminuer sa propre consommation de 5 voire 15 points lors de situations météorologiques extrèmes. À des fins informatives et pour assumer au mieux la réduction de consommation, RTE a mis en place “le signal EcoWatt”.

Mon EcoWatt

Récupération du signal

Une API[2] est disponible pour récupérer programmatiquement le statut du réseau et en connaître l’état instantané. Après une création de compte, on retrouvera une documentation[3], qui indiquera les modalités de connexion. Une authentification OAuth2 avec une limite de requête toutes les 15 minutes. Deux requêtes sont donc à réaliser :

  • HTTP/POST avec des headers Content-Type et Authorization Basic pour récupérer le token d’authentification,
  • HTTP/GET avec des headers Content-Type et Authorization Bearer pour accéder au signal.

Dans la mesure où l’on ne maintient pas de connexion, on doit établir une requête à chaque fois que l’on souhaite prendre connaissance du signal. Rappelons que l’estimation est quotidienne ; une requête par jour peut s’avérer suffisante. Voici un exemple de script.

Actions conditionnelles

Consommation logicielle

Mais c’est bien la maitrise de la consommation logicielle qui est intéressante dans notre cas. Déterminer l’énergie utilisée par les applications logicielles est un vaste sujet, dont seules les approximations nous permettent de faire des choix. Dans le secteur des systèmes embarqués, on peut mesurer directement en tête de système la consommation instantanée et précisément observer les changements d’état – de power mode, mais pour un système plus complexe tel qu’un serveur GNU/Linux, l’identification de processus spécifiques reste non triviale. Quelques logiciels proposent des calculs réels pour approximer la consommation de chaque processus d’une machine, tels que Scaphandre[4], qui se base sur l’allocation des jiffies.

On note que quelque soit la méthode de calcul, une corrélation semble inévitable : plus le temps CPU est utilisé, plus la consommation augmente.

Design logiciel

Une réponse technique réside dans le design des logiciels, dans leur capacité à utiliser efficacement les ressources matérielles. En optimisant l’empreinte mémoire et les besoins de calcul – avec par exemple asyncio, une meilleure gestion des threads, un accès à la mémoire moins gourmand…

Mais l’approche ici est quelque peu différente car on pourrait souhaiter limiter la consommation énergétique, et ce temporairement. Cette contrainte impacte également la manière de scaler, de passer à l’échelle et de déployer des services pour dix ou cent fois leur capacité initiale.

Asservissement système

Dans mon écosystème de micro-services quotidien – Docker, la configuration des services donne le contrôle sur le temps CPU disponible. Avec la bibliothèque Python pour Docker[5], on peut donc programmatiquement altérer la configuration système de chaque conteneur qui s’exécute. L’extrait de la documentation mentionne plusieurs paramètres à moduler.

update(**kwargs)
    Update resource configuration of the containers.
    Parameters
            blkio_weight (int) – Block IO (relative weight), between 10 and 1000
            cpu_period (int) – Limit CPU CFS (Completely Fair Scheduler) period
            cpu_quota (int) – Limit CPU CFS (Completely Fair Scheduler) quota
            cpu_shares (int) – CPU shares (relative weight)
            cpuset_cpus (str) – CPUs in which to allow execution
            cpuset_mems (str) – MEMs in which to allow execution
            mem_limit (int or str) – Memory limit
            mem_reservation (int or str) – Memory soft limit
            memswap_limit (int or str) – Total memory (memory + swap), -1 to disable swap
            kernel_memory (int or str) – Kernel memory limit
            restart_policy (dict) – Restart policy dictionary
    Returns
        Dictionary containing a Warnings key.
    Return type
        (dict)
    Raises
        docker.errors.APIError – If the server returns an error.

Tous les paramètres ne nous sont pas nécessaires. En se concentrant sur period, quota et cpus, on peut limiter l’exécution de conteneurs de deux manières.

  • cpu_period et cpu_quota : en spécifiant un quota par rapport à la period, on fournit un ratio d’utilisation de CPU.

  • cpuset_cpus : il est sinon possible de spécifier exactement quels CPUs utiliser, le premier et le troisième par exemple 0,2, comme les quatre premiers 0-3, dont voici un exemple de script.

Branchement

Une fois que nous pouvons modifier volontairement notre consommation énergétique, le branchement entre le signal EcoWatt déclencheur et le script opérationnel peut se réaliser. Il ne sera pas décrit ici. Il s’agit-là de mettre en forme un connecteur entre la sortie du signal EcoWatt et la mise à jour de la configuration CPU. Les limites CPU en fonction du signal seront donc à établir, et dans un premier temps à qualifier : pour diminuer mon impact de 5%, quelles valeurs limites sont à spécifier ?

Conclusion

  • L’impact de nos développements et déploiements et leur utilisation des ressources matérielles.
  • Comment limiter la consommation logicielle ? L’idée ici est de compter sur la plateforme Docker qui va ensuite déléguer ces contraintes au kernel Linux. Notons que d’autres plateformes permettent cette configuration, comme Kubernetes[6].
  • Établir une hiérarchie des services à conserver selon les niveaux de criticité : vaut-il mieux limiter tous les services ou en arrêter certains au profit d’autres ? Dans le cadre d’un produit logiciel en SaaS, qu’est-il possible de faire contractuellement ?

⚠️ Note : ce mode opératoire n’est pas dédié pour un environnement de production.


Ressources :

[0] https://www.rte-france.com/actualites/previsions-systeme-electrique-hiver-2022-2023

[1] https://monecowatt.fr

[2] https://data.rte-france.com/catalog/-/api/consumption/Ecowatt/v4.0

[3] https://data.rte-france.com/catalog/-/api/doc/user-guide/Ecowatt/4.0

[4] https://hubblo-org.github.io/scaphandre-documentation/explanations/how-scaph-computes-per-process-power-consumption.html

[5] https://docker-py.readthedocs.io/en/stable/containers.html#docker.models.containers.Container.update

[6] https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/#specify-a-cpu-request-and-a-cpu-limit