Add appendices
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
9e8b04ef5e
commit
0c2aeee91e
|
@ -1,19 +1,27 @@
|
|||
\chapter{Infrastructure et composants}
|
||||
|
||||
Deux types d'applications peuvent être considérées: les applications consommant intensivement des données (\textit{Data-intensive applications}) et les applications consommant principalement des cycles processeur (\textit{Compute-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. \cite[p. 3]{data_intensive}
|
||||
|
||||
\section{Composants}
|
||||
|
||||
Nous pouvons distinguer plusieurs types de composants:
|
||||
L'infrastructure est destinée à supporter deux types d'applications:
|
||||
|
||||
\begin{enumerate}
|
||||
\item \textbf{Les composants fonctionnels}, ceux sans qui l'application fonctionnerait de manière partielle, inadéquate, ou avec des temps de réponse inadapté
|
||||
\item \textbf{Les composants périphériques}, c'est-à-dire les composants qui aident à avoir une architecture système résiliente, évolutive et maintenable
|
||||
\item \textbf{Les composants de supervision}, qui permettent de s'assurer que tout fonctionne correctement, et qu'aucun incident n'est prévu ou n'a été constaté récemment.
|
||||
\item
|
||||
Les applications consommant principalement des cycles processeur (\textit{Compute-intensive applications}).
|
||||
\item
|
||||
Les applications consommant intensivement des données (\textit{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. \cite[p. 3]{data_intensive}
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Composants fonctionnels}
|
||||
Au niveau des composants destinés à épauler ces applications, nous pouvons distinguer les types suivants:
|
||||
|
||||
\begin{enumerate}
|
||||
\item
|
||||
\textbf{Les composants fonctionnels}, ceux sans qui l'application fonctionnerait de manière partielle, inadéquate, ou avec des temps de réponse inadapté
|
||||
\item
|
||||
\textbf{Les composants périphériques}, c'est-à-dire les composants qui aident à avoir une architecture système résiliente, évolutive et maintenable
|
||||
\item
|
||||
\textbf{Les composants de supervision}, qui permettent de s'assurer que tout fonctionne correctement, et qu'aucun incident n'est prévu ou n'a été constaté récemment.
|
||||
\end{enumerate}
|
||||
|
||||
\section{Composants fonctionnels}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
|
@ -37,13 +45,13 @@ Une application \textit{data-intensive} est généralement composée des blocs f
|
|||
\hline
|
||||
\end{tabular}
|
||||
|
||||
\subsubsection{Bases de données}
|
||||
\subsection{Bases de données}
|
||||
|
||||
\subsubsection{Tâches asynchrones}
|
||||
\subsection{Tâches asynchrones}
|
||||
|
||||
\subsubsection{Mise en cache}
|
||||
\subsection{Mise en cache}
|
||||
|
||||
\subsection{Composants périphériques}
|
||||
\section{Composants périphériques}
|
||||
|
||||
Les composants périphériques gravitent autour du fonctionnement normal de l'application.
|
||||
Ce sont les "petites mains" qui aident à ce que l'application soit résiliente ou que la charge soit amoindrie ou répartie entre plusieurs instances.
|
||||
|
@ -99,40 +107,46 @@ Si nous schématisons l'infrastructure et le chemin parcouru par une requête, n
|
|||
|
||||
\includegraphics{images/diagrams/architecture.png}
|
||||
|
||||
\subsubsection{Firewall}
|
||||
\subsection{Firewall}
|
||||
|
||||
|
||||
\subsubsection{Reverse proxy}
|
||||
\subsection{Reverse proxy}
|
||||
|
||||
Le principe du \textbf{proxy inverse} est de pouvoir rediriger du trafic entrant vers une application hébergée sur le système. Il serait tout à fait possible de rendre notre application directement accessible depuis l'extérieur, mais le proxy a aussi l'intérêt de pouvoir élever la sécurité du serveur (SSL) et décharger le serveur applicatif grâce à un mécanisme de cache ou en compressant certains résultats \footnote{\url{https://fr.wikipedia.org/wiki/Proxy_inverse}}
|
||||
|
||||
\subsubsection{Répartiteur de charge (\textit{Load balancer})}
|
||||
\subsection{Répartiteur de charge (\textit{Load balancer})}
|
||||
|
||||
Les répartiteurs de charges sont super utiles pour donner du mou à l'infrastructure:
|
||||
|
||||
\begin{enumerate}
|
||||
\item Maintenance et application de patches,
|
||||
\item Répartition des utilisateurs connectés,
|
||||
\item \ldots
|
||||
\item
|
||||
Maintenance et application de patches,
|
||||
\item
|
||||
Répartition des utilisateurs connectés,
|
||||
\item
|
||||
\ldots
|
||||
\end{enumerate}
|
||||
|
||||
\subsubsection{Serveurs d'application (\textit{Workers})}
|
||||
\subsection{Serveurs d'application (\textit{Workers})}
|
||||
|
||||
Processus et threads.
|
||||
|
||||
Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive dans les mains du processus Python, qui doit encore
|
||||
|
||||
\begin{enumerate}
|
||||
\item effectuer le routage des données,
|
||||
\item trouver la bonne fonction à exécuter,
|
||||
\item récupérer les données depuis la base de données,
|
||||
\item effectuer le rendu ou la conversion des données,
|
||||
\item et renvoyer une réponse à l'utilisateur.
|
||||
\item
|
||||
Effectuer le routage des données,
|
||||
\item
|
||||
Trouver la bonne fonction à exécuter,
|
||||
\item
|
||||
Récupérer les données depuis la base de données,
|
||||
\item
|
||||
Effectuer le rendu ou la conversion des données,
|
||||
\item
|
||||
Renvoyer une réponse à l'utilisateur.
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
|
||||
\subsection{Composants de supervision}
|
||||
\section{Composants de supervision}
|
||||
|
||||
\begin{tabular}{|p{0.2\linewidth}|p{0.55\linewidth}|p{0.15\linewidth}|}
|
||||
\hline
|
||||
|
@ -146,12 +160,12 @@ Au niveau logiciel (la partie mise en subrillance ci-dessus), la requête arrive
|
|||
\hline
|
||||
\end{tabular}
|
||||
|
||||
\subsubsection{Supervision des processus}
|
||||
\subsection{Supervision des processus}
|
||||
|
||||
https://circus.readthedocs.io/en/latest/, https://uwsgi-docs.readthedocs.io/en/latest/, statsd
|
||||
|
||||
|
||||
\subsubsection{Journaux}
|
||||
\subsection{Journaux}
|
||||
|
||||
La présence de journaux, leur structure et de la définition précise de leurs niveaux est essentielle; ce sont eux qui permettent d'obtenir des informations quant au statut de l'application:
|
||||
|
||||
|
@ -171,20 +185,20 @@ Low printer toner is not an ERROR.
|
|||
Chaque évènement est associé à un niveau; celui-ci indique sa criticité et sa émet un premier tri quant à sa pertinence.
|
||||
|
||||
\begin{itemize}
|
||||
\item
|
||||
\textbf{DEBUG}: Il s'agit des informations qui concernent tout ce qui peut se passer durant l'exécution de l'application.
|
||||
Généralement, ce niveau est désactivé pour une application qui passe en production, sauf s'il est nécessaire d'isoler un comportement en particulier, auquel cas il suffit de le réactiver temporairement.
|
||||
\item
|
||||
\textbf{INFO}: Enregistre les actions pilotées par un utilisateur - Démarrage de la transaction de paiement, \ldots
|
||||
\item
|
||||
\textbf{WARN}: Regroupe les informations qui pourraient potentiellement devenir des erreurs.
|
||||
\item
|
||||
\textbf{ERROR}: Indique les informations internes - Erreur lors de l'appel d'une API, erreur interne, \ldots
|
||||
\item
|
||||
\textbf{FATAL} (ou \textbf{EXCEPTION}): \ldots généralement suivie d'une terminaison du programme - Bind raté d'un socket, etc.
|
||||
\item
|
||||
\textbf{DEBUG}: Il s'agit des informations qui concernent tout ce qui peut se passer durant l'exécution de l'application.
|
||||
Généralement, ce niveau est désactivé pour une application qui passe en production, sauf s'il est nécessaire d'isoler un comportement en particulier, auquel cas il suffit de le réactiver temporairement.
|
||||
\item
|
||||
\textbf{INFO}: Enregistre les actions pilotées par un utilisateur - Démarrage de la transaction de paiement, \ldots
|
||||
\item
|
||||
\textbf{WARN}: Regroupe les informations qui pourraient potentiellement devenir des erreurs.
|
||||
\item
|
||||
\textbf{ERROR}: Indique les informations internes - Erreur lors de l'appel d'une API, erreur interne, \ldots
|
||||
\item
|
||||
\textbf{FATAL} (ou \textbf{EXCEPTION}): \ldots généralement suivie d'une terminaison du programme - Bind raté d'un socket, etc.
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Flux d'évènements}
|
||||
\subsection{Flux d'évènements}
|
||||
|
||||
La configuration des \emph{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 (\emph{handlers}) et loggers distincts, en fonction de nos applications.
|
||||
|
@ -217,7 +231,7 @@ Pour utiliser nos loggers, il suffit de copier le petit bout de code suivant:
|
|||
\href{https://docs.djangoproject.com/en/stable/topics/logging/\#examples}{Par
|
||||
exemples}.
|
||||
|
||||
\subsubsection{Exploitation des journaux, télémétrie}
|
||||
\subsection{Exploitation des journaux, télémétrie}
|
||||
|
||||
Des erreurs sur un environnement de production arriveront, tôt ou tard, et seront sans doute plus compliquée à corriger qu'un morceau de code dans un coin du code.
|
||||
L'exploitation des journaux permettra de comprendre, analyser, voire corriger, certains incidents.
|
||||
|
@ -238,9 +252,9 @@ La solution consiste à agréger vos journaux à un seul et même endroit:
|
|||
|
||||
CC https://mattsegal.dev/django-monitoring-stack.html
|
||||
|
||||
\subsubsection{Sumologic}
|
||||
\subsection{Sumologic}
|
||||
|
||||
\subsubsection{Alternatives}
|
||||
\subsection{Alternatives}
|
||||
|
||||
Il existe également \href{https://munin-monitoring.org}{Munin}, \href{https://www.elastic.co}{Logstash, ElasticSearch et Kibana (ELK-Stack)} ou \href{https://www.fluentd.org}{Fluentd}.
|
||||
|
||||
|
@ -276,6 +290,6 @@ Histoire de schématiser, toute équipe se retrouve à un moment où un autre da
|
|||
Et pour cause: une fois que nous aurons trouvé une joyeuse victime qui osera braver le danger, il y aura systématiquement des imprévus, des petits détails qui auront été oubliés sur le côté de la route, et qui feront lâchement planter les environnements.
|
||||
Et puisque nous n'aurons pas (encore) de télémétrie, le seul moment où nous comprendrons qu'il y a un problème, sera quand un utilisateur viendra se plaindre.
|
||||
|
||||
\subsubsection{Statsd}
|
||||
\subsection{Statsd}
|
||||
|
||||
https://www.datadoghq.com/blog/statsd/
|
||||
|
|
|
@ -700,6 +700,9 @@ que son propre identifiant:
|
|||
COMMIT;
|
||||
\end{minted}
|
||||
|
||||
Une bonne pratique consiste à ajouter un "autre" identifiant pour un modèle susceptible d'être interrogé.
|
||||
Nous pensons ici à un UUID ou à un slug \index{slug}, qui permettrait d'avoir une sorte de clé sémantique associée à un object; ceci évite également d'avoir des identifiants qui soient trop facilement récupérables.
|
||||
|
||||
\subsection{Héritage classique}
|
||||
|
||||
L'héritage classique est généralement déconseillé, car il peut
|
||||
|
|
|
@ -158,6 +158,7 @@ C'est en ça que consistent les \href{https://www.djangopackages.com/}{paquets D
|
|||
ce sont "\emph{simplement}" de petites applications empaquetées et pouvant être réutilisées dans différents contextes (eg. \href{https://github.com/tomchristie/django-rest-framework}{Django-Rest-Framework}, \href{https://github.com/django-debug-toolbar/django-debug-toolbar}{Django-Debug-Toolbar}, \ldots
|
||||
|
||||
Le projet s'occupe principalement d'appliquer une couche de glue entre différentes applications.
|
||||
Une bonne pratique consiste à \textbf{limiter à cinq} le nombre de modèles différents dans chaque application.
|
||||
|
||||
\subsection{manage.py}
|
||||
|
||||
|
@ -691,6 +692,12 @@ En continuant de cette manière (ie. Ecriture du code et des tests, vérificatio
|
|||
A noter que tester le modèle en lui-même (ses attributs ou champs) ou des composants internes à Django n'a pas de sens: cela reviendrait à mettre en doute son fonctionnement interne.
|
||||
Selon le principe du SRP \ref{SRP}, c'est le framework lui-même qui doit en assurer la maintenance et le bon fonctionnement.
|
||||
|
||||
\section{Licence}
|
||||
|
||||
Choisissez une licence!
|
||||
Si votre projet n'a aucune licence, vous pourriez être tenu responsable.
|
||||
En cas de désastre médical ou financier, cela peut faire toute la différence.
|
||||
|
||||
\section{Conclusions}
|
||||
|
||||
Comme nous l'avons vu dans la première partie, Django est un framework complet, intégrant tous les mécanismes nécessaires à la bonne évolution d'une application.
|
||||
|
|
|
@ -84,7 +84,14 @@ De cette manière, dans nos templates, on peut à présent construire un lien ve
|
|||
<a href="{% url 'wishlists' %}">{{ yearvar }} Archive</a>
|
||||
\end{minted}
|
||||
|
||||
De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, de la manière suivante:
|
||||
De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, d'une des deux manières suivantes:
|
||||
|
||||
\begin{minted}{python}
|
||||
from django.urls import reverse
|
||||
|
||||
wishlists_url = reverse('wishlists')
|
||||
\end{minted}
|
||||
|
||||
|
||||
\begin{minted}{python}
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
|
|
@ -9,3 +9,22 @@ Les fonctions
|
|||
|
||||
\section{Classes}\label{CBV}
|
||||
|
||||
Les \textit{Class Based Views} ne sont jamais que des classes qui encapsulent certains comportements, comme nous l'avons vu en (cf. \#).
|
||||
La classe présentant le comportement le plus proche d'une fonction est la classe \texttt{View} que l'on trouve dans le paquet \texttt{django.views.generic}:
|
||||
|
||||
\begin{minted}{python}
|
||||
from django.views.generic import View
|
||||
|
||||
|
||||
class WishListView(View):
|
||||
def get(self):
|
||||
pass
|
||||
|
||||
def post(self):
|
||||
pass
|
||||
|
||||
\end{minted}
|
||||
|
||||
Le premier avantage des \textit{CBVs} est de pouvoir isoler les conditions liées au type de méthode HTTP \texttt{if request.method == "GET": ... elif request.method == "POST": ...}
|
||||
|
||||
La principale \textit{cheat-sheet} est \href{https://ccbv.co.uk/}{Django Class-Based View inspector}.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<mxfile host="Electron" modified="2022-05-23T10:59:53.794Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/16.5.1 Chrome/96.0.4664.110 Electron/16.0.7 Safari/537.36" etag="Ck-ryfskyNGh9GZ3a6UR" version="16.5.1" type="device"><diagram id="uHdZmcEhaC1admDXuta1" name="Page-1">zZdNb6MwEIZ/DdpTJcCEkGOafkpbrXYjdXurLDwNVg1GZlzI/vo1wYQgt1V7aOGC7HfGH/PYjG2PbPLmWtEyu5MMhBf6rPHIhReGCVmYbyvsrRAnnbBTnHVSMAhb/g+s6FtVcwbVyBGlFMjLsZjKooAURxpVStZjtycpxqOWdAeOsE2pcNW/nGFmowiXg34DfJf1IwfxqrPktHe2kVQZZbI+kcilRzZKSuxKebMB0bLruXTtrt6wHiemoMCPNCjWv5T27x+SR33z+4zK2+XP9Vlk43ihQtuI7Wxx3yNQUhcM2l58j5zXGUfYljRtrbVZc6NlmAtTC0zRdgcKoXlzosExfLNtQOaAam9cbIPYArM7Zmmr9YA/iKyWnaAnvSO1S7479jxQMQUL5jOQEgfSuiwFTylyWVTvAAu+BdhyDCx5BVj4GrAv47VyeF2Y39PbEG+9gtnxOsKZDNjCd4D90QXyHGbHKp6cVeCwuuOMCahNTHPDFfqT4wodXNt9hYd/MWn3l89+QFMKyfGQzWZHMJqcIHEI3nOFmgpezRPZ5AfAInI3HagX0Gp2yZ9Mn/wXLiyU6XN7MZ0brOmzf+yelN29ogKq58Yr+sL0b6rD2+FgO3mAkcv/</diagram></mxfile>
|
6
main.tex
6
main.tex
|
@ -91,6 +91,12 @@
|
|||
|
||||
\chapter{Conclusions}
|
||||
|
||||
\appendix
|
||||
|
||||
\part{Annexes}
|
||||
|
||||
\chapter{Grafana}
|
||||
|
||||
\backmatter
|
||||
|
||||
\part{Ressources}
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
@book{boring_stuff,
|
||||
title = {Automate the Boring Stuff with Python},
|
||||
booktitle = {Practical Programming For Total Beginners},
|
||||
author = {Al Sweigart},
|
||||
year = {2020},
|
||||
editor = {No Starch Press},
|
||||
publisher = {William Pollock},
|
||||
edition = {2nd edition}
|
||||
}
|
||||
@book{clean_architecture,
|
||||
title = {Clean Architecture, A Craftman's Guide to Software Structure and Design},
|
||||
author = {Robert C. Martin},
|
||||
|
@ -6,12 +15,6 @@
|
|||
year = {2018},
|
||||
type = {Book}
|
||||
}
|
||||
@book{other_side,
|
||||
author = {Aurélie Jean},
|
||||
title = {De l'autre côté de la machine},
|
||||
year = {2020},
|
||||
publisher = {Editions de l'Observatoire},
|
||||
}
|
||||
@book{clean_code,
|
||||
title = {Clean Code, a Handbook of Agile Software Craftmanship},
|
||||
author = {Robert C. Martin},
|
||||
|
@ -20,6 +23,13 @@
|
|||
year = {2009},
|
||||
type = {Book}
|
||||
}
|
||||
@book{devops_handbook,
|
||||
title = {The DevOps Handbook, How to create World-class Agility, Reliability and Security in Technology Organizations},
|
||||
author = {Gene Kim and Jez Humble and Patrick Debois and John Willis},
|
||||
publisher = {IT Revolution},
|
||||
year = {2016},
|
||||
type = {Book}
|
||||
}
|
||||
@book{expert_python,
|
||||
title = {Expert Python Programming},
|
||||
author = {Jaworski, Michal and Ziadé, Tarek},
|
||||
|
@ -28,21 +38,11 @@
|
|||
edition = {4th edition},
|
||||
type = {Book}
|
||||
}
|
||||
@book{devops_handbook,
|
||||
title = {The DevOps Handbook, How to create World-class Agility, Reliability and Security in Technology Organizations},
|
||||
author = {Gene Kim and Jez Humble and Patrick Debois and John Willis},
|
||||
publisher = {IT Revolution},
|
||||
year = {2016},
|
||||
type = {Book}
|
||||
}
|
||||
@book{boring_stuff,
|
||||
title = {Automate the Boring Stuff with Python},
|
||||
booktitle = {Practical Programming For Total Beginners},
|
||||
author = {Al Sweigart},
|
||||
@book{other_side,
|
||||
author = {Aurélie Jean},
|
||||
title = {De l'autre côté de la machine},
|
||||
year = {2020},
|
||||
editor = {No Starch Press},
|
||||
publisher = {William Pollock},
|
||||
edition = {2nd edition}
|
||||
publisher = {Editions de l'Observatoire},
|
||||
}
|
||||
@book{maintainable_software,
|
||||
title = {Building Maintainable Software},
|
||||
|
|
Loading…
Reference in New Issue