Architectures distribuées et traitements asynchrones

Cela fait quelque temps que je réfléchis à l’idée d’écrire un article sur les architectures distribuées, et plus particulièrement sur les traitements asynchrones. J’en parlais déjà au Forum PHP en 2013, dans de ma conférence intitulée «De 0 à 10 millions de visiteurs uniques avec les moyens d’une startup» mais je vais entrer plus en profondeur dans le sujet.

Pour quoi faire ?

On peut vouloir faire des traitements asynchrones pour différentes raisons. Si on s’en tient au développement web, la principale raison est de répondre plus vite aux requêtes des visiteurs, en exécutant certaines actions de manière différée. L’exemple classique est lorsqu’une action sur votre site doit déclencher un appel sur l’API d’un service tiers : Cet appel d’API peut prendre plusieurs secondes, et il peut même échouer en cas de problème momentané du service en question ; dans ce cas, plutôt que de faire attendre notre internaute, il vaut mieux lui répondre immédiatement et traiter cet appel d’API de manière asynchrone. Pareil pour des envois d’emails (même si les serveurs SMTP opèrent déjà de cette manière), des traitements sur des fichiers audio/vidéo, des calculs lourds, etc.

Si on élargit le débat au-delà du web, c’est un bon moyen pour découpler les différentes briques qui composent un logiciel afin de mettre en place une architecture distribuée. C’est souvent un élément essentiel lorsqu’on a besoin de scalabilité et même de rapidité. Un système monolithique atteindra tôt ou tard ses limites, là où un système composé de plusieurs entités qui communiquent ensemble sera plus facile à faire évoluer − au prix d’une complexité initiale plus grande.
En éclatant le code applicatif en plusieurs morceaux, on peut distribuer son exécution sur plusieurs machines assez facilement, facilitant ainsi l’évolutivité de la plate-forme.

Concrètement, l’idée est d’avoir des entités qui s’envoient des messages au lieu de discuter entre elles directement. Quand un message est envoyé, on n’attend pas une réponse immédiate ; une fois que le message aura été traité, un autre message sera éventuellement envoyé en retour pour le notifier, à moins que le résultat ne soit par exemple stocké dans une base de données où il sera disponible pour de futurs besoins.

Le sujet des architectures distribuées n’est pas nouveau. L’idée de RPC (appel à procédure distante) a été décrite dès 1976. Dans les années 90, quand les langages orientés objet étaient à la mode, beaucoup d’énergie a été déployée dans les systèmes servant à exécuter des objets à distance. C’est dans ce contexte que sont apparus des ORB (object request brokers) comme CORBA dès 1991 et RMI (Remote Method Invocation) intégré à Java dès la version 1.1 en 1997.
D’ailleurs, la complexité de CORBA a facilité l’émergence de normes plus simples et basées sur des technos web, comme XML-RPC et SOAP (Simple Object Access Protocol) en 1998, elles-mêmes simplifiées avec l’apparition du REST en 2000 (qui s’est développé d’autant plus avec l’usage du JSON, sérialisation plus simple à manipuler que le XML).

Mais comme on va le voir, il ne suffit pas de considérer qu’il y a des procédures/méthodes/objets à appeler pour que le système soit robuste en toutes circonstances. On peut d’ailleurs remarquer que les illusions de l’informatique distribuée sont bien connues et listées depuis les années 90 :

  1. Le réseau est fiable.
  2. Le temps de latence est nul.
  3. La bande passante est infinie.
  4. Le réseau est sûr.
  5. La topologie du réseau ne change pas.
  6. Il y a un et un seul administrateur réseau.
  7. Le coût de transport est nul.
  8. Le réseau est homogène.

Effectivement, rien de tout cela n’est vrai. Découpler une application apporte beaucoup d’avantages, mais comporte aussi des contraintes et des risques qu’il faut connaître et évaluer.

Comment faire ?

Pour mettre en place ce type d’architecture, il existe un certain nombre de moyens techniques, depuis les plus simples jusqu’aux plus complexes. Je vais passer en revue quelques notions et solutions.

Quand on parle de traitements asynchrones, on a habituellement trois composants à mettre en place :

  • Une partie qui permet de donner des ordres de traitements, avec éventuellement des informations complémentaires (de quel type d’ordre il s’agit, avec parfois des données additionnelles, etc.). Cela prend habituellement la forme d’une simple bibliothèque logicielle, mais certaines technos imposent plus de contraintes − comment les ORB qui obligeaient à créer des stubs.
  • La pièce centrale du système, qui gère les messages qui sont envoyés, en les classant éventuellement par priorité ou en les rangeant dans différentes files. Cette partie peut être basée sur des technologies variées (bases de données, files de messages, tables de hachage, ou autre).
    Les technos utilisées, que ce soit pour gérer les messages ou pour communiquer entre les différentes briques de l’architecture, ont une influence directe sur les performances du système.
  • La dernière partie est constituée par des «workers», c’est-à-dire du code qui traite les messages et effectue le travail demandé. Là encore, il existe plusieurs manières de faire : soit les workers sont des programmes indépendants (qu’il faut alors gérer correctement), soit ils sont lancés par la brique centrale (au prix d’un coût d’instanciation qui ajoute de la latence dans les traitements).

