[Explication approfondie de l'architecture et de la mise en œuvre de Yarn] 2-3 Bibliothèque de service de bibliothèque de base Yarn et bibliothèque d'événements

Dans un immense système distribué, comment les différents composants coordonnent-ils leur travail ? Comment les composants sont-ils découplés ? Comment les threads peuvent-ils fonctionner plus efficacement et réduire les inefficacités causées par le blocage ? Cette section présentera la bibliothèque de services et la bibliothèque d'événements de Yarn, et verra comment Yarn résout ces problèmes.

1. Bibliothèque de services

1. Introduction

Pour les objets à long cycle de vie, Yarn adopte un modèle basé sur les services pour les gérer, qui présente les caractéristiques suivantes :

  • Gestion par état : divisée en 4 états : NOTINITED(créé), INITED(initialisé), STARTED(démarré), STOPPED(arrêté).
  • Les modifications de l'état du service déclenchent d'autres actions.
  • Les services peuvent être composés de manière compositionnelle.

2) Brève analyse du code source

L'adresse du code source se trouve hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/servicedans Servicel'interface de .
Il définit les quatre états du service, ainsi que la transition d'état, l'acquisition d'informations, l'enregistrement et d'autres méthodes qui doivent être mises en œuvre.

public interface Service extends Closeable {
    
    

  public enum STATE {
    
    
    NOTINITED(0, "NOTINITED"),
    INITED(1, "INITED"),
    STARTED(2, "STARTED"),
    STOPPED(3, "STOPPED");
  }

  void init(Configuration config);
  void start();
  void stop();
  void close() throws IOException;
  void registerServiceListener(ServiceStateChangeListener listener);
  // ......

La classe abstraite AbstractServiceimplémente Servicel'interface et fournit l' Serviceimplémentation Les services non-composition peuvent directement hériter de cette classe abstraite et ensuite la développer.

public abstract class AbstractService implements Service {
    
    
  // 以 start 实现为例,执行后会触发其他的操作
  public void start() {
    
    
    if (isInState(STATE.STARTED)) {
    
    
      return;
    }
    //enter the started state
    synchronized (stateChangeLock) {
    
    
      if (stateModel.enterState(STATE.STARTED) != STATE.STARTED) {
    
    
        try {
    
    
          startTime = System.currentTimeMillis();
          serviceStart();
          if (isInState(STATE.STARTED)) {
    
    
            //if the service started (and isn't now in a later state), notify
            if (LOG.isDebugEnabled()) {
    
    
              LOG.debug("Service " + getName() + " is started");
            }
            notifyListeners();
          }
        } catch (Exception e) {
    
    
          noteFailure(e);
          ServiceOperations.stopQuietly(LOG, this);
          throw ServiceStateException.convert(e);
        }
      }
    }
  }

  // ......

Pour les services combinés tels que ResourceManager, NodeManager, etc., l'héritage est requis CompositeService. Il y aura un traitement logique pour les services composites.

  public List<Service> getServices() {
    
    
    synchronized (serviceList) {
    
    
      return new ArrayList<Service>(serviceList);
    }
  }

  protected void addService(Service service) {
    
    
    if (LOG.isDebugEnabled()) {
    
    
      LOG.debug("Adding service " + service.getName());
    }
    synchronized (serviceList) {
    
    
      serviceList.add(service);
    }
  }

2. Bibliothèque d'événements

Le problème avec les appels de fonction traditionnels :
l'ensemble du processus d'exécution est en série et synchrone. Lorsque vous appelez une autre fonction, vous devez attendre que la fonction se termine avant de continuer. Le schéma de principe est le suivant :
image.png

Afin de résoudre le problème des appels fonctionnels, le modèle de programmation **"event-driven"** peut être utilisé.

