2017-01-12 2 views
1

j'ai écrit un programme de collecte de journal en déplacement, qui gère un tas de goroutines comme suit:golang: comment déboguer état de course possible

  1. routine A exécute serveur HTTP, permet aux utilisateurs d'afficher les informations du journal
  2. la routine B exécute le serveur UDP, permet aux messages de journal d'être envoyés à partir de LAN
  3. routine C exécute un temporisateur, qui interroge/télécharge périodiquement des archives de journal zippées à partir d'un serveur de fichiers HTTP interne (ne fait pas partie du programme)
  4. routine B & C à la fois envoyer des messages traités à un canal 0 La routine D exécute une boucle for for {} avec une instruction select qui reçoit un message du canal et le vide sur le disque
  5. il existe quelques autres routines go comme une routine pour analyser les archives de journal générées par la routine D vers Créer des index SQLite etc.

Le programme rencontre un problème: après quelques heures d'exécution, le serveur HTTP de visionneuse de journal fonctionne toujours correctement, mais aucun message ne provient des routines UDP ou fileserver. Je sais qu'il y a des messages de journal sans fin envoyant à partir de différents canaux, aussi si je redémarre le programme, il commence à traiter les journaux entrants à nouveau.

J'ai ajouté -race au compilateur, et en effet trouver un code problématique, et j'ai corrigé ces, mais toujours, le problème persiste. De plus, bien qu'il y ait des problèmes racistes, l'ancien code de version qui s'exécute sur notre serveur de production fonctionne bien, quel que soit le code racé.

Ma question est, comment puis-je procéder pour localiser le problème. Ce qui suit est la boucle de clé dans ma routine de traitement de journal:

for { 
    select { 
    case msg := <-logCh: 
     logque.Cache(msg) 
    case <-time.After(time.Second): 
    } 
    if time.Since(lastFlush) >= 3 * time.Second { 
     logque.Flush() 
     lastFlush = time.Now() 
    } 
} 
+0

Regardez une trace de la pile lorsque le serveur cesse de fonctionner et de voir où chaque goroutine est bloqué. – JimB

+0

comment regarder trace de la pile pendant que le programme fonctionne bien? Notez que rien ne semble être faux, juste que la routine de minuterie n'imprime pas de message pendant qu'elle est déclenchée, et que le serveur UDP cesse de recevoir des messages, et rien n'a été produit sur la console – xrfang

+0

Vous pouvez envoyer un SIGQUIT pour quitter avec une trace de pile, configurer un Gestionnaire http ou gestionnaire de signal pour en imprimer un à la demande, utiliser le point de terminaison pprof goroutine, etc. Vos goruotines sont bloquées pour une raison quelconque, vous voulez donc voir pourquoi. – JimB

Répondre

0

J'ai finalement trouvé le code qui a créé le blocage. Dans le code suivant:

for { 
    select { 
    case msg := <-logCh: 
     logque.Cache(msg) 
    case <-time.After(time.Second): 
    } 
    if time.Since(lastFlush) >= 3 * time.Second { 
     logque.Flush() 
     lastFlush = time.Now() 
    } 
} 

logque.Flush intérieur() il y a un code qui génèrent les messages du journal qui, à son tour écrire dans le canal, a finalement provoqué remplissage de la mémoire tampon du canal vers le haut. Cela se produit uniquement lorsque j'active le mode de débogage, le code de production ne le fait pas dans la méthode Flush().

Pour répondre à ma propre question, la méthode que je l'habitude de clouer le problème est assez simple:

if len(logch) >= LOG_CHANNEL_CAP { 
    //drop the message or store it into 
    //secondary buffer... 
    return 
} 
logch <- msg 
+0

Bien que le problème soit résolu, je suis toujours intéressé par la façon de trouver une raison de blocage à la manière d'une boîte noire. Comme proposé par @JimB, casser un morceau de code courant et inspecter ses informations de trace de pile, est-ce possible? – xrfang