Dans les notions qui me semblent importantes à avoir en tête, il y en a principalement deux :

  • La scalabilité : Est-ce que la solution retenue peut soutenir un très grand nombre de messages échangés, et est-il possible de répartir leur traitement sur plusieurs ordinateurs ?
  • La persistance : Si la partie centrale de l’architecture venait à tomber en panne, est-ce que les messages qui étaient en attente de traitement sont perdus ou bien sont-ils conservés pour être traités au redémarrage du système ?

Pour la mise en œuvre, je vais explorer 2 manières de faire, chacune avec 2 technos différentes :

  • L’utilisation d’une base de données dans laquelle on écrit les messages, avec un système de polling (“attente active” ou “scrutation” en français) pour instancier leurs traitements.
    1. De manière artisanale, avec l’utilisation de la crontab.
    2. Avec l’outil Resque.
  • L’utilisation d’un système intégrant une file de messages.
    1. Avec l’outil Gearman.
    2. Avec l’outil Beanstalkd.

Base de données ou file de messages ?

Parmi les quatre méthodes que je vais détailler, trois d’entre elles reposent d’une manière ou d’une autre sur l’utilisation d’une base de données. Continuer la lecture de « Architectures distribuées et traitements asynchrones »

Arkiv : Sauvegarde de fichiers et bases MySQL + archivage sur Amazon S3 et Amazon Glacier

Pour mes besoins, j’ai créé un programme qui sert à faire des sauvegardes de fichiers et de bases de données MySQL. Ces sauvegardes sont stockées en local et peuvent être archivées sur Amazon S3 ainsi que sur Amazon Glacier.

Ce programme s’appelle Arkiv et son code source est disponible sur GitHub. Il est placé sous une licence libre très permissive.

Pourquoi avoir développé ce logiciel ?

J’utilisais depuis longtemps le programme Backup-Manager, qui me permettait de sauvegarder mes fichiers et mes bases de données en local et sur un serveur FTP, puis sur Amazon S3. Ce programme est très pratique ; il existe depuis plus de 10 ans (il me semble que je l’utilise depuis tout ce temps), il offre pas mal d’options de configuration, et il est disponible dans les paquets Ubuntu.
Mais avec le temps, mes besoins ont évolué, et certaines limites sont apparues : Il ne permet pas de faire plus d’une sauvegarde par jour, ne supporte pas tous les datacenters Amazon (les plus récents ne sont pas compatibles avec les anciennes versions de l’API), ne permet pas d’archiver sur Amazon Glacier et il manque de souplesse au niveau de la purge des sauvegardes.

Vous connaissez sûrement Amazon S3, mais Amazon Glacier est plus récent et moins connu. Ce sont deux services AWS (Amazon Web Services), l’offre de Cloud Computing d’Amazon.
Amazon S3 peut être vu comme un espace de stockage de fichiers de taille illimitée à haute disponibilité. Les données sont disponibles en temps réel. On paye suivant la quantité de données stockée, pour un coût assez faible (pour donner un ordre d’idée, stocker 500 GO de données dans le datacenter de Londres coûte environ 12$ par mois), auquel s’ajoutent des frais suivant le nombre d’échanges et la quantité de données échangées. Un très grand nombre de services stockent leurs fichiers sur Amazon S3 pour ne plus avoir à s’embarrasser de la problématique du stockage.
Amazon Glacier est lui aussi un espace de stockage de fichiers illimité. Sauf que contrairement à S3, il a été conçu spécifiquement pour les stockages à très longue durée, qui n’ont pas forcément besoin d’être lus en temps réel. Le coût est extrêmement faible (compter 2,25$ par mois pour stocker 500 GO de données à Londres), mais en contrepartie la récupération de données peut prendre entre quelques minutes et 12 heures (suivant le tarif de récupération choisi).

Mon souhait était de pouvoir fonctionner (pour mes serveurs personnels) de la manière suivante :

  • Sauvegarder tous les jours certains répertoires et certaines bases MySQL.
  • Écrire ces sauvegardes sur le disque local, mais les copier aussi sur Amazon S3 et sur Amazon Glacier.
  • Garder les sauvegardes sur le disque local pendant 3 jours avant de les effacer, pour que les versions les plus “fraîches” soient accessibles immédiatement en cas de problème.
  • Attendre 2 semaines avant d’effacer les archives stockées sur Amazon S3, pour permettre une récupération relativement facile de données assez récentes, sans pour autant payer le stockage de données périmées.
  • Garder sans limite de temps les archives stockées sur Amazon Glacier, pour avoir une trace de toutes les versions de mes fichiers.