  • Tous les objets sont résumés dans des gestionnaires d'événements
  • Les gestionnaires d'événements sont associés les uns aux autres via des événements
  • Chaque gestionnaire d'événements gère un événement
  • Un autre événement est déclenché si nécessaire
  • Le traitement de chaque type d'événement peut être divisé en plusieurs étapes, représentées par une machine à états finis
  • L'important est qu'il y ait un **"Central Asynchronous Dispatcher (AsyncDispatcher)", ** responsable de la collecte et de la distribution des événements à traiter

Le schéma de principe est le suivant :
image.png

Grâce à la méthode ci-dessus, le programme peut avoir les caractéristiques d'un couplage faible et d'une cohésion élevée. Chaque module n'a besoin que de remplir sa propre fonction et, en même temps, d'améliorer l'efficacité de l'exécution. L'opération de fractionnement peut être envoyée via des événements.

3. Cas d'utilisation de la bibliothèque de services et de la bibliothèque d'événements

Cette section mettra en œuvre une version simplifiée MapReduce ApplicationMasterpour aider à comprendre comment utiliser le service et l'événement.
Semblable à MR, un travail sera divisé en plusieurs tâches pour l'exécution. Ainsi, les événements impliquant à la fois des objets de travail et de tâche. Et avoir une AsyncDispatcherpoignée d'expédition.
Le cas a été téléchargé sur github, veuillez cliquer sur ⭐️
https://github.com/Simon-Ace/hadoop-yarn-study-demo/tree/master/service-event-demo

a) Rubrique événements

Reportez-vous à l'implémentation de Task et Job Event dans le code source hadoop pour apporter quelques simplifications.
1. tâche

public enum TaskEventType {
    
    

  //Producer:Client, Job
  T_KILL,

  //Producer:Job
  T_SCHEDULE
}
public class TaskEvent extends AbstractEvent<TaskEventType> {
    
    

  private String taskID;

  public TaskEvent(String taskID, TaskEventType type) {
    
    
    super(type);
    this.taskID = taskID;
  }

  public String getTaskID() {
    
    
    return taskID;
  }
}

2, travail

public enum JobEventType {
    
    

  //Producer:Client
  JOB_KILL,

  //Producer:MRAppMaster
  JOB_INIT
}
public class JobEvent extends AbstractEvent<JobEventType> {
    
    

    private String jobID;

    public JobEvent(String jobID, JobEventType type) {
    
    
        super(type);
        this.jobID = jobID;
    }

    public String getJobId() {
    
    
        return jobID;
    }
}

2) Planificateur d'événements

  • Définir et enregistrer EventDispatcher
  • méthode d'initialisation et de démarrage du service
import com.shuofxz.event.JobEvent;
import com.shuofxz.event.JobEventType;
import com.shuofxz.event.TaskEvent;
import com.shuofxz.event.TaskEventType;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.service.CompositeService;
import org.apache.hadoop.service.Service;
import org.apache.hadoop.yarn.event.AsyncDispatcher;
import org.apache.hadoop.yarn.event.Dispatcher;
import org.apache.hadoop.yarn.event.EventHandler;

@SuppressWarnings("unchecked")
public class MyMRAppMaster extends CompositeService {
    
    
    private Dispatcher dispatcher;  // AsyncDispatcher
    private String jobID;
    private int taskNumber;         // 一个 job 包含的 task 数
    private String[] taskIDs;

    public MyMRAppMaster(String name, String jobID, int taskNumber) {
    
    
        super(name);
        this.jobID = jobID;
        this.taskNumber = taskNumber;
        taskIDs = new String[taskNumber];
        for (int i = 0; i < taskNumber; i++) {
    
    
            taskIDs[i] = this.jobID + "_task_" + i;
        }
    }

    public void serviceInit(Configuration conf) throws Exception {
    
    
        dispatcher = new AsyncDispatcher();
        dispatcher.register(JobEventType.class, new JobEventDispatcher()); // register a job
        dispatcher.register(TaskEventType.class, new TaskEventDispatcher()); // register a task
        addService((Service) dispatcher);
        super.serviceInit(conf);
    }

    public void serviceStart() throws Exception {
    
    
        super.serviceStart();
    }

    public Dispatcher getDispatcher() {
    
    
        return dispatcher;
    }

    private class JobEventDispatcher implements EventHandler<JobEvent> {
    
    
        public void handle(JobEvent event) {
    
    
            if (event.getType() == JobEventType.JOB_KILL) {
    
    
                System.out.println("Receive JOB_KILL event, killing all the tasks");
                for (int i = 0; i < taskNumber; i++) {
    
    
                    dispatcher.getEventHandler().handle(new TaskEvent(taskIDs[i], TaskEventType.T_KILL));
                }
            } else if (event.getType() == JobEventType.JOB_INIT) {
    
    
                System.out.println("Receive JOB_INIT event, scheduling tasks");
                for (int i = 0; i < taskNumber; i++) {
    
    
                    dispatcher.getEventHandler().handle(new TaskEvent(taskIDs[i], TaskEventType.T_SCHEDULE));
                }
            }
        }
    }

