ZooKeeper aprendiendo el análisis del código fuente de ZooKeeper

1. Análisis macro de la estructura fuente de ZooKeeper

  Código fuente del análisis macro de ZooKeeper, como se muestra a continuación:

        

 

  Para analizar el código fuente, primero debe analizar toda la macro de estructura de ZooKeeper. Debe saber que ZooKeeper se divide en dos partes: el clúster de servidores y el cliente.

  El servidor:

  • Cada servidor ZooKeeper tiene tres estados: inicialización, ejecución y apagado. Por lo tanto, cuando todos los servidores se ejecutan para formar un clúster de zookeeper, pueden proporcionar servicios externos (también se puede ejecutar una sola máquina);
  • Después de que el servidor inicia el servicio, se inicializa para formar un clúster disponible;

  Para el cliente:

  • El cliente encapsula la capa de operación de la API, de modo que cualquier acceso se base en la misma API;
  • La API del cliente debe seguir un cierto protocolo para encapsular el protocolo del mensaje;
  • La comunicación de red debe realizar la serialización, deserialización y establecimiento de conexión;

  Por supuesto, esta parte de la encapsulación del protocolo, la serialización / deserialización y el establecimiento de la conexión proporcionada por el cliente también debe ser proporcionada por el servidor. Podemos interceptar la solicitud escribiendo el pseudo servidor para ver, el código es el siguiente:

public  class SoecktLister { 
    
