{"id":959,"date":"2010-06-05T15:54:36","date_gmt":"2010-06-05T13:54:36","guid":{"rendered":"http:\/\/blogdev.alwaysdata.com\/2010\/06\/05\/incident-sql-explications-2\/"},"modified":"2018-02-01T16:35:40","modified_gmt":"2018-02-01T15:35:40","slug":"incident-sql-explications-2","status":"publish","type":"post","link":"https:\/\/blog.alwaysdata.com\/fr\/2010\/06\/05\/incident-sql-explications-2\/","title":{"rendered":"Incident SQL&nbsp;: explications"},"content":{"rendered":"<p>Hier vers 12h40, une erreur humaine nous a&nbsp;fait perdre un petit nombre de bases de donn\u00e9es clients. Nous avons \u00e9t\u00e9 contraints de restaurer les bases concern\u00e9es \u00e0&nbsp;partir des derni\u00e8res sauvegardes. Tous les clients concern\u00e9s ont re\u00e7u un email indiquant les bases touch\u00e9es ainsi que la date de la sauvegarde pr\u00e9c\u00e9dente utilis\u00e9e. Nous vous pr\u00e9sentons nos plus sinc\u00e8res excuses, et revenons en d\u00e9tail dans ce billet sur ce qui s\u2019est pass\u00e9, ainsi que les mesures que nous allons prendre pour \u00e9viter que cela ne se reproduise \u00e0&nbsp;nouveau.<\/p>\n<h2>Ce qui s\u2019est&nbsp;pass\u00e9<\/h2>\n<p>Une commande de suppression (rm \u2011fr) a&nbsp;\u00e9t\u00e9 ex\u00e9cut\u00e9e sur le serveur de production alors qu\u2019elle \u00e9tait destin\u00e9e \u00e0&nbsp;un serveur de d\u00e9veloppement. Cette commande a&nbsp;eu le temps de tourner environ une seconde avant d\u2019\u00eatre arr\u00eat\u00e9e, mais cela a&nbsp;suffi \u00e0&nbsp;supprimer une partie des bases de donn\u00e9es. Nous avons alors imm\u00e9diatement commenc\u00e9 \u00e0&nbsp;faire la liste des bases disparues. Une fois cette liste obtenue, nous avons recr\u00e9\u00e9 les bases \u00e0&nbsp;partir des derni\u00e8res sauvegardes (effectu\u00e9es chaque jour).<\/p>\n<h2 style=\"font-size: 1.5em;\">Et la redondance&nbsp;?<\/h2>\n<p>Comme vous le savez, nos serveurs sont syst\u00e9matiquement redond\u00e9s dans un second datacenter. Mais ce m\u00e9canisme n\u2019est utile que lors des pannes de serveur ou de datacenter, pas pour les erreurs humaines. La synchronisation entre les datacenters se fait en temps r\u00e9el, et les donn\u00e9es modifi\u00e9es sont imm\u00e9diatement r\u00e9percut\u00e9es sur le serveur de secours.<\/p>\n<p>Sit\u00f4t un fichier supprim\u00e9 sur le serveur principal, il l\u2019est \u00e9galement sur le serveur secondaire. Ce dernier ne nous est donc d\u2019aucune aide dans ce cas pr\u00e9cis, et seules les sauvegardes r\u00e9guli\u00e8res peuvent nous aider \u00e0&nbsp;r\u00e9cup\u00e9rer une version pr\u00e9c\u00e9dente des bases et fichiers.<\/p>\n<h2 style=\"font-size: 1.5em;\">Comment \u00e9viter un nouvel incident&nbsp;?<\/h2>\n<p>Disons-le tout de suite&nbsp;: on ne pourra jamais exclure compl\u00e8tement l\u2019erreur humaine, et cet incident n\u2019a pas pour origine une n\u00e9gligence particuli\u00e8re de notre c\u00f4t\u00e9. Mais \u00e7a ne veut pas dire qu\u2019on ne va rien faire suite \u00e0&nbsp;cet incident.<\/p>\n<p>Il y&nbsp;a deux axes sur lesquels nous allons travailler&nbsp;: comment \u00e9viter une nouvelle erreur humaine, et comment \u00eatre mieux pr\u00e9par\u00e9 si elle devait se reproduire.<\/p>\n<h3>\u00c9viter l\u2019erreur humaine<\/h3>\n<p>\u00c0 nouveau, il y&nbsp;a deux composantes pour atteindre cet objectif&nbsp;: par la technique, et par la pr\u00e9vention humaine.<\/p>\n<p>Techniquement, nous allons r\u00e9fl\u00e9chir \u00e0&nbsp;mettre en&nbsp;place&nbsp;:<\/p>\n<ul>\n<li>un syst\u00e8me de protection des suppressions sur les serveurs en production. <a href=\"http:\/\/www.safe-rm.org.nz\/\">safe-rm<\/a> pourrait \u00eatre une premi\u00e8re solution&nbsp;;<\/li>\n<li>un syst\u00e8me de distinction visuelle (par exemple, des prompts de couleur diff\u00e9rente) entre les serveurs en production et les autres.<\/li>\n<\/ul>\n<p>Humainement, nous allons r\u00e9fl\u00e9chir \u00e0&nbsp;\u00e9dicter des r\u00e8gles d\u2019utilisation pour limiter les risques, par exemple&nbsp;:<\/p>\n<ul>\n<li>se d\u00e9connecter syst\u00e9matiquement d\u2019un serveur en production une fois qu\u2019on a&nbsp;effectu\u00e9 ce qu\u2019on avait \u00e0&nbsp;faire dessus, pour \u00e9viter qu\u2019une session inutile ne reste ouverte&nbsp;;<\/li>\n<li>si on doit malgr\u00e9 tout garder une session ouverte, s\u2019obliger \u00e0&nbsp;diff\u00e9rencier le terminal, par exemple en \u00e9vitant de rester sur le shell mais en d\u00e9marrant une commande de type top ou&nbsp;nano.<\/li>\n<\/ul>\n<h3 style=\"font-size: 1.17em;\">Se pr\u00e9parer au&nbsp;pire<\/h3>\n<p>Une fois les fichiers supprim\u00e9s, nous avons d\u00fb travailler \u00e0&nbsp;restaurer au plus vite les bases de donn\u00e9es perdues. Une telle suppression sauvage des fichiers internes aux bases de donn\u00e9es rend MySQL et PostgreSQL instables, et nous avons donc d\u00fb nous h\u00e2ter de faire des tests sur un serveur temporaire pour s\u2019assurer de la marche \u00e0&nbsp;suivre.<\/p>\n<p>Par ailleurs, nous n\u2019avions aucune m\u00e9thode \u00e9prouv\u00e9e pour d\u00e9tecter les bases supprim\u00e9es puis r\u00e9installer les derni\u00e8res sauvegardes. Ce n\u2019\u00e9tait pas tr\u00e8s compliqu\u00e9, mais cela a&nbsp;n\u00e9cessit\u00e9 l\u2019\u00e9criture de scripts et de tests pour s\u2019assurer du bon fonctionnement de la proc\u00e9dure. C\u2019est seulement ensuite que nous avons pu restaurer pour de bon les bases supprim\u00e9es, d\u2019o\u00f9 environ 2&nbsp;heures de d\u00e9lai entre la suppression des fichiers et la restauration effective des&nbsp;bases.<\/p>\n<p>Nous avons d\u00e9cid\u00e9 il y&nbsp;a quelques semaines de lancer un programme de simulation des diff\u00e9rents probl\u00e8mes possibles sur notre architecture (panne de machine\/r\u00e9seau\/datacenter, p\u00e9n\u00e9tration de nos syst\u00e8mes, suppression de donn\u00e9es). Ce n\u2019est pas encore en place parce qu\u2019il y&nbsp;a tout un travail technique en amont pour pouvoir dupliquer un serveur de production et y&nbsp;faire des simulations, mais cet incident nous montre une fois de plus l\u2019int\u00e9r\u00eat d\u2019\u00eatre pr\u00e9par\u00e9 \u00e0&nbsp;de multiples sc\u00e9narios catastrophe.<\/p>\n<p>Par ailleurs, nous sommes en train de travailler sur un nouveau syst\u00e8me de redondance. Rien n\u2019est encore fait, nous en sommes encore au stade de l\u2019exp\u00e9rimentation, mais ce syst\u00e8me pourrait nous permettre de faire des \u00ab&nbsp;snapshots&nbsp;\u00bb r\u00e9guliers (par exemple, toutes les heures) de l\u2019int\u00e9gralit\u00e9 de nos donn\u00e9es. S\u2019il avait \u00e9t\u00e9 en place, ce syst\u00e8me nous aurait permis non pas de partir sur des sauvegardes datant de plusieures heures, mais maximum d\u2019une heure. Nous aurons l\u2019occasion de faire un billet \u00e0&nbsp;ce sujet si ce syst\u00e8me se concr\u00e9tise.<\/p>\n<h2 style=\"font-size: 1.5em;\">Ce qui a&nbsp;bien fonctionn\u00e9<\/h2>\n<p>Terminons sur une note positive&nbsp;: nous pouvons relever que notre politique de communication en temps r\u00e9el et de transparence, via notre <a href=\"http:\/\/twitter.com\/alwaysdata\">compte Twitter<\/a>,&nbsp;fonctionne bien en cas d\u2019incident. Il faudrait encore l\u2019am\u00e9liorer en affichant, dans l\u2019administration alwaysdata et sur notre forum, les incidents en cours (tout le monde n\u2019est pas sur Twitter). Nous avons \u00e9galement pu contacter personnellement chacun de nos clients par email en leur indiquant pr\u00e9cis\u00e9ment les bases touch\u00e9es et la date de derni\u00e8re restauration.<\/p>\n<p>En outre, les sauvegardes ont \u00e9t\u00e9 d\u2019une grande utilit\u00e9. Ce n\u2019est pas une surprise, et chacun peut d\u2019ailleurs acc\u00e9der librement \u00e0&nbsp;ses sauvegardes via un r\u00e9pertoire de son compte. Mais c\u2019\u00e9tait la premi\u00e8re fois qu\u2019elles ont \u00e9t\u00e9 utilis\u00e9es \u00e0&nbsp;grande \u00e9chelle.<\/p>\n<p>Pour conclure, j\u2019aimerais pr\u00e9senter une nouvelle fois toutes nos excuses au nom de l\u2019\u00e9quipe alwaysdata pour ce malheureux incident. Merci \u00e0&nbsp;tous les messages d\u2019encouragement que nous avons re\u00e7us, ils sont toujours tr\u00e8s appr\u00e9ci\u00e9s, a&nbsp;fortiori en situation de&nbsp;crise.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hier vers 12h40, une erreur humaine nous a&nbsp;fait perdre un petit nombre de bases de donn\u00e9es clients. Nous avons \u00e9t\u00e9 contraints de restaurer les bases \u2026 <a class=\"read-more\" href=\"https:\/\/blog.alwaysdata.com\/fr\/2010\/06\/05\/incident-sql-explications-2\/\">Keep reading<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"wp_typography_post_enhancements_disabled":false,"footnotes":""},"categories":[1],"tags":[134,181,188],"class_list":["post-959","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-base-de-donnees-fr","tag-mysql-fr","tag-postgresql-fr"],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts\/959","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/comments?post=959"}],"version-history":[{"count":0,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/posts\/959\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/media?parent=959"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/categories?post=959"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.alwaysdata.com\/fr\/wp-json\/wp\/v2\/tags?post=959"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}