    private class TaskEventDispatcher implements EventHandler<TaskEvent> {
    
    
        public void handle(TaskEvent event) {
    
    
            if (event.getType() == TaskEventType.T_KILL) {
    
    
                System.out.println("Receive T_KILL event of task id " + event.getTaskID());
            } else if (event.getType() == TaskEventType.T_SCHEDULE) {
    
    
                System.out.println("Receive T_SCHEDULE event of task id " + event.getTaskID());
            }
        }
    }
}

3) Procédure d'essai

  • générer un nouveau travail
  • événement déclencheur JOB_KILLetJOB_INIT
public class MyMRAppMasterTest {
    
    
    public static void main(String[] args) {
    
    
        String jobID = "job_20221011_99";
        MyMRAppMaster appMaster = new MyMRAppMaster("My MRAppMaster Test", jobID, 10);
        YarnConfiguration conf = new YarnConfiguration(new Configuration());
        try {
    
    
            appMaster.serviceInit(conf);
            appMaster.serviceStart();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        appMaster.getDispatcher().getEventHandler().handle(new JobEvent(jobID, JobEventType.JOB_KILL));
        appMaster.getDispatcher().getEventHandler().handle(new JobEvent(jobID, JobEventType.JOB_INIT));
    }
}

Résultat de sortie :

Receive JOB_KILL event, killing all the tasks
Receive JOB_INIT event, scheduling tasks
Receive T_KILL event of task id job_20150723_11_task_0
Receive T_KILL event of task id job_20150723_11_task_1
Receive T_KILL event of task id job_20150723_11_task_2
Receive T_KILL event of task id job_20150723_11_task_3
Receive T_KILL event of task id job_20150723_11_task_4
Receive T_KILL event of task id job_20150723_11_task_5
Receive T_KILL event of task id job_20150723_11_task_6
Receive T_KILL event of task id job_20150723_11_task_7
Receive T_KILL event of task id job_20150723_11_task_8
Receive T_KILL event of task id job_20150723_11_task_9
Receive T_SCHEDULE event of task id job_20150723_11_task_0
Receive T_SCHEDULE event of task id job_20150723_11_task_1
Receive T_SCHEDULE event of task id job_20150723_11_task_2
Receive T_SCHEDULE event of task id job_20150723_11_task_3
Receive T_SCHEDULE event of task id job_20150723_11_task_4
Receive T_SCHEDULE event of task id job_20150723_11_task_5
Receive T_SCHEDULE event of task id job_20150723_11_task_6
Receive T_SCHEDULE event of task id job_20150723_11_task_7
Receive T_SCHEDULE event of task id job_20150723_11_task_8
Receive T_SCHEDULE event of task id job_20150723_11_task_9

4. Résumé

Cette section présente les bibliothèques de services et d'événements de Yarn.
La bibliothèque de services standardise les objets de type service avec un long cycle de vie, définit les quatre états du service, les méthodes à réaliser telles que l'enregistrement start-stop, et donne l'implémentation de base des services de type unique et de type combiné.
L'utilisation de la bibliothèque d'événements résout les problèmes de couplage élevé et d'inefficacité bloquante de l'appel de fonction d'origine. Une grande tâche peut être divisée en plusieurs petites tâches, et les petites tâches deviennent des événements différents pour déclencher le traitement. Chaque gestionnaire d'événements gère un type d'événement et un planificateur asynchrone central gère la collecte et la distribution des événements.
Enfin, un MR ApplicationMaster simplifié est utilisé pour combiner la bibliothèque d'événements et la bibliothèque de services, afin de mieux comprendre comment les utiliser ensemble dans le projet.
Pendant le processus d'apprentissage, écrire une démo peut mieux vous aider à comprendre les connaissances.


Article de référence :
"Hadoop Technology Insider - Analyse approfondie des principes de conception et de mise en œuvre de la structure du fil" Section 3.4

Je suppose que tu aimes

Origine blog.csdn.net/shuofxz/article/details/127308665
conseillé
Classement