Ça a l’air simple, vu comme ça, mais je n’ai pas trouvé d’outil me permettant de le faire simplement.
Et pour compliquer un peu les choses, mes besoins professionnels vont plus loin :

  • Sauvegarder toutes les heures certains répertoires et certaines bases MySQL.
  • Écrire ces sauvegardes en local, ainsi que sur Amazon S3 et Amazon Glacier.
  • Garder toutes les sauvegardes (donc 24 sauvegardes par jour) en local pendant 3 jours ; puis n’en garder qu’une sur six (donc 4 sauvegardes par jour) pendant 4 jours ; puis une par jour pendant une semaine.
  • Garder toutes les sauvegardes sur Amazon S3 pendant 2 semaines ; puis une sur quatre (6 sauvegardes par jour) pendant 2 semaines ; puis une par jour pendant un mois.
  • Stocker les archives sur Amazon Glacier sans limite de temps.

Donc là il faut être capable de faire une sauvegarde toutes les heures, mais aussi gérer les purges (en local et sur Amazon S3) de manière très fine.

J’ai donc pris la décision de créer mon propre script de sauvegarde et d’archivage. Les habitués de ce blog se souviennent que j’ai écrit récemment un article sur l’utilisation de mysqldump, fournissant même un script de sauvegarde de bases MySQL qui allait jusqu’à copier les sauvegardes sur Amazon S3. Je suis juste passé à l’échelle supérieure.

Pour un maximum de portabilité, j’ai développé le programme en shell Bash. C’est le shell le plus courant sur les systèmes Unix/Linux.  Ainsi, pas besoin d’interpréteur spécifique (ce qui serait le cas si je l’avais développé en PHP) et pas besoin de compilation (ce qui aurait été nécessaire si je l’avais codé en C).
Pour être le plus ergonomique possible − dans la mesure de ce qu’il est possible de faire en ligne de commande − j’ai pris le temps de faire deux choses :

  • La configuration est interactive. La génération du fichier de configuration se fait en répondant à des questions (dont une majorité proposant des réponses par défaut) et non pas en remplissant à la main un fichier vide. Et le script ajoute automatiquement (enfin, si vous le souhaitez uniquement) Arkiv en Crontab pour qu’il soit exécuté automatiquement à la fréquence que vous souhaitez.
  • J’utilise les capacités ANSI des terminaux pour faire un peu de mise-en-page des textes, avec de la couleur, des textes en gras ou en vidéo-inverse. Que ce soit pour la génération du fichier de configuration ou pour les logs d’exécution, cela facilite grandement la compréhension.

Et pour le nom du projet, j’ai choisi un mot qui veut dire “archive” dans plusieurs langues (notamment scandinaves ; un peu comme Skriv, qui veut dire “écrire” dans ces mêmes langues).

Comment installer Arkiv

La directive est assez simple, et expliquée sur la page GitHub du projet.
Pour commencer, il faut cloner le repository :

# git clone https://github.com/Amaury/Arkviv

Si vous souhaitez archiver sur Amazon S3 et Amazon Glacier : Avant de lancer le programme de configuration, il faut créer un “bucket” Amazon S3 et un “vault” Amazon Glacier (dans le même datacenter), puis créer un utilisateur IAM et lui donner les droits en lecture-écriture sur ce bucket et ce vault.

Ensuite on lance la configuration :

# cd Arkiv; ./arkiv config

Voici une copie d’écran d’un exemple d’installation :

Cliquez pour agrandir

(Dans cet exemple, vous pouvez voir que les sauvegardes sont faites toutes les heures, archivées sur Amazon S3 et Amazon Glacier, et que les purges sont configurées assez finement.)

Il est possible de faire en sorte que les sauvegardes ne se fassent pas tous les jours et toutes les heures, mais de choisir une fréquence à la carte. Et comme il est possible d’utiliser plusieurs fichiers de configuration différents (en fournissant leurs chemins en paramètre), il est possible de mettre en place des politiques de sauvegarde assez complexes, pour coller au plus près des besoins.

À la fin de ce processus, le fichier de configuration est créé, et le programme a été ajouté en Crontab pour s’exécuter automatiquement.

À l’exécution

Lorsque le programme s’exécute, il passe par plusieurs étapes :

  1. Démarrage
    1. Arkiv est lancé par la Crontab.
    2. Il crée un dossier sur le disque local, qui accueillera les fichiers sauvegardés.
  2. Sauvegarde
    1. Tous les chemins listés dans la configuration sont compressés et le résultat est enregistré dans le dossier dédié.
    2. Si la sauvegarde MySQL est activée, les bases de données sont dumpées et sauvegardées dans le même dossier.
    3. Des checksums sont calculés pour tous les fichiers sauvegardés.
  3. Archivage
    1. Si l’archivage sur Amazon Glacier a été activé, tous les fichiers de sauvegarde y sont copiés. Pour chacun d’eux, un fichier JSON est créé, contenant la réponse renvoyée par Amazon. Ces fichiers contiennent les identifiants nécessaires à la récupération des fichiers.
    2. Si l’archivage sur Amazon S3 a été activé, le dossier et tout ce qu’il contient (fichiers de sauvegarde, fichier de checksum, fichiers JSON d’Amazon Glacier) y sont copiés.
  4. Purge
    1. Effacement sur le disque local des fichiers de sauvegarde qui ont atteint l’âge défini.
    2. Si l’archivage sur Amazon S3 a été activé, les fichiers de sauvegarde qui ont atteint l’âge défini sont effacés. Les fichiers de checksum et les fichiers JSON d’Amazon Glacier ne sont pas effacés, afin de permettre la récupération des fichiers archivés sur Amazon Glacier et d’en vérifier l’intégrité.

Sauf en cas de problème, l’exécution du programme se déroule de manière silencieuse.

Voici un exemple de ce que vous pourrez trouver dans le fichier de log :

Cliquez pour agrandir

Vous pouvez voir que la « mise-en page » est là pour rendre les logs faciles à lire. Les éventuelles alertes et erreurs sont mises en avant grâce à de la couleur et des pictos.

Améliorations futures

Comme toujours, j’ai développé ce logiciel pour répondre à mes besoins, et je le rends accessible à tous sous licence libre parce qu’il pourra rendre des services à d’autres personnes que moi.
Je n’ai pas envie d’en étendre les fonctionnalités. L’archivage par FTP ou SCP, ou sur des plates-formes Cloud autres que celle d’Amazon, pourrait être pratique pour certains, mais cela complexifierait beaucoup le code. Arkiv ne se destine pas à être un outil obèse capable de tout gérer ; je préfère qu’il reste un outil avec des fonctionnalités réduites, mais qu’il adresse les bonnes fonctionnalités, et qu’il les accomplisse le mieux possible.
Donc on verra.

En attendant, n’hésitez pas à le tester et à me faire des retours. Si vous trouvez des bugs, vous pouvez utiliser la buglist fournie par GitHub.

Edit du 13 août : J’ai ajouté une fonctionnalité supplémentaire, l’encryption des fichiers (algorithme AES 256 bits par OpenSSL). Ça peut être utile pour les plus paranoïaques 😉

Edit du 29 août : J’ai ajouté le support des sauvegardes binaires de bases de données (utilisant l’outil xtrabackup), en global ou incrémental. Ainsi que l’écriture des logs dans syslog.

Utilisation de MySQLDump

Il existe plusieurs moyens pour faire des sauvegardes de bases de données. Je ne vais pas parler ici de l’utilisation des logs binaires ni de la mise en place de réplication pour effectuer les sauvegardes sur un serveur esclave ; je vais me concentrer sur l’outil principal de sauvegarde lorsqu’on utilise MySQL : mysqldump

Je pense que tout le monde (en tout cas, une majorité des gens qui lisent cet article) sait à quoi sert cet outil. Il sert à écrire un fichier contenant toutes les directives SQL permettant de recréer une base de données à l’identique de l’état dans lequel elle se trouvait au moment de la sauvegarde.
Je ne vais pas m’étaler sur les aspects théoriques, mais plutôt vous expliquer comment je l’utilise.

Je me sers de mysqldump depuis une bonne quinzaine d’années, il me semble. À l’époque, l’utilisation par défaut (sans passer d’option particulière en ligne de commande) était assez pénible, surtout quand on voulait restaurer les données ; le code SQL généré contenait une commande INSERT pour chaque ligne de chaque table. Quand on injectait le fichier, le serveur mettait un temps infini pour exécuter toutes ces insertions et recalculer les index au fur et à mesure.
Ma vie a changé quand j’ai découvert l’option “–extended-insert”, qui regroupe plusieurs insertions dans une seule commande INSERT.

Les options à utiliser

Aujourd’hui, l’option “–opt” est activée par défaut sur les versions modernes de mysqldump. Cette option se contente d’activer par défaut les options suivantes :

  • –add-drop-table : Ajoute des directives pour effacer les tables avant de les recréer. Utile pour réinjecter un fichier en écrasant les anciennes versions des tables qui pourraient déjà traîner dans la base.
  • –add-locks : Ajoute des commandes pour verrouiller les tables pendant leur écriture ; il est alors impossible de lire ou d’écrire dedans en même temps que les données sont injectées, ce qui évite de ralentir l’injection.
  • –create-options : Ajoute les commandes de création des tables. On ne saurait s’en passer.
  • –disable-keys : Cette option accélère l’injection des données en faisant en sorte que les index sont créés qu’une fois que toutes les lignes sont injectées. Sauf que cela ne fonctionne qu’avec les index non uniques des tables MyISAM. Et comme vous êtes censés utiliser le moteur InnoDB à la place du MyISAM, on s’en moque un peu…
  • –extended-insert : Je viens d’en parler, c’est juste essentiel.
  • –lock-tables : Cette option a pour but de garantir l’intégrité des données qui sont sauvegardées, en verrouillant les tables durant la lecture. Je vais revenir sur ce point, car il est problématique.
  • –quick : Par défaut, quand mysqldump s’occupe d’une table, il tente de récupérer toutes les données en mémoire, avant d’en écrire le contenu. Sauf que si vous avez de très grosses tables, cela ne tiendra pas en RAM. L’option “–quick” empêche de tout charger en mémoire.
  • –set-charset : Demande l’ajout de la directive SET NAMES avec l’indication de l’encodage de caractères utilisés. Ça ne mange pas de pain.

Du coup, toutes ces options peuvent sembler utiles (et c’est sûrement pour ça qu’elles ont été regroupées sous l’option unique “–opt”, et que cette option est activée par défaut). Sauf qu’il y a un problème lorsqu’on exécute mysqldump en production avec ces options : Je vous ai dit que l’option “–lock-tables” verrouille les tables au moment où on les lit.

Encore une fois, la volonté derrière cela est assez simple. Si des écritures (ajouts ou modifications de données) ont lieu pendant la sauvegarde de la base de données, le fichier qui est généré n’a alors plus aucune cohérence. Vous pouvez avoir récupéré des données dont le début reflète un état différent de la fin, parce que les données ont bougé entretemps… Vous imaginez le bordel.
Sauf que si vous utilisez cette option sur votre serveur de production (et sans avoir mis en place une réplication qui vous permettrait de faire les sauvegardes sur un serveur esclave), cela veut dire que pendant toute la durée de l’exécution de mysqldump, votre application risque de vouloir manipuler les données… sans succès. Le pire, c’est que ces verrous sont posés par base ; donc si vous avez des données avec des liaisons qui se font entre des tables qui sont dans des bases différentes, cela ne sera pas suffisant de toute façon.

Continuer la lecture de « Utilisation de MySQLDump »

Gestion des dates et heures dans les bases de données

Je vais vous parler d’une réflexion que j’ai en ce moment, causée par un développement sur un produit qui se veut à destination d’utilisateurs répartis autour du globe.

Jusqu’ici, je n’avais jamais vraiment été confronté à de véritables problèmes de gestion des dates dans mes applications. Je stockais les dates et heures en base de données dans des champs de type DATETIME (avec MySQL). Les dates enregistrées l’étaient en partant du principe qu’elles étaient valables en France, et donc au moment de lire les dates pour les afficher cela ne posait pas de soucis pour des utilisateurs situés en France là encore.

Notez bien que j’utilise MySQL, qui a la très mauvaise idée de stocker les dates sans la moindre information de timezone. Donc quand vous enregistrez la valeur ‘2011-04-12 11:04:12’, il l’enregistre telle quelle, sans plus d’information. À vous de vous débrouiller avec ça. Encore une fois, tant que vous êtes dans le même pays pour la lecture et l’écriture, cela ne pose aucun problème. Ça devient plus délicat quand ce n’est pas le cas.
Je vais m’expliquer en détail, mais sachez qu’avec d’autres moteurs de base de données, comme PostgreSQL par exemple (je ne connais pas les autres ; j’ai travaillé un peu avec Oracle il y a 10 ans, mais je n’ai pas de souvenir à ce niveau), il y a des champs permettant de gérer les timezones, ce qui évite bien des soucis la plupart du temps.

Le cas d’utilisation problématique apparaît lorsque vous devez lire une date et l’afficher pour un utilisateur situé dans un fuseau horaire différent de celui qui a été à l’origine de l’enregistrement.
Ce qui est normalement prévu, c’est de convertir la date depuis sa timezone de départ vers la timezone d’arrivée. Si on part du principe que la timezone utilisée par le serveur n’a pas été modifiée, on peut se baser dessus pour faire la conversion. Pour cela, on peut utiliser la fonction CONVERT_TZ(). Par exemple, pour lire une date enregistrée en France et l’afficher pour un utilisateur québécois, on peut écrire ceci :

SELECT CONVERT_TZ(date, @@session.time_zone, '-5:00') FROM MaTable;

Le résultat est que la date stockée dans le champ date est convertie, depuis la timezone définie par le système (ou éventuellement dans la configuration de MySQL), vers une date dont la timezone a 5 heures de retard sur le fuseau zéro.
Donc si la date en base est ‘2011-04-12 11:04:12’, que le système a une timezone par défaut configurée pour être celle de la France, qu’on est actuellement en hiver (donc la timezone serveur est ‘+01:00’), le résultat sera ‘2011-04-12 05:04:12’.

