Review the infrastructure content (and images)

This commit is contained in:
Fred Pauchet 2024-02-27 15:35:37 +01:00
parent 3d860d6a6b
commit 8fa688c380
7 changed files with 92 additions and 72 deletions

View File

@ -3,26 +3,32 @@
Linfrastructure est destinée à supporter deux types dapplications :
. Les applications consommant principalement des cycles processeur (_Compute-intensive applications_),
. Les applications consommant intensivement des données (_Data-intensive applications_). Une application consommant principalement des données est rarement limitée par la puisse du CPU, mais plus souvent par la quantité et la complexité des structures de données, et la vitesse à laquelle celles-ci doivent être échangées.
. Les applications consommant intensivement des données (_Data-intensive applications_). Une application consommant principalement des données est rarement limitée par la puissance du CPU, mais plus souvent par la quantité et la complexité des structures de données, et la vitesse à laquelle celles-ci doivent être échangées cite:[data_intensive(3)].
Au niveau des composants destinés à épauler ces applications, nous
pouvons distinguer les types suivants :
Au niveau des composants destinés à épauler ces applications, nous pouvons distinguer les types suivants :
. *Les composants fonctionnels*, ceux sans qui lapplication fonctionnerait de manière partielle, inadéquate, ou avec des temps de réponse inadaptés,
. *Les composants périphériques*, cest-à-dire les composants qui aident à avoir une architecture système résiliente, évolutive et maintenable,
*Les composants de supervision*, qui permettent de sassurer que tout fonctionne correctement, et quaucun incident nest prévu ou na été constaté récemment.
_Designing for production_ means thinking about production issues as first-class concerns: :
.Il faut voir ceci comme un gros gâteau, où la supervision est appliquée sur les étages fonctionnels et périphériques
image::infrastructure/components.drawio.png[align="center"]
* *Operations*: Security, availablity, capacity, status, communication,
* *Control plane*: Monitoring, deployment, anomaly detection, new features,
* *Interconnect*: Routing, load balancing, failover, traffic management,
* *Instances*: Services, processes, components, instance monitoring,
* *Foundation*: Hardware, VMs, IP addresses, physical network.
L'objectif est de construire une infrastructure _Production-ready_, en essayant déjà de couvrir au maximum les erreurs qui pourraient survenir.
Plus précisément :
* *Opérations*: Sécurité, disponibilité, capacité, statuts et communication.
* *Flight Control* : Monitoring, déploiements, détections d'anomalies, nouvelles fonctionnalités.
* *Interconnexions* : Routage, load balancing, failover, gestion du trafic,
* *Instances* : Services, processus, composants,
* *Fondations* : Hardware, machines virtuelles, adresses IP, réseau physique.
=== Composants fonctionnels
Une application _data-intensive_ est généralement composée des blocs fonctionnels suivants, de manière non-exhaustive :
.Une architecture possible pour un système de données moderne, qui combine plusieurs composants cite:[data_intensive(5)]
image::infrastructure/modern-infrastructure.drawio.png[align="center"]
Une application _data-intensive_ est généralement composée des blocs fonctionnels suivants, de manière non-exhaustive cite:[data_intensive(3)] :
[width="90%",cols="<23%,<61%,<16%",options="header",]
|===
@ -44,33 +50,43 @@ mots-clés ou en utilisant des filtres particuliers |ElasticSearch, Solr
==== Bases de données
==== Mise en cache
==== Caches
==== Moteurs dindexation
==== Tâches asynchrones
==== Traitements asynchrones
=== Composants périphériques
Les composants périphériques gravitent autour du fonctionnement normal de lapplication. Ce sont les "petites mains" qui aident à ce que lapplication soit résiliente ou que la charge soit amoindrie ou répartie entre plusieurs instances. Il sagit des composants comme le proxy inverse ou les distributeurs de charge: ce sont des composants qui sont fortement recommandés, mais pas obligatoires à au bon fonctionnement de lapplication.
Les composants périphériques gravitent autour du fonctionnement normal de lapplication.
Ce sont les "petites mains" qui aident à ce que lapplication soit résiliente ou que la charge soit amoindrie ou répartie entre plusieurs instances.
Il sagit des composants comme un proxy inverse ou les répartiteurs de charge : ce sont des composants qui ne sont pas pas obligatoires au bon fonctionnement de lapplication, mais fortement recommandés quand même.
____
"Focusing on resilience often means that a firm can handle events that may cause crises for most organizations in a manner that is routine and mundane.
Specific architectural patterns that they implemented includedfail fasts (settings aggressive timeouts such that failing components dont make the entire system crawl to a halt), fallbacks (designing each feature to degrade or fall back to a lower quality representation), and feature removal (removing non-critical features when they run slowly from any given page to prevent them from impacting the member experience).
Another astonishing example of the resilience that the netflix team created beyond preserving business continuity during the AWS outage, was that they went over six hours into the AWS outage before declaring a Sev 1 incident, assuming that AWS service would eventually be restored (i.e., "AWS will come back...it usually does, right ?").
Only after six hours into the outage did they activate any business continuity procedures.
____
[quote]
----
"Focusing on resilience" often means that a firm can handle events that may cause crises for most organizations in a manner that is routine and mundane cite:[devops(282)].
----
Avoir des composants périphériques correctement configurés permet danticiper ce type derreurs, et donc daugmenter la résilience de lapplication. Certaines plateformes, comme Amazon Web Services, favorisent la flexibilité et leslasticité plutôt que la disponibilité dune seule machine.
Cest donc une bonne idée de faire en sorte que des erreurs dindisponibilité peuvent arriver footnote:[Netflix a par exemple développer le https://github.com/netflix/chaosmonkey[Chaos Monkey], qui soccupe déteindre au hasard des machines virtuels et
containers dans un environnement de production, juste pour faire en sorte que les équipes soient drillées à développer toutes sortes de mécanismes de remise en service -].
Cette résilience est obtenue en applicant des schémas spécifiques, incluant notamment les modèles suivants :
* _Fail-Fast_ : Mise en place de _timeouts_ aggressifs pour que, si l'application devait planter, elle le fasse rapidement.
* _Fallbacks_ : Faire en sorte que la qualité fournie par chaque fonctionnalité puisse être dégradée, mais que cette fonctionnalité continue à tourner,
* _Feature removals_ : Autoriser à retirer certaines fonctionnalités non-critiques lorsqu'elles tournent plus lentement, afin de limiter l'impact qu'elle pourrait avoir sur l'expérience utilisateur.
Un exemple assez impressionant de résilience concerne un incident majeur qui a touché AWS en 2011.
Netflix (dont l'infrastructure tournait sur AWS) a attendu https://netflixtechblog.com/lessons-netflix-learned-from-the-aws-outage-deefe5fd0c04[six heures avant de décréter l'incident comme étant de sévérité 1].
Ils ont réussi à continuer à fournir un service (diminué, il est vrai) durant ces six heures, rien qu'en ayant anticipé la possibilité que ces composants puissent être rendus indisponibles.
Avoir des composants périphériques correctement configurés permet danticiper certaines erreurs, et donc daugmenter la résilience de lapplication.
Certaines plateformes, comme Amazon Web Services, favorisent la flexibilité et leslasticité plutôt que la disponibilité dune seule machine.
Cest donc une bonne idée de faire en sorte que des erreurs dindisponibilité peuvent arriver footnote:[Netflix a par exemple développer le https://github.com/netflix/chaosmonkey[Chaos Monkey], qui soccupe déteindre au hasard des machines virtuels et containers dans un environnement de production, juste pour faire en sorte que les équipes soient drillées à développer toutes sortes de mécanismes de remise en service.].
[width="90%",cols="<23%,<61%,<16%",options="header",]
|===
|Type |Utilité |Exemples
|Firewall | |firewalld, UFW
|Reverse Proxy | |Nginx
|Reverse Proxy | |Nginx, Apache
|Load balancers |Distribution de la charge sur plusieurs serveurs, en
fonction du nombre dutilisateurs, du nombre de requêtes à gérer et du
@ -81,16 +97,12 @@ temps que prennent chacune dentre elles |HAProxy
Si nous schématisons linfrastructure et le chemin parcouru par une requête, nous pourrions arriver à la synthèse suivante :
. Lutilisateur fait une requête via son navigateur (Firefox ou Chrome)
. Le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et éventuellement du contenu
. Le firewall du serveur (Debian GNU/Linux, CentOS, ...vérifie si la requête peut être prise en compte
. La requête est transmise à lapplication qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx)
. Elle est ensuite transmise par socket et est prise en compte par un
des _workers_ (= un processus Python) instancié par Gunicorn. Silun de
ces travailleurs venait à planter, il serait automatiquement réinstancié
par Supervisord.
. Qui la transmet ensuite à lun de ses _workers_ (= un processus
Python).
. Lutilisateur fait une requête via son navigateur (Firefox ou Chrome),
. Le navigateur envoie une requête http, sa version, un verbe (GET, POST, ...), un port et contenu,
. Le firewall du serveur (Debian GNU/Linux, CentOS, ...vérifie si la requête peut être prise en compte,
. La requête est transmise à lapplication qui écoute sur le port (probablement 80 ou 443; et _a priori_ Nginx),
. Elle est ensuite transmise par socket et est prise en compte par un des _workers_ (= un processus Python) instancié par Gunicorn. Si lun de ces travailleurs venait à planter, il serait automatiquement réinstancié par Supervisord,
. Qui la transmet ensuite à lun de ses _workers_ (= un processus Python),
. Après exécution, une réponse est renvoyée à lutilisateur.
image:infrastructure/architecture.png[align="center"]
@ -172,29 +184,6 @@ Chaque évènement est associé à un niveau; celui-ci indique sa criticité et
* *ERROR*: Indique les informations internes - Erreur lors de lappel dune API, erreur interne, ...
* *FATAL* (ou *EXCEPTION*): ...généralement suivie dune terminaison du programme - Bind raté dun socket, etc.
La configuration des _loggers_ est relativement simple, un peu plus complexe si nous nous penchons dessus, et franchement complète si nous creusons encore. Il est ainsi possible de définir des formattages, différents gestionnaires (_handlers_) et loggers distincts, en fonction de nos applications.
Sauf que comme nous lavons vu avec les 12 facteurs, nous devons traiter les informations de notre application comme un flux dévènements.
Ilnest donc pas réellement nécessaire de chipoter la configuration, puisque la seule classe qui va réellement nous intéresser concerne les `StreamHandler`, qui seront pris en charge par gunicorn .
La configuration que nous allons utiliser est celle-ci :
. *Formattage*: à définir - mais la variante suivante est complète, lisible et pratique:
`{levelname} {asctime} {module} {process:d} {thread:d} {message}`
. *Handler*: juste un, qui définit un `StreamHandler`
. *Logger*: pour celui-ci, nous avons besoin dun niveau (`level`) et de savoir sil faut propager les informations vers les sous-paquets, auquel cas il nous suffira de fixer la valeur de `propagate` à `True`.
Pour utiliser nos loggers, il suffit de copier le petit bout de code suivant :
[source,python]
----
import logging
logger = logging.getLogger(__name__)
logger.debug('helloworld')
----
https://docs.djangoproject.com/en/stable/topics/logging/#examples[Par exemples].
==== Télémétrie et exploitation des journaux
Des erreurs sur un environnement de production arriveront, tôt ou tard, et seront sans doute plus compliquée à corriger quun morceau de code dans un coin du code. Lexploitation des journaux permettra de comprendre, analyser, voire corriger, certains incidents.
@ -206,12 +195,12 @@ Comme nous lavons vu, en fonction de linfrastructure choisie, il existe pl
. Les journaux des autres composants: base de données, service de mise en cache, ...
Une manière de faire consiste à se connecter physiquement ou à distance à la machine pour analyser les logs.
En pratique, cest impossible : entre les répartiteurs de charge, les différents serveurs, ..., il vous sera physiquement impossible de récupérer une information cohérente.
La solution consiste à agréger vos journaux à un seul et même endroit:
En pratique, cest impossible : entre les répartiteurs de charge, les différents serveurs, ..., il vous sera impossible de récupérer une information cohérente, croisée entre tous les différents composants.
La solution consiste à agréger vos journaux à un seul et même endroit :
image:infrastructure/mattsegal-logging.png[[align="center"]]
.mattsegal.dev/django-monitoring-stack.html
image::infrastructure/mattsegal-logging.png[[align="center"]]
CC https://mattsegal.dev/django-monitoring-stack.html
==== Sumologic

View File

@ -216,8 +216,8 @@ image::django/admin/django-list_display.png[align="center"]
[WARNING]
====
Il n'est pas possible d'afficher tout et n'importe quoi sans un peu de configuration.
Par exemple, si nous souhaitons afficher le nom de la liste dont dépend l'élément ou une propriété relative, il est nécessaire de passer par une méthode au niveau de la classe d'administration.
Il n'est pas possible d'afficher tout et n'importe quoi sans un minimum de configuration.
Par exemple, si nous souhaitons afficher le nom de la liste dont dépend l'élément ou une propriété relative, il est nécessaire d'ajouter une méthode au niveau de la classe d'administration.
```python
@ -228,7 +228,6 @@ class ItemAdmin(admin.ModelAdmin):
list_display = ("__str__", "wishlist_name") <2>
```
<1> Nous définissons une méthode `wishlist_name`
<2> à laquelle nous faisons référence dans la propriété `list_display`.
@ -299,24 +298,29 @@ Idem pour les filtres verticaux, qui se basent également des champs de type `Ma
===== Conclusions
Les différents filtres disponibles permettent de créer rapidement des facettes, telles que nous pouvons les trouver sur des moteurs de recherche récents.
Ces filtres restent limités, mais peuvent être mis en place _très_ rapidement, et offrent ainsi une interface facile à mettre en place, tout en offrant quelques fonctionnalités de base personnalisées, sans avoir à dégainer un outil d'accès à des données relationelles comme PgAdmin ou MySQLAdmin).
==== Affichage des détails d'un élément
Le fonctionnement habituel d'une application est d'afficher un ensemble d'éléments, puis d'autoriser la sélection d'un élément en particulier pour agir dessus, soit en l'affichant, soit en le modifiant, soit en le supprimant.
L'administration étant orientée sur la gestion des données, l'affichage n'est pas géré ; il est donc possible de supprimer un élement ou de le modifier.
Cette section se concentre sur la modification.
. Un formulaire de modification par défaut pour un élément dans l'administration
image::django/admin/item-display.png[align="center"]
*... montrer le regroup_by et les collapse.*
=== Permissions
On la dit plus haut, il vaut mieux éviter de proposer un accès à
ladministration à vos utilisateurs. Il est cependant possible de
configurer des permissions spécifiques pour certains groupes, en leur
autorisant certaines actions de visualisation/ajout/édition ou
suppression.
On la dit plus haut, il vaut mieux éviter de proposer un accès à ladministration à vos utilisateurs. Il est cependant possible de configurer des permissions spécifiques pour certains groupes, en leur autorisant certaines actions de visualisation/ajout/édition ou suppression.
Cela se joue au niveau du `ModelAdmin`, en implémentant les méthodes
suivantes:
Cela se joue au niveau du `ModelAdmin`, en implémentant les méthodes suivantes:
[source,python]
----

View File

@ -366,7 +366,7 @@ Après application de notre contexte sur ce template, nous obtiendrons ce docume
----
.Résultat
image::django/django-first-template.png[images/django/django-first-template]
image::django/django-first-template.png[align="center"]
=== Conclusions

View File

@ -616,6 +616,33 @@ Traduit rapidement à partir de la langue de Batman :
Mais la partie réellement intéressante concerne le fait que
"`Tout code qui sera passé par Black aura la même forme, indépendamment du project sur lequel vous serez en train de travailler. Létape de formatage deviendra transparente, et vous pourrez vous concentrer sur le contenu`".
=== Loggers
La configuration des _loggers_ peut être relativement simple, un peu plus complexe si nous nous penchons dessus, et franchement complète si nous creusons encore.
Il est ainsi possible de définir des formattages, différents gestionnaires (_handlers_) et loggers distincts, en fonction de nos applications.
Sauf que comme nous lavons vu lors du chapitre sur les 12 facteurs, il vaut mieux traiter l'ensemble des informations de notre application comme des flux dévènements.
Il nest donc pas réellement nécessaire de beaucoup chipoter la configuration, puisque la seule classe qui va réellement nous intéresser concerne les `StreamHandler`, qui seront pris en charge par gunicorn.
La configuration que nous allons utiliser est celle-ci :
. *Formattage*: à définir - mais la variante suivante est complète, lisible et pratique:
`{levelname} {asctime} {module} {process:d} {thread:d} {message}`
. *Handler*: juste un, qui définit un `StreamHandler`
. *Logger*: pour celui-ci, nous avons besoin dun niveau (`level`) et de savoir sil faut propager les informations vers les sous-paquets, auquel cas il nous suffira de fixer la valeur de `propagate` à `True`.
Pour utiliser nos loggers, il suffit de copier le petit bout de code suivant :
[source,python]
----
import logging
logger = logging.getLogger(__name__)
logger.debug('helloworld')
----
https://docs.djangoproject.com/en/stable/topics/logging/#examples[Par exemples].
=== Typage statique
Nous vous disions ci-dessus que Python est un langage dynamique interprété.

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB