\chapter{Infrastructure et composants}

\begin{figure}[H]
  \centering
  \scalebox{1.0}{\includegraphics[max size={\textwidth}{\textheight}]{images/diagrams/infrastructure.drawio.png}}
  \caption{Une architecture possible pour un système de données, qui combine plusieurs composants \cite[p. 5]{data_intensive}}
\end{figure}

Pour une mise ne production, le standard \emph{de facto} est le suivant:

\begin{itemize}
\item
  Nginx comme reverse proxy
\item
  HAProxy pour la distribution de charge
\item
  Gunicorn ou Uvicorn comme serveur d'application
\item
  Supervisor pour le monitoring
\item
  PostgreSQL ou MySQL/MariaDB comme bases de données.
\item
  Celery et RabbitMQ pour l'exécution de tâches asynchrones
\item
  Redis / Memcache pour la mise à en cache (et pour les sessions ? A
  vérifier).
\item
  Sentry, pour le suivi des bugs
\end{itemize}

Si nous schématisons l'infrastructure et le chemin parcouru par une requête, nous pourrions arriver à la synthèse suivante:

\begin{enumerate}
\item
  L'utilisateur fait une requête via son navigateur (Firefox ou Chrome)
\item
  Le navigateur envoie une requête http, sa version, un verbe (GET,
  POST, \ldots\hspace{0pt}), un port et éventuellement du contenu
\item
  Le firewall du serveur (Debian GNU/Linux, CentOS, ...
  vérifie si la requête peut être prise en compte
\item
  La requête est transmise à l'application qui écoute sur le port
  (probablement 80 ou 443; et \emph{a priori} Nginx)
\item
  Elle est ensuite transmise par socket et est prise en compte par un
  des \emph{workers} (= un processus Python) instancié par Gunicorn. Si
  l'un de ces travailleurs venait à planter, il serait automatiquement
  réinstancié par Supervisord.
\item
  Qui la transmet ensuite à l'un de ses \emph{workers} (= un processus
  Python).
\item
  Après exécution, une réponse est renvoyée à l'utilisateur.
\end{enumerate}

\includegraphics{images/diagrams/architecture.png}


\section{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}}

\section{Load balancer}

\section{Workers}

\section{Supervision des processus}

\section{Bases de données}

\section{Tâches asynchrones}

\section{Mise en cache}

\section{Niveau application}

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.
\end{enumerate}

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. Il est possible de démarrer petit, et de suivre l'évolution des besoins en fonction de la charge estimée ou ressentie, d'ajouter un mécanisme de mise en cache, des logiciels de suivi, ...

\section{Supervision globale}


\subsection{Journaux}

La structure des niveaux de journaux est essentielle.

\begin{quote}
When deciding whether a message should be ERROR or WARN, imagine being woken up at 4 a.m.
Low printer toner is not an ERROR.

---  Dan North former ToughtWorks consultant
\end{quote}

\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, ...
\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, ...
\item
  \textbf{FATAL} (ou \textbf{EXCEPTION}): ... généralement suivie d'une terminaison du programme - Bind raté
  d'un socket, etc.
\end{itemize}

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,
gestionnaires (\emph{handlers}) et loggers distincts, en fonction de nos applications.

Sauf que comme nous l'avons vu avec les 12 facteurs, nous devons traiter les informations de notre application comme un flux d'évènements. Il n'est donc pas réellement nécessaire de chipoter la configuration,
puisque la seule classe qui va réellement nous intéresser concerne les \texttt{StreamHandler}. La configuration que nous allons utiliser est celle-ci:

\begin{enumerate}
\item
  Formattage: à définir - mais la variante suivante est complète, lisible et pratique:
  \texttt{\{levelname\}\ \{asctime\}\ \{module\}\ \{process:d\}\ \{thread:d\}\ \{message\}}
\item
  Handler: juste un, qui définit un \texttt{StreamHandler}
\item
  Logger: pour celui-ci, nous avons besoin d'un niveau (\texttt{level})
  et de savoir s'il faut propager les informations vers les
  sous-paquets, auquel cas il nous suffira de fixer la valeur de
  \texttt{propagate} à \texttt{True}.
\end{enumerate}

Pour utiliser nos loggers, il suffit de copier le petit bout de code suivant:

\begin{minted}{python}
    import logging

    logger = logging.getLogger(__name__)
    logger.debug('helloworld')
\end{minted}


\href{https://docs.djangoproject.com/en/stable/topics/logging/\#examples}{Par
exemples}.


\begin{enumerate}
    \def\labelenumi{\arabic{enumi}.}
    \item
      Sentry via sentry\_sdk
    \item
      Nagios
    \item
      LibreNMS
    \item
      Zabbix
\end{enumerate}

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}.


\subsection{Zabbix, Nagios, ...}

\subsection{Sentry}

\subsection{Greylog}