C’est parfait !

Oui mais non. En Europe, le passage à l’heure d’été se fait le dernier dimanche de mars, alors qu’en Amérique du Nord il se fait le deuxième dimanche de mars ; les passages à l’heure d’hiver se faisant respectivement le premier dimanche de novembre et le dernier dimanche d’octobre. Il y a donc 3 semaines dans l’année pendant lesquelles il n’y a plus que 5 heures de décalage horaire entre la France et le Québec, au lieu des 6 heures habituelles.

Imaginons que je convertisse la date ‘2010-03-21 15:27:10’, par la même manière que précédemment, que se passe-t-il ?

CONVERT_TZ('2010-03-21 15:27:10', @@session.time_zone, '-05:00')

Il faut comprendre que le premier paramètre est indépendant des deux suivants. Le deuxième paramètre prend la valeur de la timezone locale, définie par le système ; ce qui me donne ‘+01:00’ (décalage en France en hiver) ou ‘+02:00’ (décalage en France en été). Mais pour le troisième paramètre, j’ai donné une valeur fixe, qui va s’ajouter au paramètre précédent.
Donc, suivant que je fasse cette conversion en été ou en hiver (et donc suivant la valeur du second paramètre), le décalage horaire qui va être calculé sera de 6 ou de 7 heures.

Ce n’est pas bon du tout ! Il n’y a jamais 7 heures de décalage horaire entre la France et le Québec !

Il faudrait donc que je sache moduler le troisième paramètre, pour lui donner une valeur différente en fonction de la date en cours (‘-05:00’ en hiver et ‘-04:00’ en été). Ainsi, le décalage sera toujours bien de 6 heures…
Sauf que la date en question (21 mars) tombe pile sur l’un des créneaux pendant lesquels il n’y a plus que 5 heures de décalage horaire entre la France et le Québec ! Comment faire pour interpréter cela correctement, et obtenir la bonne valeur (‘2010-03-21 10:27:10’, pour info) ?

Après avoir pas mal cherché, il semblerait qu’il ne faille pas faire confiance à MySQL. Du tout. Il ne sait pas gérer les timezones et encore moins les passages heure d’été/heure d’hiver ; donc quand il enregistre une date, il la stocke telle quelle et il vous laissera vous débrouiller quand vous voudrez l’afficher.
Pour ne pas faire confiance à MySQL, le plus simple est de stocker toutes les dates telles qu’elles sont sur le temps UTC, donc sans décalage par rapport au temps universel. Au moment de la lecture, les dates doivent alors être récupérées de la même manière (temps UTC), puis converties au moment de l’affichage, en fonction des préférences locales de l’utilisateur.

Pour être plus clair, il suffit de faire la conversion au moment de l’écriture :

INSERT INTO MaTable SET date = CONVERT_TZ('2017-05-06 05:49:00', @@session.time_zone, '+00:00');

Au moment de la lecture, plus besoin de faire de conversion quand on lit les données en base. Par contre, il faudra convertir au moment de l’affichage, comme je l’ai dit plus haut.

Mais cette requête utilise la timezone locale du serveur, pour calculer le décalage horaire (ici ‘+01:00’ ou ‘+02:00’ si le serveur est en France, suivant qu’on soit en été ou en hiver au moment où la requête est exécutée). Si c’est un utilisateur qui fournit une date et heure, il va falloir récupérer sa timezone locale (‘-05:00’ ou ‘-04:00’ s’il est au Québec, suivant la période de l’année).

Par contre, si les seules dates que vous enregistrez sont les date et heure courantes, en utilisant la fonction NOW(), il peut être plus simple de configurer le serveur pour qu’il reste sur l’UTC.
Cela peut être fait en modifiant le fichier de configuration (‘/etc/mysql/my.cnf) :

default_time_zone = '+00:00'

Ou en modifiant le paramètre de la connexion en cours :

SET @@session.time_zone = '+00:00';

Quelques liens sur le sujet :

Installation serveur HTTP(S) rapide

Voici un article qui va me servir à rassembler les différentes documentations dont je me sert à chaque fois que j’installe un serveur Web. Là, j’ai pris un serveur virtuel chez OVH (à 3 € HT par mois, pour 2 GO de RAM et 10 GO d’espace disque), sur lequel j’ai installé une distribution Ubuntu 16.04.

Une fois l’installation terminée, on reçoit un email avec le mot de passe root. Commençons donc par nous logguer sur la machine.

Installations de base

Installons quelques outils utiles :

# apt-get install tree htop iftop make screen subversion git

Créons un nouvel utilisateur, et ajoutons-le au groupe sudo (pour qu’il puisse exécuter des commandes en tant que root) :

# adduser toto
# usermod -aG sudo toto

Éditons la configuration SSH pour empêcher la connexion avec l’utilisateur root. Pour cela, il faut ouvrir le fichier /etc/ssh/sshd_config et éditer la ligne suivante :

