Written by

Le mer­cre­di 17 juillet 2013 à 0h02 (UTC+2), une cor­rup­tion de sys­tème de fichiers s’est pro­duite sur le ser­veur mysql1. Toutes les bases de don­nées héber­gées sur ce ser­veur ont été indis­po­nibles durant la nuit, et une faible pro­por­tion d’entre elles ont été vic­times de cor­rup­tion de données.

Ce billet revient en détails sur cet inci­dent : ce qu’il s’est pas­sé et les ensei­gne­ments que nous en tirons. Nous avons essayé d’u­ti­li­ser des termes com­pré­hen­sibles par tous, tout en gar­dant autant de détails tech­niques que possible.

Vous pou­vez éga­le­ment relire le compte-ren­du en direct de l’incident.

Ce qu’il s’est passé

Utilisation de bcache

Commençons par pré­ci­ser que le maté­riel du ser­veur mysql1 a été chan­gé le 7 juillet afin de l’é­qui­per à la fois de disques SSD et de disques méca­niques. Le ser­veur était aupa­ra­vant uni­que­ment pour­vu des disques SSD, mais l’aug­men­ta­tion crois­sante de l’es­pace disque a jus­ti­fié cette évolution.

bcache est une tech­no­lo­gie inté­grée récem­ment à Linux et qui per­met de com­bi­ner des disques SSD et méca­niques afin d’ob­te­nir un espace disque impor­tant et des per­for­mances proches de celles d’un SSD. Nous revien­drons en détails sur le choix de cette tech­no­lo­gie dans la seconde par­tie du billet.

Défaillance d’un disque

Le 16 juillet à 3h29, un des disques du ser­veur a connu un pro­blème maté­riel. Le disque a auto­ma­ti­que­ment été éjec­té du RAID1, et le ser­veur a conti­nué à fonc­tion­ner nor­ma­le­ment sur le second disque — c’est le prin­cipe même du RAID. Ce genre de pro­blème n’est pas rare. Deux possibilités :

  • soit le disque est défi­ni­ti­ve­ment hors ser­vice, auquel cas il fau­dra le remplacer ;
  • soit le disque a connu un pro­blème tem­po­raire, et il suf­fit de le « redé­mar­rer » pour qu’il fonc­tionne à nou­veau normalement.

Notre équipe a pris connais­sance de l’in­ci­dent le matin — aucune astreinte n’a été déclen­chée, puisque cela n’a aucun impact sur le bon fonc­tion­ne­ment du ser­veur. Nous avons déci­dé de pro­gram­mer une inter­ven­tion pour le soir même (c’est une opé­ra­tion qui néces­site de mettre le ser­veur hors ser­vice pen­dant quelques minutes, nous pré­fé­rons donc le faire à des heures creuses).

Redémarrage du serveur

À 23h52, nous redé­mar­rons le ser­veur mysql1. Nous consta­tons que le disque qui était sor­ti du RAID fonc­tionne à nou­veau nor­ma­le­ment. Mais immé­dia­te­ment, nous obser­vons une cor­rup­tion du sys­tème de fichiers (XFS) sur lequel les bases de don­nées sont sto­ckées. Après une inves­ti­ga­tion rapide, nous com­pre­nons ce qu’il vient de se passer.

Les bases de don­nées sont sto­ckées sur un pseu­do-disque bcache, com­bi­nai­son vir­tuelle de nos disques méca­niques et de nos SSD. Lorsque Linux démarre, bcache scanne l’en­semble des disques phy­siques à la recherche d’une signa­ture. Cette signa­ture, lors­qu’elle est détec­tée, signi­fie que ce disque fait par­tie d’un pseu­do-disque bcache. bcache com­bine ensuite les disques trou­vés et crée le pseu­do-disque. Ces signa­tures sont ins­tal­lées une fois pour toutes à l’ins­tal­la­tion du système.

Nos deux disques méca­niques étaient en RAID1, ce qui veut dire que les deux disques étaient stric­te­ment iden­tiques et syn­chro­ni­sés. C’est, bien enten­du, le prin­cipe du RAID1 : si un disque tombe en panne, l’autre prend la relève puis­qu’il est sa copie conforme. Dans le cas de mysql1, à 23h52, nous avions donc :

  • le disque défaillant qui était res­té dans son état de 3h29 (avec des don­nées « périmées ») ;
  • le second disque qui conte­nait les « vraies » don­nées, à savoir les plus récentes.

