c++ - sous - option de compilation




Compiler une application pour une utilisation dans des environnements hautement radioactifs (16)

Ce que vous demandez est un sujet assez complexe - difficile à répondre. Les autres réponses sont acceptables, mais elles ne couvrent qu’une petite partie de toutes les tâches que vous devez faire.

Comme indiqué dans les commentaires , il n'est pas possible de résoudre les problèmes matériels à 100%, mais il est possible avec une probabilité élevée de les réduire ou de les résoudre en utilisant diverses techniques.

Si j'étais vous, je créerais le logiciel du niveau d'intégrité de sécurité le plus élevé (SIL-4). Obtenez le document CEI 61513 (pour l'industrie nucléaire) et suivez-le.

Nous compilons une application C / C ++ intégrée qui est déployée dans un dispositif blindé dans un environnement bombardé de radiations ionisantes . Nous utilisons GCC et la compilation croisée pour ARM. Une fois déployée, notre application génère des données erronées et se bloque plus souvent que nous le souhaiterions. Le matériel est conçu pour cet environnement et notre application fonctionne sur cette plate-forme depuis plusieurs années.

Pouvons-nous apporter des modifications à notre code ou des améliorations à la compilation qui peuvent être apportées pour identifier / corriger les erreurs non corrigées et la corruption de mémoire provoquée par des événements uniques ? D'autres développeurs ont-ils réussi à réduire les effets néfastes des erreurs logicielles sur une application de longue durée?


Compte tenu des commentaires de Supercat, des tendances des compilateurs modernes, etc., je serais tenté de revenir à l’époque antique et d’écrire le code dans son ensemble en allocation d’allocation et en mémoire statique. Pour ce type de fiabilité absolue, je pense que l’assemblage n’engage plus une grande différence de coût par rapport au coût.


Il serait peut-être utile de savoir si cela signifie que le matériel doit être "conçu pour cet environnement". Comment corrige-t-il et / ou indique-t-il la présence d'erreurs SEU?

Dans un projet lié à l’exploration spatiale, nous avions un MCU personnalisé, qui déclencherait une exception / interruption sur les erreurs SEU, mais avec un certain retard, c’est-à-dire que certains cycles risquent de passer / que les instructions soient exécutées après celui qui a provoqué l’exception SEU.

Le cache de données était particulièrement vulnérable. Un gestionnaire invaliderait donc la ligne de cache incriminée et redémarrerait le programme. Seulement, en raison du caractère imprécis de l'exception, la séquence d'insns précédée de l'exception soulevant insn ne peut pas être redémarrée.

Nous avons identifié les séquences dangereuses (non redémarrables) (comme lw $3, 0x0($2) , suivies d'un insn, qui modifie les $2 données et ne dépend pas de celles-ci $3 ), et j'ai apporté des modifications à GCC afin qu'elles ne se produisent pas (par exemple, en dernier recours, en séparant les données). deux insns par a nop ).

Juste quelque chose à considérer ...


J'ai vraiment lu beaucoup de bonnes réponses!

Voici mon 2 cent: construire un modèle statistique de l'anomalie mémoire / registre, en écrivant un logiciel pour vérifier la mémoire ou pour effectuer des comparaisons fréquentes des registres. En outre, créez un émulateur, à la manière d'une machine virtuelle, sur lequel vous pouvez expérimenter le problème. Je suppose que si vous modifiez la taille de la jonction, la fréquence d'horloge, le fournisseur, le boîtier, etc., vous observerez un comportement différent.

Même la mémoire de notre ordinateur de bureau a un certain taux d'échec, ce qui n'empêche pas le travail quotidien.


Puisque vous demandez spécifiquement des solutions logicielles et que vous utilisez le C ++, pourquoi ne pas utiliser la surcharge d'opérateur pour créer vos propres types de données sécurisés? Par exemple:

Au lieu d'utiliser uint32_t (et double , int64_t etc.), créez votre propre SAFE_uint32_t qui contient un multiple (minimum de 3) de uint32_t. Surchargez toutes les opérations que vous voulez effectuer (* + - / << >> = ==! = Etc), et faites en sorte que les opérations surchargées s'exécutent indépendamment sur chaque valeur interne, c'est-à-dire ne le faites pas une fois et copiez le résultat. Avant et après, vérifiez que toutes les valeurs internes correspondent. Si les valeurs ne correspondent pas, vous pouvez mettre à jour le mauvais en fonction de la valeur la plus courante. S'il n'y a pas de valeur commune, vous pouvez notifier en toute sécurité qu'il y a une erreur.

De cette manière, peu importe si une corruption survient dans l'ALU, les registres, la RAM ou sur un bus, vous aurez toujours plusieurs tentatives et de très bonnes chances de détecter les erreurs. Notez cependant que cela ne fonctionne que pour les variables que vous pouvez remplacer - votre pointeur de pile, par exemple, sera toujours susceptible.

Histoire parallèle: je suis tombé sur un problème similaire, également sur une vieille puce ARM. Il s’est avéré qu’il s’agissait d’une chaîne d’outils qui utilisait une ancienne version de GCC qui, avec la puce spécifique que nous utilisions, provoquait un bogue dans certains cas extrêmes qui altéraient (parfois) la transmission de valeurs à des fonctions. Assurez-vous que votre appareil n'a pas de problèmes avant de le blâmer sur l'activité radio, et oui, parfois c'est un bug du compilateur =)


Quelqu'un a mentionné l'utilisation de puces plus lentes pour empêcher les ions de retourner les bits aussi facilement. De la même manière, utilisez peut-être un cpu / ram spécialisé qui utilise plusieurs bits pour stocker un seul bit. Nous fournissons donc une tolérance de panne matérielle car il serait très improbable que tous les bits soient inversés. Donc, 1 = 1111, mais il faudrait se faire frapper 4 fois pour être réellement inversé. (4 pourrait être un mauvais nombre car si 2 bits sont retournés, c'est déjà ambigu). Donc, si vous choisissez 8, vous obtenez 8 fois moins de RAM et un temps d’accès légèrement plus lent, mais une représentation des données beaucoup plus fiable. Vous pourriez probablement faire cela à la fois au niveau logiciel avec un compilateur spécialisé (allouer x quantité d'espace supplémentaire pour tout) et une implémentation linguistique (encapsuleurs d'écriture pour les structures de données qui allouent des choses de cette façon).Ou du matériel spécialisé ayant la même structure logique mais le faisant dans le micrologiciel.


Tout d'abord, concevez votre application en fonction de l'échec . Assurez-vous que, dans le cadre d'un fonctionnement en flux normal, il est prévu de réinitialiser (en fonction de votre application et du type de défaillance, qu'elle soit matérielle ou matérielle). Il est difficile d’obtenir une solution parfaite: les opérations critiques nécessitant un certain degré de transactalité peuvent nécessiter une vérification et un ajustement au niveau de l’assemblage afin que toute interruption en un point clé ne puisse pas entraîner des commandes externes incohérentes. Échouez rapidement dès qu'une corruption de mémoire ou une déviation du flux de contrôle irrécupérable sont détectées. Consignez les échecs si possible.

Deuxièmement, si possible, corrigez la corruption et continuez . Cela signifie que le contrôle et la fixation des tables constantes (et du code de programme si vous le pouvez) souvent; peut-être avant chaque opération majeure ou lors d'une interruption programmée, et stocker des variables dans des structures qui se corrigent automatiquement (à nouveau avant chaque opération majeure ou lors d'une interruption programmée, prenez un vote à la majorité des voix à partir de 3 et corrigez s'il s'agit d'un seul écart). Consignez les corrections si possible.

Troisièmement, échec du test . Configurez un environnement de test reproductible qui retourne les bits en mémoire de manière aléatoire. Cela vous permettra de reproduire des situations de corruption et vous aidera à concevoir votre application en fonction de celles-ci.


Un point que personne ne semble avoir mentionné. Vous dites que vous développez dans GCC et que vous effectuez une compilation croisée sur ARM. Comment savez-vous que vous n'avez pas de code qui présuppose de la RAM libre, de la taille d'un nombre entier, de la taille d'un pointeur, du temps requis pour effectuer une opération donnée, du temps de fonctionnement continu du système ou de tout ce genre de choses? C'est un problème très courant.

La réponse est généralement le test unitaire automatisé. Rédigez des faisceaux de test qui exercent le code sur le système de développement, puis exécutez les mêmes faisceaux de test sur le système cible. Cherchez les différences!

Recherchez également les erreurs sur votre périphérique intégré. Vous constaterez peut-être qu'il y a quelque chose à propos de "ne faites pas ceci parce qu'il va planter, donc activez cette option du compilateur et le compilateur contournera le problème".

En bref, les sources de bogues les plus probables sont les bogues de votre code. Tant que vous n'êtes pas sûr que ce n'est pas le cas, ne vous inquiétez pas (encore) des modes de défaillance plus ésotériques.


Voici une énorme quantité de réponses, mais je vais essayer de résumer mes idées à ce sujet.

Quelque chose qui tombe en panne ou qui ne fonctionne pas correctement peut résulter de vos propres erreurs - il devrait alors être facile à résoudre lorsque vous localisez le problème. Mais il existe également une possibilité de défaillance matérielle - ce qui est difficile, voire impossible, à résoudre globalement.

Je recommanderais d’abord d’essayer d’attraper la situation problématique en se connectant (pile, registres, appels de fonction) - soit en les enregistrant quelque part dans un fichier, soit en les transmettant directement ("oh non - je tombe en panne").

La récupération d’une telle situation d’erreur est soit un redémarrage (si le logiciel est toujours actif), soit une réinitialisation matérielle (par exemple, hw watchdogs). Plus facile de commencer à partir du premier.

Si le problème est lié au matériel, alors la journalisation devrait vous aider à identifier dans quel problème d'appel de fonction se produit et peut vous donner une connaissance approfondie de ce qui ne fonctionne pas et où.

De plus, si le code est relativement complexe - il est logique de le "diviser pour le vaincre" - ce qui signifie que vous supprimez / désactivez certains appels de fonction pour lesquels vous soupçonnez que le problème est - en désactivant généralement la moitié du code et en activant une autre moitié - vous pouvez obtenir un "ça marche" / "ne fonctionne pas" type de décision après laquelle vous pouvez vous concentrer sur une autre moitié du code. (Où est le problème)

Si un problème survient après un certain temps (on peut alors suspecter un dépassement de capacité de la pile), il est donc préférable de surveiller les registres de points de la pile, s'ils augmentent constamment.

Et si vous parvenez à minimiser complètement votre code jusqu'à ce que le type d'application "hello world" - et qu'il échoue toujours de manière aléatoire - des problèmes matériels sont attendus - et il doit y avoir une "mise à niveau matérielle" - ce qui signifie inventer un tel cpu / ... combinaison de matériel qui supporterait mieux les radiations.

La chose la plus importante est probablement de savoir comment récupérer vos journaux si la machine est complètement arrêtée / réinitialisée / ne fonctionne pas - probablement la première chose à faire pour bootstap - est de rentrer chez soi si une situation problématique est découverte.

Si votre environnement peut également transmettre un signal et recevoir une réponse, vous pouvez essayer de créer une sorte d’environnement de débogage à distance en ligne, mais vous devez disposer au moins de supports de communication en état de fonctionnement et de processeurs / RAM en état de fonctionnement. Et par débogage à distance, je veux dire soit l’approche de type stub GDB / gdb, soit votre propre implémentation de ce dont vous avez besoin pour obtenir de votre application (par exemple, télécharger les fichiers journaux, télécharger la pile d’appel, télécharger ram, redémarrer).


Vous voulez 3+ machines esclaves avec un maître en dehors de l'environnement de rayonnement. Toutes les E / S passent par le maître qui contient un mécanisme de vote et / ou de nouvelle tentative. Les esclaves doivent avoir chacun un chien de garde matériel et l'appel à les cogner devrait être entouré de CRC ou similaires afin de réduire la probabilité de choc involontaire. Les transferts doivent être contrôlés par le maître, ainsi la connexion perdue avec le maître équivaut à un redémarrage dans quelques secondes.

L'un des avantages de cette solution est que vous pouvez utiliser la même API pour le maître et pour les esclaves, ainsi la redondance devient une fonctionnalité transparente.

Edit: D'après les commentaires, je ressens le besoin de clarifier "l'idée de CRC". La possibilité que l'esclave bouge son propre chien de garde soit proche de zéro si vous entourez la bosse de CRC ou que vous effectuez des contrôles de synthèse sur des données aléatoires du maître. Ces données aléatoires ne sont envoyées par le maître que lorsque l'esclave examiné est aligné sur les autres. Les données aléatoires et CRC / digest sont immédiatement effacés après chaque bosse. La fréquence de déclenchement maître-esclave devrait être plus du double du délai d'attente du chien de garde. Les données envoyées par le maître sont générées de manière unique à chaque fois.


Ce qui pourrait vous aider est un watchdog . Les chiens de garde ont été largement utilisés en informatique industrielle dans les années 1980. Les pannes matérielles étaient alors beaucoup plus courantes - une autre réponse se réfère également à cette période.

Un chien de garde est une fonctionnalité matérielle / logicielle combinée. Le matériel est un simple compteur qui décompte d’un nombre (par exemple 1023) à zéro. TTL ou une autre logique pourrait être utilisée.

Le logiciel a été conçu pour qu’une seule routine surveille le bon fonctionnement de tous les systèmes essentiels. Si cette routine se termine correctement = trouve que l'ordinateur fonctionne correctement, il remet le compteur à 1023.

La conception générale est telle que, dans des circonstances normales, le logiciel empêche le compteur matériel d’atteindre zéro. Si le compteur atteint zéro, le matériel du compteur effectue sa tâche unique et réinitialise l'ensemble du système. Du point de vue du compteur, zéro est égal à 1024 et le compteur poursuit le compte à rebours.

Ce chien de garde s'assure que l'ordinateur connecté est redémarré dans de très nombreux cas de défaillance. Je dois avouer que je ne connais pas le matériel capable de remplir une telle fonction sur les ordinateurs actuels. Les interfaces avec le matériel externe sont maintenant beaucoup plus complexes qu’avant.

Un inconvénient inhérent au chien de garde est que le système n'est pas disponible à partir du moment où il échoue jusqu'à ce que le compteur du chien de garde atteigne zéro + le temps de redémarrage. Bien que ce délai soit généralement beaucoup plus court que toute intervention humaine ou externe, l'équipement pris en charge devra pouvoir fonctionner sans contrôle informatique pour cette période.


Il est peut-être possible d’utiliser C pour écrire des programmes qui se comportent de manière robuste dans de tels environnements, mais seulement si la plupart des formes d’optimisation du compilateur sont désactivées. Les compilateurs optimiseurs sont conçus pour remplacer de nombreux modèles de codage apparemment redondants par des modèles "plus efficaces", et peuvent ne pas avoir la moindre idée que le programmeur teste x==42 alors que le compilateur sait qu'il est impossible que x puisse contenir autre chose, c'est parce le programmeur veut empêcher l'exécution de certains codes avec x ayant une autre valeur, même dans les cas où le seul moyen de conserver cette valeur serait que le système reçoive une sorte de problème électrique.

Déclarer des variables comme étant volatile est souvent utile, mais peut ne pas être une panacée. Il est particulièrement important de noter que le codage sécurisé nécessite souvent que les opérations dangereuses comportent des verrouillages matériels qui nécessitent plusieurs étapes pour être activés, et que le code soit écrit en utilisant le modèle:

... code that checks system state
if (system_state_favors_activation)
{
  prepare_for_activation();
  ... code that checks system state again
  if (system_state_is_valid)
  {
    if (system_state_favors_activation)
      trigger_activation();
  }
  else
    perform_safety_shutdown_and_restart();
}
cancel_preparations();

Si un compilateur traduit le code de manière relativement littérale, et si toutes les vérifications de l'état du système sont répétées après le prepare_for_activation() , le système peut prepare_for_activation() la prepare_for_activation() - prepare_for_activation() événements uniques plausibles, même ceux qui corrompraient de manière arbitraire le compteur de programme et empiler. Si un problème survient juste après un appel à prepare_for_activation() , cela impliquerait que l'activation aurait été appropriée (puisqu'il n'y a aucune autre raison que prepare_for_activation() aurait été appelé avant le problème). Si le problème entraînait une prepare_for_activation() code avec prepare_for_activation() , mais qu'aucun événement subséquent ne survienne, il ne serait pas possible pour le code d'atteindre ultérieurement trigger_activation() sans avoir passé le contrôle de validation ou appelé en premier lieu cancel_preparations [si la pile échoue, L’exécution pourrait passer à un endroit juste avant trigger_activation() après le contexte prepare_for_activation() , mais l’appel de cancel_preparations() aurait eu lieu entre les appels de prepare_for_activation() et de trigger_activation() , rendant ainsi le dernier appel inoffensif.

Un tel code peut être sûr en C traditionnel, mais pas avec les compilateurs C modernes. De tels compilateurs peuvent être très dangereux dans ce type d’environnement car agressifs, ils s’efforcent d’inclure uniquement du code qui sera pertinent dans des situations pouvant survenir via un mécanisme bien défini et dont les conséquences seraient également bien définies. Un code dont le but est de détecter et de nettoyer après une défaillance peut, dans certains cas, aggraver les choses. Si le compilateur détermine que la tentative de récupération invoque dans certains cas un comportement indéfini, il peut en déduire que les conditions qui nécessiteraient une telle récupération dans de tels cas ne peuvent pas se produire, éliminant ainsi le code qui les aurait vérifiées.


La NASA a rédigé un document sur les logiciels durcis par les radiations . Il décrit trois tâches principales:

  1. Contrôle régulier de la mémoire pour les erreurs, puis élimination de ces erreurs,
  2. des mécanismes robustes de récupération d'erreur, et
  3. la possibilité de reconfigurer si quelque chose ne fonctionne plus.

Notez que la fréquence d'analyse de la mémoire doit être assez fréquente pour que les erreurs multibits se produisent rarement, car la plupart des mémoires ECC peuvent récupérer des erreurs d'un seul bit, et non des erreurs multibits.

La reprise sur incident robuste inclut le transfert de flux de contrôle (généralement le redémarrage d’un processus à un point antérieur à l’erreur), la libération des ressources et la restauration des données.

Leur principale recommandation pour la restauration des données consiste à en éviter le besoin en faisant en sorte que les données intermédiaires soient traitées de manière temporaire, de sorte que tout redémarrage avant l'erreur ramène également les données à un état fiable. Cela semble similaire au concept de "transactions" dans les bases de données.

Ils discutent des techniques particulièrement adaptées aux langages orientés objet tels que C ++. Par exemple

  1. CCE basés sur des logiciels pour des objets de mémoire contigus
  2. Programmation par contrat : vérification des conditions préalables et des conditions ultérieures, puis vérification de l'objet pour vérifier qu'il est toujours dans un état valide.

Et, il se trouve que la NASA a utilisé le C ++ pour d’importants projets tels que Mars Rover .

L'abstraction et l'encapsulation de classes C ++ ont permis un développement et des tests rapides entre plusieurs projets et développeurs.

Ils ont évité certaines fonctionnalités C ++ susceptibles de créer des problèmes:

  1. Exceptions
  2. Modèles
  3. Iostream (pas de console)
  4. Héritage multiple
  5. Surcharge de l'opérateur (autre que new et delete )
  6. Allocation dynamique (utilisation d’un pool de mémoire dédiée et new emplacement pour éviter toute possibilité de corruption du tas du système).

Travaillant depuis environ 4 à 5 ans avec le développement de logiciels / micrologiciels et les tests d’environnement de satellites miniaturisés *, je voudrais partager mon expérience ici.

* ( les satellites miniaturisés sont beaucoup plus sujets aux perturbations d'un événement que les plus gros satellites en raison de la taille relativement petite et limitée de ses composants électroniques )

Pour être très concis et direct: il n’existe aucun mécanisme permettant de récupérer d’une situation détectable ou erronée par le logiciel / micrologiciel lui-même sans , au moins, une copie de la version de travail minimale du logiciel / micrologiciel quelque part à des fins de récupération - et avec le matériel pris en charge la reprise (fonctionnelle).

Maintenant, cette situation est normalement gérée à la fois au niveau du matériel et du logiciel. Ici, comme vous le demandez, je partagerai ce que nous pouvons faire au niveau logiciel.

  1. ... but de la récupération ... Fournir la possibilité de mettre à jour / recompiler / reflasher votre logiciel / micrologiciel dans un environnement réel. C’est une fonctionnalité presque indispensable pour tout logiciel / micrologiciel dans un environnement fortement ionisé. Sans cela, vous pourriez avoir autant de logiciels / matériels redondants que vous le souhaitez, mais à un moment donné, ils vont tous exploser. Alors, préparez cette fonctionnalité!

  2. ... version minimale de travail ... Avez réactif, plusieurs copies, version minimale du logiciel / firmware dans votre code. C'est comme le mode sans échec sous Windows. Au lieu de n'avoir qu'une seule version de votre logiciel entièrement fonctionnelle, vous devez disposer de plusieurs copies de la version minimale de votre logiciel / micrologiciel. La taille minimale de la copie minimale est généralement bien inférieure à celle de la copie complète et ne présente presque toujours que les deux ou trois caractéristiques suivantes:

    1. capable d'écouter pour commander depuis un système externe,
    2. capable de mettre à jour le logiciel / firmware actuel,
    3. capable de surveiller les données de maintenance de l'opération de base.
  3. ... copier ... quelque part ... Avoir un logiciel / firmware redondant quelque part.

    1. Vous pouvez, avec ou sans matériel redondant, essayer d’avoir un logiciel / micrologiciel redondant dans votre ARM uC. Cela se fait normalement en ayant deux ou plusieurs logiciels / microprogrammes identiques dans des adresses séparées qui s'envoient des pulsations - mais un seul sera actif à la fois. Si un ou plusieurs logiciels / micrologiciels sont réputés ne pas répondre, passez à l’autre logiciel / micrologiciel. L’avantage de cette approche est que nous pouvons avoir un remplacement fonctionnel immédiatement après une erreur - sans aucun contact avec le système / la partie externe responsable de la détection et de la réparation de l’erreur (dans le cas d’un satellite, c’est généralement le centre de contrôle de la mission ( MCC)).

      Strictement parlant, sans matériel redondant, l'inconvénient est que vous ne pouvez pas éliminer tous les points de défaillance. Au minimum, vous aurez toujours un seul point d'échec, qui est le commutateur lui-même (ou souvent le début du code). Néanmoins, pour un appareil dont la taille est limitée dans un environnement fortement ionisé (tel que les satellites pico / femto), la réduction du point unique de pannes à un point sans matériel supplémentaire sera toujours utile. Un peu plus, le code pour le basculement serait certainement bien inférieur au code de l'ensemble du programme, ce qui réduirait considérablement le risque d'y inclure un événement unique.

    2. Mais si vous ne le faites pas, vous devez avoir au moins une copie dans votre système externe qui peut entrer en contact avec l'appareil et mettre à jour le logiciel / micrologiciel (dans le cas du satellite, il s'agit à nouveau du centre de contrôle de mission).

    3. Vous pouvez également avoir la copie dans votre mémoire permanente sur votre appareil, ce qui peut être déclenché pour restaurer le logiciel / micrologiciel du système en cours d'exécution.
  4. ... détectable situation erronée .. L'erreur doit être détectable , généralement par le circuit de correction / détection des erreurs matérielles ou par un petit morceau de code pour la correction / détection des erreurs. Il est préférable de mettre un tel code petit, multiple et indépendant du logiciel / firmware principal. Sa tâche principale est uniquement de vérifier / corriger. Si le circuit matériel / le microprogramme est fiable (par exemple, il est plus résistant aux radiations que les restes - ou comporte plusieurs circuits / logiques), vous pouvez alors envisager de le corriger. Mais si ce n'est pas le cas, il est préférable de le définir comme une détection d'erreur. La correction peut être effectuée par un système / périphérique externe. Pour la correction d'erreur, vous pouvez envisager d'utiliser un algorithme de correction d'erreur de base tel que Hamming / Golay23, car ils peuvent être implémentés plus facilement dans le circuit / logiciel. Mais cela dépend finalement de la capacité de votre équipe. Pour la détection d'erreur, le CRC est normalement utilisé.

  5. ... le matériel supportant la reprise Venons-en maintenant à l'aspect le plus difficile de ce problème. En fin de compte, la récupération nécessite que le matériel responsable de la récupération soit au moins fonctionnel. Si le matériel est en panne de manière permanente (normalement après que sa dose ionisante totale ait atteint un certain niveau), il n’ya (malheureusement) aucun moyen pour le logiciel d’aider à la récupération. Ainsi, le matériel est à juste titre la préoccupation la plus importante pour un appareil exposé à un niveau de rayonnement élevé (tel que le satellite).

En plus de la suggestion ci-dessus consistant à anticiper l'erreur du micrologiciel en raison d'un événement perturbé, j'aimerais également vous suggérer d'avoir:

  1. Détection d'erreur et / ou algorithme de correction d'erreur dans le protocole de communication entre sous-systèmes. C’est un autre impératif pour éviter les signaux incomplets / erronés provenant d’autres systèmes.

  2. Filtrez dans votre lecture ADC. Ne pas utiliser la lecture ADC directement. Filtrez-le par filtre médian, filtre moyen ou tout autre filtre - ne faites jamais confiance à une valeur de lecture unique. Échantillon plus, pas moins - raisonnablement.


Vous pouvez également être intéressé par la littérature abondante sur le sujet de la tolérance algorithmique aux pannes. Cela inclut l'ancienne affectation: écrivez une sorte qui trie correctement ses entrées lorsqu'un nombre constant de comparaisons échouera (ou, la version légèrement plus diabolique, lorsque le nombre asymptotique de comparaisons échouées sera proportionnel à log(n) pour n comparaisons).

Un article à commencer par la lecture est l'article de 1984 de Huang et Abraham intitulé " Tolérance aux pannes basée sur un algorithme pour les opérations matricielles ". Leur idée est vaguement similaire au calcul crypté homomorphique (mais ce n’est pas vraiment la même chose, car ils tentent de détecter / corriger les erreurs au niveau de l’opération).

Un descendant plus récent de ce document est Bosilca, Delmas, Dongarra et Langou " La tolérance de panne basée sur un algorithme appliquée au calcul haute performance ".


Cette réponse suppose que vous êtes soucieux de disposer d’un système qui fonctionne correctement, en plus d’un système dont le coût est minimal ou rapide; la plupart des gens qui jouent avec des objets radioactifs attachent de l'importance à la correction / sécurité plutôt qu'à la vitesse

Plusieurs personnes ont suggéré des modifications matérielles que vous pouvez apporter (bon - il y a déjà beaucoup de bonnes choses dans les réponses et je n'ai pas l'intention de les répéter toutes), et d'autres ont suggéré la redondance (excellent en principe), mais je ne pense pas. n'importe qui a suggéré comment cette redondance pourrait fonctionner dans la pratique. Comment échouez-vous? Comment savez-vous quand quelque chose a «mal tourné»? De nombreuses technologies fonctionnent sur le principe que tout fonctionnera, et l'échec est donc une tâche délicate à gérer. Cependant, certaines technologies informatiques distribuées conçues pour l’échelle prévoient une défaillance (après tout avec suffisamment d’échelle, la défaillance d’un nœud sur plusieurs est inévitable quel que soit le MTBF d’un nœud unique); vous pouvez exploiter cela pour votre environnement.

Voici quelques idées:

  • Assurez-vous que tout votre matériel est répliqué n fois (où n est supérieur à 2, et de préférence impair), et que chaque élément matériel peut communiquer entre eux. Ethernet est un moyen évident de le faire, mais il existe de nombreux autres itinéraires beaucoup plus simples qui offriraient une meilleure protection (par exemple, CAN). Réduisez au minimum les composants communs (même les blocs d'alimentation). Cela peut vouloir dire échantillonner les entrées ADC à plusieurs endroits, par exemple.

  • Assurez-vous que l'état de votre application se trouve dans un emplacement unique, par exemple dans une machine à états finis. Cela peut être entièrement basé sur la RAM, mais n'empêche pas un stockage stable. Il sera donc stocké à plusieurs endroits.

  • Adoptez un protocole de quorum pour les changements d'état. Voir RAFT pour un exemple. Comme vous travaillez en C ++, il existe des bibliothèques bien connues pour cela. Les modifications apportées au FSM ne seraient effectuées que lorsque la majorité des nœuds seraient d'accord. Utilisez une bonne bibliothèque connue pour la pile de protocoles et le protocole de quorum plutôt que d'en lancer une vous-même, sinon tout votre bon travail sur la redondance sera gaspillé lorsque le protocole de quorum sera raccroché.

  • Assurez-vous de la somme de contrôle (par exemple, CRC / SHA) de votre FSM et stockez le CRC / SHA dans le FSM lui-même (en plus de la transmission dans le message et de la compilation des messages eux-mêmes). Demandez aux nœuds de vérifier régulièrement leur FSM par rapport à cette somme de contrôle, aux messages entrants de la somme de contrôle, et vérifiez que leur somme de contrôle correspond à la somme de contrôle du quorum.

  • Créez autant de contrôles internes que possible dans votre système, en faisant en sorte que les nœuds détectant leur propre défaillance redémarrent (mieux que de continuer à travailler à moitié si vous avez suffisamment de nœuds). Essayez de les laisser se retirer proprement du quorum lors du redémarrage au cas où ils ne reviendraient pas. Au redémarrage, demandez-leur de contrôler l'image du logiciel (et tout ce qu'ils chargent) et effectuez un test de RAM complet avant de se réintroduire dans le quorum.

  • Utilisez du matériel pour vous aider, mais faites-le avec précaution. Par exemple, vous pouvez obtenir de la mémoire RAM ECC et lire / écrire régulièrement afin de corriger les erreurs ECC (et de paniquer si l’erreur est non corrigible). Cependant (de mémoire), la RAM statique est beaucoup plus tolérante aux rayonnements ionisants que la mémoire DRAM, il est donc préférable d’utiliser la mémoire DRAM statique. Voir le premier point sous «des choses que je ne ferais pas».

Supposons que chaque nœud ait 1% de chance d'échouer en une journée et supposons que vous pouvez rendre les échecs totalement indépendants. Avec 5 nœuds, il en faut trois pour échouer en un jour, ce qui représente une chance de 0,001%. Avec plus, eh bien, vous avez l'idée.

Choses que je ne ferais pas :

  • Sous-estimez la valeur de ne pas avoir le problème pour commencer. À moins que le poids ne vous préoccupe, un gros bloc de métal autour de votre appareil constituera une solution beaucoup moins chère et plus fiable qu'une équipe de programmeurs ne peut imaginer. Le couplage optique des entrées d’EMI pose un problème, etc. Peu importe, tentez, lors de l’approvisionnement en composants, d’alimenter ceux qui répondent le mieux aux rayonnements ionisants.

  • Rouler vos propres algorithmes . Les gens ont déjà fait ce genre de choses. Utilisez leur travail. La tolérance aux pannes et les algorithmes distribués sont difficiles. Utilisez le travail des autres si possible.

  • Utilisez des paramètres de compilateur compliqués dans l’espoir naïf de détecter davantage d’échecs. Si vous avez de la chance, vous pourrez détecter plus d'échecs. Plus probablement, vous utiliserez un chemin de code dans le compilateur qui a été moins testé, en particulier si vous l'avez lancé vous-même.

  • Utilisez des techniques qui n'ont pas été testées dans votre environnement. La plupart des personnes qui écrivent des logiciels à haute disponibilité doivent simuler les modes de défaillance pour vérifier le bon fonctionnement de leur HA, et omettent de nombreux modes de défaillance. Vous êtes dans la "chance" d'avoir des échecs fréquents à la demande. Testez donc chaque technique et assurez-vous que son application améliore réellement le MTBF d’un niveau qui dépasse la complexité pour l’introduire (avec la complexité viennent des bugs). Appliquez ceci en particulier à mon avis sur les algorithmes de quorum, etc.





fault-tolerance