PermitRootLogin no

Continuer la lecture de « Installation serveur HTTP(S) rapide »

Recrutement : Développeur PHP 5

Fine Media, l’entreprise que j’ai co-créé et dont je suis le directeur technique, est à la recherche d’un développeur web.

Présentation de l’entreprise

Nous sommes éditeurs de sites web. Notre activité principale porte sur les sites Ooreka, qui sont un ensemble de plus de 420 sites de niche, sur des sujets aussi variés que les fenêtres, la défiscalisation ou le home cinéma. C’est notre « encyclopédie de la vie pratique ».
Nous éditons aussi des sites communautaires, comme CommentFaitOn ou DcoPhoto.

Nous sommes localisés dans le 17è arrondissement de Paris (métro Villiers).

L’entreprise existe depuis 2007 et est une filiale du groupe Solocal (ex Groupe PagesJaunes) depuis 2011.
Nous sommes une vingtaine de personnes, et l’équipe technique comprend 9 personnes.

Environnement technique et méthodes de travail

  • Linux. On utilise de l’Ubuntu Server sur les serveurs, et de l’Ubuntu Workstation sur les postes de développement.
  • PHP 5. Tout est développé en PHP, en objet.
  • MySQL. On fait des requêtes assez compliquées. Il vaudrait mieux que vous sachiez la différence entre une sous-requête et une jointure.
  • Redis. Nous faisons de l’hybridation de bases, cela peut être l’occasion pour vous d’approcher le noSQL de près.
  • Temma. Nous utilisons notre propre framework MVC, qui est publié sous licence libre.

Nous travaillons suivant une méthode dérivée de SCRUM. Nous faisons des cycles itératifs d’une durée d’un mois (cf. l’article où j’en parlais).

Ce que vous aurez à faire

  • Améliorer notre framework MVC, ainsi que notre CMS. Ils sont petits et légers, des vrais jouets faciles à faire évoluer dans les directions qui nous intéressent.
  • Génie logiciel : modélisation des objets métier, évolution du modèle de base de données, développement orienté objet.
  • Gestion de projet : écriture des spécifications techniques, suivi du planning, supervision des tests.

Je cherche quelqu’un ayant déjà fait ses armes en développement Web, et qui aime ça. Un passionné avec des idées à faire valoir, ayant envie de les partager et de les appliquer. Une personne qui sache travailler en équipe, qui cherche à apprendre des choses nouvelles.

Alors si vous êtes ambitieux, si vous avez des idées techniques intéressantes, si vous aimez le Web et avez envie de bosser sur des trucs pointus et originaux, envoyez-moi votre CV à l’adresse amaury.bouchard@finemedia.fr.

Ajout : Suite à des questions, je préfère préciser que nous ne recherchons pas de prestataire, ni de développeur travaillant à distance. L’idée est d’embaucher quelqu’un qui fera partie intégrante de l’équipe − y compris dans sa localisation géographique.

Conférence sur les bases de données relationnelles le jeudi 28 février

L’antenne parisienne de l’AFUP organise jeudi prochain, le 28 février, un Rendez-Vous consacré aux base de données relationnelles open-source.

Nous avons la chance d’accueillir trois experts renommés :

Le tout se tiendra dans les locaux de Linagora, 80 Rue Roque de Fillol 92800 Puteaux (plan). Ouverture des portes à 18h30, début des conférences à 19h00.
Un pot aura lieu après les conférences, nous permettant de discuter en buvant un verre et en grignotant. Merci à SkySQL de sponsoriser l’évènement.

Le nombre de places est limité, merci de vous inscrire sur le site de l’AFUP.

Recrutement : Administrateur système

Le poste d’administrateur système n’est plus à pourvoir. Merci à tous ceux qui m’ont envoyé un CV.

Fine Media, l’entreprise que j’ai co-créé et dont je suis le directeur technique, est à la recherche d’un administrateur système / responsable d’exploitation.

Présentation de l’entreprise

Nous éditons des sites web communautaires, comme CommentFaitOn ou DcoPhoto, et des sites « de niche » comme Le guide de la cuisine, ou les sites ComprendreChoisir (sur la fenêtre, la défiscalisation, le home cinema, les standards téléphoniques, …).

L’entreprise est bientôt âgée de 5 ans, comprend environ 25 personnes et est devenue une filiale du groupe PagesJaunes depuis l’été dernier. Le cadre et les projets sont dynamiques et motivants, l’équipe est jeune et très motivée.
Nous sommes localisés dans le 17è arrondissement de Paris (métro Villiers).

Définition du poste

Le poste d’administrateur couvre un champ d’action assez large.