    public  static  void main (String [] args) lanza Exception { 
        ServerSocket serverSocket = new ServerSocket (2181 ); 
        Socket accept = serverSocket.accept ();
        byte [] resultado = nuevo  byte [2048 ]; 
        accept.getInputStream (). read (resultado); 

        ByteBuffer bb = ByteBuffer.wrap (resultado); 
        ByteBufferInputStream bbis = nuevo ByteBufferInputStream (bb); 
        BinaryInputArchive bia =BinaryInputArchive.getArchive (bbis); 
        RequestHeader header2 = new RequestHeader (); 
        header2.deserialize (bia, "encabezado" ); 
        System.out.println (encabezado2); 
        bbis.close (); 
    } 
}

  Luego acceda a través del cliente:

 clase pública ZooKeeperTest { 

   zooKeeper privado zooKeeper; 

   public ZooKeeperTest () {
       try { 
         zooKeeper = new ZooKeeper ("localhost: 2181" ,
                  5000 ,
                 null , false ); 
      } catch (IOException e) { 
         e.printStackTrace (); 
      } 
   } 

   public  void add (ruta de cadena, datos de cadena) {
       try { 
         String newPath =zooKeeper.create (ruta, data.getBytes (), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 
      } catch (KeeperException e) { 
         e.printStackTrace (); 
      } catch (InterruptedException e) { 
         e.printStackTrace (); 
      } 
   } 

   public  static  void main (String [] args) { 
      ZooKeeperTest zooKeeperTest = new ZooKeeperTest (); 
      zooKeeperTest.add ( "/ monkey2", "2019" ); 
   } 

}

  Para que el servidor pueda recibir la solicitud:

RequestHeader {protocolVersion = 45, lastZxidSeen = 0, timeOut = 0, sessionId = 21474836480000, passwd = []}

  De hecho, estos contenidos son el paquete de protocolo de un mensaje de solicitud simple.

En segundo lugar, el análisis del código fuente del servidor

  1. Inicialización del servidor

  De acuerdo con el script de inicio de ZooKeeper./zkServer.sh start -server ip: port, abra el script para ver la entrada de inicio del servidor: org.apache.zookeeper.server.quorum.QuorumPeerMain.

  Nota: La estructura de almacenamiento de datos del servidor es: org.apache.zookeeper.server.DataTree, dataTree se coloca en ZKDataBasse.

  Después de que se inicie el servidor, cargará el archivo de configuración zoo.cfg, la carga de datos, el establecimiento de comunicación y la elección del líder a su vez. El código es el siguiente:

@ Override
 pública  la sincronizada  vacío Inicio () {
     SI (! {La getView () containsKey (MyID).)
         De banda  nueva nuevo una RuntimeException ( "mi ID" + + MyID "El no va a utilizar la lista de pares" ); 
    } 
    loadDataBase ();      // Cargar Carga de datos znode de datos: lea el archivo de instantánea del disco duro (en el directorio de datos) 
    startServerCnxnFactory ();    // Establecimiento de comunicación de red 
    intente { 
        adminServer.start (); 
    } catch (AdminServerException e) { 
        LOG.warn ( "Problema al iniciar AdminServer" , e ); 
        System.out.println (e); 
    }
    startLeaderElection ();      // elecciones 
    startJvmPauseMonitor ();          Súper .start ();    // ahora llamando al método de ejecución hilo 
}

  Nota: La configuración se ha cargado antes de llamar a esto, como el código:

public  void runFromConfig (configuración de QuorumPeerConfig) lanza IOException, AdminServerException {
     try { 
        ManagedUtil.registerLog4jMBeans (); 
    } catch (JMException e) { 
        LOG.warn ( "No se puede registrar el control log4j JMX" , e); 
    } 

    LOG.info ( "Inicio del quórum par" ); 
    MetricsProvider metricsProvider; 
    pruebe { 
        metricsProvider = MetricsProviderBootstrap.startMetricsProvider ( 
            config.getMetricsProviderClassName (), 
            config.getMetricsProviderConfiguration ()); 
    }catch (error de MetricsProviderLifeCycleException) {
         lanzar una  nueva IOException ("No se puede iniciar MetricsProvider" + config.getMetricsProviderClassName (), error); 
    } 
    pruebe { 
        ServerMetrics.metricsProviderInitialized (metricsProvider); 
        ServerCnxnFactory cnxnFactory = nulo ; 
        ServerCnxnFactory secureCnxnFactory = nulo ; 

        if (config.getClientPortAddress ()! = null ) { 
            cnxnFactory = ServerCnxnFactory.createFactory ();
            cnxnFactory.configure (config.getClientPortAddress (), config.getMaxClientCnxns (), config.getClientPortListenBacklog (), falso ); 
        } 

        if (config.getSecureClientPortAddress ()! = null ) { 
            secureCnxnFactory = ServerCnxnFactory.createFactory (); 
            secureCnxnFactory.configure (config.getSecureClientPortAddress (), config.getMaxClientCnxns (), config.getClientPortListenBacklog (), verdadero ); 
        } 

        quorumPeer = getQuorumPeer (); 
        quorumPeer.setTxnFactory ( nuevo FileTxnSnapLog (config.getDataLogDir (), config.getDataDir ()));
        quorumPeer.enableLocalSessions (config.areLocalSessionsEnabled ()); 
        quorumPeer.enableLocalSessionsUpgrading (config.isLocalSessionsUpgradingEnabled ()); 
        // quorumPeer.setQuorumPeers (config.getAllMembers ()); 
        quorumPeer.setElectionType (config.getElectionAlg ()); 
        quorumPeer.setMyid (config.getServerId ()); 
        quorumPeer.setTickTime (config.getTickTime ()); 
        quorumPeer.setMinSessionTimeout (config.getMinSessionTimeout ()); 
        quorumPeer.setMaxSessionTimeout (config.getMaxSessionTimeout ()); 
        quorumPeer.setInitLimit (config.getInitLimit ()); 
        quorumPeer.setSyncLimit (config.getSyncLimit ());
        quorumPeer.setConnectToLearnerMasterLimit (config.getConnectToLearnerMasterLimit ()); 
        quorumPeer.setObserverMasterPort (config.getObserverMasterPort ()); 
        quorumPeer.setConfigFileName (config.getConfigFilename ());
        quorumPeer.setClientPortListenBacklog (config.getClientPortListenBacklog ()); 
        quorumPeer.setZKDatabase ( Nueva ZKDatabase (quorumPeer.getTxnFactory ())); 
        quorumPeer.setQuorumVerifier (config.getQuorumVerifier (), falsa );
        si (config.getLastSeenQuorumVerifier () =! nula ) { 
            quorumPeer.setLastSeenQuorumVerifier (config.getLastSeenQuorumVerifier (), falsa ); 
        } 
        QuorumPeer.initConfigInZKDatabase (); 
        quorumPeer.setCnxnFactory (cnxnFactory);
        quorumPeer.setSecureCnxnFactory (secureCnxnFactory); 
        quorumPeer.setSslQuorum (config.isSslQuorum ());
        quorumPeer.setUsePortUnification (config.shouldUsePortUnification ()); 
        quorumPeer.setLearnerType (config.getPeerType ()); 
        quorumPeer.setSyncEnabled (config.getSyncEnabled ()); 
        quorumPeer.setQuorumListenOnAllIPs (config.getQuorumListenOnAllIPs ()); 
        if (config.sslQuorumReloadCertFiles) { 
            quorumPeer.getX509Util (). enableCertFileReloading (); 
        } 

        // establece las configuraciones de autenticación sasl de quórum 
        quorumPeer.setQuorumSaslEnabled (config.quorumEnableSasl);
        if  (quorumPeer.isQuorumSaslAuthEnabled ()) {
            quorumPeer.setQuorumServerSaslRequired (config.quorumServerRequireSasl);
            quorumPeer.setQuorumLearnerSaslRequired (config.quorumLearnerRequireSasl); 
            quorumPeer.setQuorumServicePrincipal (config.quorumServicePrincipal); 
            quorumPeer.setQuorumServerLoginContext (config.quorumServerLoginContext); 
            quorumPeer.setQuorumLearnerLoginContext (config.quorumLearnerLoginContext); 
        } 
        quorumPeer.setQuorumCnxnThreadsSize (config.quorumCnxnThreadsSize); 
        quorumPeer.initialize (); 

        if (config.jvmPauseMonitorToRun) { 
            quorumPeer.setJvmPauseMonitor ( nuevo JvmPauseMonitor (config)); 
        }

         quorumPeer.start ();     // Por el momento, es para llamar al método de inicio de quorumPeer, no para iniciar el hilo quorumPeer, el hilo real se inicia en el método de inicio de super.start () 
        quorumPeer.join ();      // Espere a que el servidor se inicialice 
    ) catch (InterruptedException e) {
         // warn, pero generalmente está bien 
        LOG.warn ("Quorum Peer interrupted" , e); 
    } finalmente {
         if (metricsProvider! = null ) {
             try { 
                metricsProvider.stop (); 
            } catch ( Error de 
                lanzamiento ) { LOG.warn ( "Error al detener las métricas" , error);
            }  
        } 
    }
}

  El proceso detallado de inicio del servidor se muestra en la siguiente figura:

  

 

 

  2. Respuesta de solicitud del servidor

  Luego, el servidor proporciona la solicitud de respuesta de servicio externamente, como se muestra en la siguiente figura (operación de escritura de respuesta):

    

 

 

   El proceso anterior cumple con el protocolo de coherencia Zab de ZooKeeper. El nombre completo del protocolo Zab es Zookeeper Atomic Broadcast (transmisión atómica Zookeeper). Zookeeper utiliza el protocolo Zab para garantizar la coherencia final de las transacciones distribuidas.

  Para obtener detalles sobre el acuerdo de Zab y las reglas electorales, consulte:

 

 

Tres, análisis de código fuente del cliente

  1. Inicialización del cliente

  El proceso de inicio del cliente es el siguiente:

        

 

 

  Al principio, el cliente realizará un análisis de clúster e inicialización de red (objeto ClientCncx). Al mismo tiempo, el objeto ClientCncx creará dos subprocesos, SendThread y EventThread, para gestionar la solicitud / respuesta y los eventos del observador. El código es el siguiente:

público ClientCnxn ( 
    Cadena chrootPath, 
    HostProvider hostProvider, 
    int sessionTimeout, 
    ZooKeeper ZOOKEEPER, 
    ClientWatchManager observador, 
    ClientCnxnSocket clientCnxnSocket, 
    largo sessionId,
     byte [] sessionPasswd,
     boolean canBeReadOnly) {
     este .zooKeeper = ZOOKEEPER;
    this .watcher = vigilante;
    this .sessionId = sessionId ;
    this .sessionPasswd = sessionPasswd;
    this .sessionTimeout = sessionTimeout ;
    esta.hostProvider = hostProvider;
    this .chrootPath = chrootPath; 

    connectTimeout = sessionTimeout / hostProvider.size (); 
    readTimeout = sessionTimeout * 2/3 ; 
    readOnly = canBeReadOnly;    sendThread

  = nuevo SendThread (clientCnxnSocket); 
    eventThread = new EventThread ();
   this .clientConfig = zooKeeper.getClientConfig (); 
    initRequestTimeout (); 
} 

public  void start () {
     sendThread.start (); 
    eventThread.start (); 
}

  2. Gestión de solicitudes del cliente

  El proceso para que el cliente acceda al servidor es el siguiente:

           

 

 

   Se puede ver en la figura anterior que ClientCncx ha iniciado dos hilos: SendThread y EventThread. Estos dos hilos manejan la respuesta a la solicitud del servidor, y el otro maneja el evento de escucha.

  Estos dos subprocesos se basan en la cola para la gestión de solicitudes, outGoingQueue se usa para procesar la cola para enviar solicitudes de solicitud, PendingQueue se usa para almacenar las solicitudes que se han enviado en espera de las respuestas del servicio, de modo que cuando se recibe la solicitud, se puede realizar el procesamiento de la respuesta, y waitingEventsQueue se usa para el almacenamiento temporal El objeto que necesita ser activado, por lo que la aplicación de la cola se da cuenta del alto rendimiento de ZooKeeper.

  Por lo tanto, el cliente utiliza principalmente estas tecnologías: la gestión de solicitudes subyacente es cola> hilo para procesamiento de cola> método de comunicación predeterminado NIO> bloqueo sincronizado (utilizado en la cola).

  Tanto el cliente como el servidor utilizan el componente de serialización de Jute y su propio protocolo de comunicación. Para obtener más información, consulte:

Cuatro, operación y mantenimiento de ZooKeeper

  Uso diario en Linux: comando echo zk | comando nc ip port para la operación y mantenimiento diario de ZooKeeper, como: echo mntr | nc 192.168.0.31 2181.

  El comando nc en Linux es una poderosa herramienta de red, el nombre completo es netcat, instalación en línea: yum install -y nc. Los comandos zk comunes son los siguientes:

        

 

  Por supuesto, también puede usar su propio código para implementar la operación y el mantenimiento de la interfaz. 

Supongo que te gusta

Origin www.cnblogs.com/jing99/p/12722430.html
Recomendado
Clasificación