Les deux disques avaient donc, du point de vue de bcache, des signa­tures iden­tiques. Au redé­mar­rage du ser­veur, bcache a donc assem­blé les SSD avec le disque défaillant (le pre­mier trou­vé) plu­tôt que le second disque, à jour. Or les SSD conte­naient des don­nées récentes. Nous avions donc un pseu­do-disque qui était la com­bi­nai­son de cer­taines don­nées de 23h52 (SSD) et de don­nées de 3h29 (disque défaillant).

Évidemment, ce pseu­do-disque ne conte­nait alors pas des don­nées cohé­rentes, d’où la cor­rup­tion de fichiers. Nous avons immé­dia­te­ment démon­té le sys­tème de fichiers pour recom­bi­ner les SSD avec le second disque, avec les don­nées à jour. Mais c’é­tait trop tard : le simple fait d’a­voir préa­la­ble­ment mon­té le pseu­do-disque bcache avec le disque défaillant a entrai­né des écri­tures sur les SSD. Les don­nées des SSD n’é­taient alors plus cohé­rentes avec le second disque.

Restauration des données

Malgré les cor­rup­tions du sys­tème de fichiers, une très grande pro­por­tion des don­nées res­tait lisible. Nous avons donc pris la déci­sion de res­tau­rer autant que pos­sible les don­nées à jour, plu­tôt que de res­tau­rer les sau­ve­gardes de la veille pour tout le monde.

La pre­mière étape a été de copier l’en­semble des don­nées (300 Go) sur un ser­veur tem­po­raire. Par sécu­ri­té, nous avons copié une seconde fois les don­nées, sur un second ser­veur tem­po­raire. Les don­nées du pre­mier ser­veur ont été uti­li­sées pour démar­rer MySQL (acces­sible uni­que­ment en interne) et essayer de récu­pé­rer le maxi­mum de bases pos­sible, ce qui a entrai­né des modi­fi­ca­tions sur les fichiers. Les don­nées du second ser­veur n’é­taient là que pour nous per­mettre de recom­men­cer le pro­ces­sus, si besoin.

La res­tau­ra­tion des don­nées (qui consis­tait essen­tiel­le­ment à exé­cu­ter “mys­ql­dump” sur chaque base) a pris du temps : la cor­rup­tion a entraî­né de nom­breux plan­tages de MySQL, ralen­tis­sant l’o­pé­ra­tion. Une fois que nous avions un dump SQL pour la grande majo­ri­té des bases (96 %), nous avons pu démar­rer la res­tau­ra­tion finale sur mysql1 (refor­ma­té entre temps). Les 4 % de bases cor­rom­pues ont ensuite été res­tau­rées depuis les sau­ve­gardes de la veille.

Dans cer­tains rares cas, les don­nées récu­pé­rées que nous pen­sions saines étaient fina­le­ment en par­tie cor­rom­pues. Les clients concer­nés ont pu nous contac­ter pour que nous res­tau­rions alors une sauvegarde.

Diminuer les risques à l’avenir

Commençons d’emblée par dire que la perte de don­nées est un risque qu’il est impos­sible de réduire à zéro. Les causes peuvent être mul­tiples : bug, erreur humaine, pro­blème maté­riel, acci­dent majeur, etc. C’est la rai­son pour laquelle les sau­ve­gardes existent. Cela ne veut tou­te­fois pas dire qu’on ne peut pas réduire davan­tage les risques.

Utilisation de technologies jeunes

L’incident a pour ori­gine un bug dans bcache. Il est donc légi­time de se deman­der si l’u­ti­li­sa­tion de bcache, une tech­no­lo­gie rela­ti­ve­ment jeune, était judicieux.

En règle géné­rale, plus une tech­no­lo­gie est jeune, plus le risque qu’elle pré­sente des dys­fonc­tion­ne­ments (mineurs ou majeurs) est éle­vé. Il faut donc juger si les avan­tages qu’ap­portent la tech­no­lo­gie jus­ti­fient la prise de risque. Naturellement, ce juge­ment évo­lue au fil du temps : plus la tech­no­lo­gie mûrit, plus les risques diminuent.