Au quotidien, cela implique :

  • Maintenance du réseau interne de l’entreprise, qui comprend près de 30 postes de travail, 4 serveurs et un NAS. Nous avons un second réseau dédié à la téléphonie (voix sur IP).
  • Administration des serveurs de production, soit 8 machines hébergées en datacenter.
  • Exploitation : Mise en pré-production et en production de nos projets, déroulement des cahiers de tests. Amélioration de nos procédures de suivi et de documentation.
  • Monitoring de nos serveurs et applications.
  • Sauvegarde et archivage des données de production et du réseau interne.

Je cherche quelqu’un qui puisse aussi participer aux évolutions que nous avons commencé à mettre en place sur notre architecture :

  • Expertise en base de données (configuration MySQL, optimisation de requêtes, réplication de bases).
  • Amélioration de la montée en charge de nos serveurs Web.
  • Étude de solutions de virtualisation (KVM) et noSQL (Redis).

Environnement technique

  • Linux : Tous nos serveurs tournent sous Ubuntu, ainsi que la plupart de nos postes de travail.
  • Web : Nos applications sont écrites en PHP, exécutées par Apache, et utilisent des bases de données MySQL.
  • Serveurs : Nos serveurs de productions sont majoritairement des bi-Xeon QuadCore/16 GO, avec des disques allant de 300 GO à 750 GO en RAID. Les serveurs internes tournent sur du matériel classique, certains sont virtualisés.
  • Scripting : Quelques scripts d’administration sont écrits en shell, mais la plupart de nos outils sont écrits en PHP.

Une migration de plate-forme de production est prévue à court terme, j’aimerais que le nouvel administrateur participe pleinement à son design et à sa mise en place.

Détails

Le poste est à pourvoir dès que possible.
C’est un CDI à temps complet.
Le salaire est en fonction de l’expérience et des compétences.

Si vous êtes intéressés, envoyez-moi votre CV à l’adresse amaury.bouchard@finemedia.fr.

Recrutement : Développeur principal PHP 5

Le poste de développeur n’est plus à pourvoir. Merci à tous ceux qui m’ont envoyé un CV.
Par contre, nous sommes à la recherche d’un administrateur système, n’hésitez pas à postuler.

Un billet inhabituel aujourd’hui : Fine Media, l’entreprise que j’ai co-créé et dont je suis le directeur technique, est à la recherche d’un développeur web. Pas n’importe quel poste de développement ; nous cherchons notre développeur principal.

C’est quoi un développeur principal ? Simplement la personne qui pourra prendre mon relais. Un “responsable des développements”, si vous préférez.

Présentation de l’entreprise

Nous éditons des sites web communautaires, comme CommentFaitOn ou DcoPhoto, et des sites « de niche » comme Le guide de la cuisine, ou les sites ComprendreChoisir (sur la fenêtre, la défiscalisation, le home cinema, les standards téléphoniques, …).

Nous sommes localisés dans le 17è arrondissement de Paris (métro Villiers).

L’environnement technique

  • Linux. On utilise de l’Ubuntu Server sur les serveurs, et de l’Ubuntu Workstation sur les postes de développement. À vrai dire, même les rédacteurs et les commerciaux sont sous Linux, chez nous.
  • PHP 5. Tout est développé en PHP, en objet, en utilisant des design patterns, avec des cycles de développement itératifs et des validations test/pré-production/production.
  • MySQL. On fait des requêtes assez compliquées. Il vaudrait mieux que vous sachiez la différence entre une sous-requête et une jointure.
  • Subversion. Si vous n’avez jamais utilisé le moindre système de gestion de sources, ce n’est pas grave, vous vous y ferez très vite. Et après vous ne pourrez plus vous en passer.

Ce que vous aurez à faire

  • Améliorer notre framework MVC interne, ainsi que notre CMS. Ils sont petits et légers, des vrais jouets faciles à faire évoluer dans les directions qui nous intéressent.
  • Travailler sur FineFS, notre outil de clustering réseau, placé sous licence libre. Si vous cherchez un projet hyper-technique en PHP, vous allez être servis ! 😉
  • Génie logiciel : modélisation des objets métier, évolution du modèle de base de données, développement orienté objet.
  • Gestion de projet : écriture des spécifications techniques, suivi du planning, supervision des tests.

Évidemment, c’est un poste avec certaines responsabilités. Donc je cherche quelqu’un ayant déjà fait ses preuves en développement Web, et qui aime ça. Un passionné avec des idées à faire valoir, ayant envie de les partager et de les appliquer. Mais aussi quelqu’un qui souhaite faire de la gestion de projets et faire de l’encadrement.

Sans oublier que je prends le temps de former les membres de mon équipe. Car il s’agit vraiment d’une équipe : je cherche quelqu’un qui pourra nous apporter autant que nous pourrons lui apporter.

Alors si vous êtes ambitieux, si vous avez des idées techniques intéressantes, si vous aimez le Web et avez envie de bosser sur des trucs pointus et originaux, envoyez-moi votre CV à l’adresse amaury.bouchard@finemedia.fr.