En ce qui concerne bcache, les avan­tages sont impor­tants : per­mettre d’aug­men­ter consi­dé­ra­ble­ment les per­for­mances sans sacri­fier l’es­pace disque. Rappelons que contrai­re­ment à la majo­ri­té des héber­geurs, nous n’im­po­sons aucune limite sur la taille des bases de données.

Nous sui­vons l’é­vo­lu­tion des tech­no­lo­gies hybrides SSD/disque méca­nique depuis déjà long­temps. Il en existe de nom­breuses, au-delà de bcache : dm-cacheEnhanceIOFlashCacheCacheCadebtier pour n’en citer qu’une par­tie. En début d’an­née, nous avons tes­té et com­pa­ré « en labo­ra­toire » plu­sieurs de ces solu­tions. Au terme de ces tests, nous avons déci­dé d’u­ti­li­ser bcache sur un ser­veur de pseu­do-pro­duc­tion : http11, sur lequel nous avons migré une poi­gnée de clients volon­taires. Pendant 4 mois, ce ser­veur a tour­né avec bcache sans pré­sen­ter le moindre pro­blème, tout en tenant ses pro­messes de per­for­mances accrues.

Précisons que bcache, déve­lop­pé par un ingé­nieur de Google, existe depuis 2010, et est consi­dé­ré comme stable par son auteur depuis 2011 — date de la der­nière décou­verte d’un bug pou­vant pro­vo­quer des cor­rup­tions de don­nées. Utilisé en pro­duc­tion par de nom­breuses per­sonnes et orga­ni­sa­tions depuis, il a été inté­gré à Linux en 2013 au terme d’une longue et sévère revue de code par plu­sieurs déve­lop­peurs seniors de Linux.

Notre déci­sion d’u­ti­li­ser bcache en pro­duc­tion est par­fai­te­ment assu­mée et nous n’es­ti­mons pas qu’il s’a­gisse d’une faute. Le bug, que nous avons depuis remon­té aux déve­lop­peurs, a été cor­ri­gé moins de 2h après, un dimanche soir. Une telle réac­ti­vi­té n’est qu’un atout sup­plé­men­taire pour bcache.

Améliorer la fiabilité de notre matériel

Deux élé­ments maté­riels ont, indi­rec­te­ment, conduit au bug :

  • le fait que le disque ait ren­con­tré un pro­blème tem­po­raire qui a pro­vo­qué son éjec­tion du RAID ;
  • le fait que nos châs­sis ne soient pas équi­pés de hot swap, nous obli­geant à redé­mar­rer le ser­veur pour relan­cer le disque (ou à débran­cher un ser­veur pour rem­pla­cer un disque).

Nous allons rem­pla­cer l’en­semble de nos ser­veurs au cours des pro­chains mois. Parmi leurs avan­tages, ils seront encore plus fiables qu’ac­tuel­le­ment. Nous aurons l’oc­ca­sion de reve­nir en détails sur cette migra­tion dans quelques semaines.

Ajouter une option de redondance

Plusieurs clients sou­hai­te­raient que nous pro­po­sions une option de redon­dance master/slave qui per­met­trait de pal­lier cer­tains types de pannes, dont l’in­ci­dent que nous avons eu. Cette option a néces­sai­re­ment un coût non négligeable.

Dites-nous dans les com­men­taires si vous seriez inté­res­sé par une telle option, qui aug­men­te­rait le prix d’un pack d’en­vi­ron 50 %.

En conclusion

Environ 300 bases de don­nées MySQL ont été cor­rom­pues et ont dû être res­tau­rées depuis les sau­ve­gardes de la veille, ce qui repré­sente moins de 4 % des bases sto­ckées sur mysql1, et moins de 1,5 % de l’en­semble des bases MySQL. Chaque client concer­né a été contac­té par mail, et nous leur réité­rons nos excuses.

Nous pré­pa­rons de gros chan­ge­ments internes des­ti­nés à amé­lio­rer encore davan­tage notre fia­bi­li­té, déjà très éle­vée. Vous en sau­rez plus très bientôt.

N’hésitez pas à nous faire vos retours et sug­ges­tions en com­men­taires. Nous sommes tou­jours pre­neurs. Nous remer­cions au pas­sage tous ceux qui nous ont appor­té leur sou­tien durant cet inci­dent, c’est tou­jours apprécié.

Nous sou­hai­tons enfin d’ex­cel­lentes vacances à tous ceux qui s’ap­prêtent à en prendre — et bon cou­rage à ceux qui en reviennent :)