Proceso de análisis del código fuente de Zookeeper

Prefacio

Como servicio de coordinación distribuida, Zookeeper proporciona algunos servicios básicos para sistemas distribuidos, como servicios de nombres, gestión de configuración, sincronización, etc., lo que permite a los desarrolladores manejar problemas distribuidos más fácilmente.

En los sistemas distribuidos, la coordinación es una tarea crítica. Por ejemplo, cómo permitir que un grupo de procesos o máquinas independientes sepan qué tareas deben realizar, cómo sincronizar su estado con otros procesos o máquinas y cómo manejar fallas o excepciones. Todos estos problemas los resuelve Zookeeper.

Este artículo le brindará una comprensión profunda de la implementación interna de Zookeeper, comenzando por sus diversos componentes e interfaces, y analizando sus principios de funcionamiento e ideas de diseño. Espero que en el proceso de lectura de este análisis del código fuente, pueda tener una comprensión profunda de los principios de funcionamiento y las ideas de diseño de Zookeeper, para que pueda utilizarlo mejor para resolver sus problemas distribuidos.

El cuidador del zoológico comienza

No importa qué código estemos viendo, debemos comenzar desde el punto de entrada del programa para que podamos comprender mejor la estructura general y el proceso operativo.

Insertar descripción de la imagen aquí

A través zkServer.shdel script, puede ver que la clase de inicio es QuorumPeerMain.

Insertar descripción de la imagen aquí

Puede ver que el inicio de Zookeeper se inicia a través del método principal y, finalmente, runFromConfigse llama al método para configurar e iniciar un nodo del clúster de ZooKeeper.

Insertar descripción de la imagen aquí

El código anterior establece QuorumPeerlas rutas del directorio de instantáneas y el registro de transacciones, la selección del algoritmo de elección, la ID del servidor especificada, el ciclo de reloj definido y la instancia de guardado de datos y otras configuraciones. Además, se crean clases de fábrica (NIO/Netty) para conexiones de servidor y cliente. Finalmente, llame al método de inicio para iniciar el servicio.

Insertar descripción de la imagen aquí

En start, se completan principalmente las siguientes cuatro tareas:

  1. Cargue datos del disco a la memoria para proporcionar las reservas de datos necesarias para el procesamiento y la respuesta posteriores.
  2. Establezca un Socket para manejar la solicitud del cliente e implementar la comunicación e interacción con el cliente.
  3. Realicé los preparativos para la elección del Líder y determiné el algoritmo electoral. .
  4. Llevar a cabo la elección de líder y monitorear el estado de los nodos y procesar en consecuencia, detectar y manejar fallas de nodos o estados anormales de manera oportuna y garantizar la confiabilidad y estabilidad de todo el sistema.

Cargar datos del disco

ZooKeeper opera a nivel de memoria. Para garantizar la confiabilidad, los datos se conservarán en archivos en forma de registros de transacciones, por lo que los datos se cargan en la memoria al inicio.

Insertar descripción de la imagen aquí

El objetivo principal de este código es cargar la base de datos de Zookeeper desde el disco a la memoria y verificar y procesar epochla información relacionada. getDataTree().lastProcessedZxidEsta línea de código obtiene la última transacción que se ha procesado en el servidor ZooKeeper zxid, ZxidUtils.getEpochFromZxid(lastProcessedZxid)esta línea de código la obtiene zxidde epoch: readLongFromFile(CURRENT_EPOCH_FILENAME)Esta línea de código lee la información actual del archivo epoch. Si zxidel valor de pertenencia epoches menor que el actual epoch, IOExceptionse generará una excepción.

Comunicación e interacción con los clientes.

cnxnFactoryEl servidor está establecido Socket para recibir y procesar solicitudes de clientes. El código en la imagen a continuación es NIOServerCnxnFactoryy hay otro NettyServerCnxnFactory. La opción NIOaún Nettyse puede configurar en el archivo de configuración. Si está familiarizado con NIOél, puede leer la columna de programación de redes.Netty
Insertar descripción de la imagen aquí

El núcleo es el procesamiento de las solicitudes de los clientes, existen los siguientes procesadores:

Insertar descripción de la imagen aquí

  • CommitProcessorEs el procesador de envío de transacciones, que esperará la votación de la Propuesta en el clúster hasta que se pueda enviar la Propuesta.
  • SyncRequestProcessorResponsable de persistir las solicitudes de transacciones (solicitudes de escritura) en el disco local.
  • AckRequestProcessorEs un procesador exclusivo del Líder. Su principal responsabilidad es SyncRequestProcessorenviar comentarios ACK al recopilador de votos de la Propuesta después de que el procesador completa el registro del registro de transacciones, para notificar al recopilador de votos que el servidor actual ha completado el registro del registro de transacciones para la Propuesta.
  • FollowerRequestProcessorEste procesador puede ser responsable de procesar las solicitudes de lectura y escritura del cliente, y reenviarlas a otros procesadores para su procesamiento, como reenviar solicitudes de escritura al nodo líder.
  • SendAckRequestProcessorResponsable de enviar un mensaje de reconocimiento (ACK) al nodo líder para notificarle que la solicitud ha sido procesada.

Preparación para las elecciones de líderes

startLeaderElectionEl llamado principal es createElectionAlgorithmcrear el administrador de conexión de red entre clusters QuorumCnxManagery seleccionar un algoritmo de elección, este se configura a través del archivo de configuración y el valor predeterminado es FastLeaderElection.

Insertar descripción de la imagen aquí

Procesamiento del estado del nodo

super.start()QuorumPeer.javaLos métodos de la clase de ejecución run()se utilizan principalmente para monitorear y procesar el estado del nodo.

Insertar descripción de la imagen aquí

Cuando se inicia Zookeeper, se encuentra en el primer Lookingestado. A través de la elección, uno de los servidores se convierte en Líder y los otros servidores se convierten en Seguidores. Si el código es difícil de entender, puedes echar un vistazo al protocolo ZAB .

Insertar descripción de la imagen aquí

Resumir

Al analizar profundamente el código fuente, noté su simplicidad y su diseño inteligente de implementación funcional. Aunque la funcionalidad que maneja el código es bastante compleja, la simplicidad de la organización y el estilo de codificación hacen que sea bastante fácil de leer y comprender. Se presta especial atención al uso extensivo de la programación de redes y al cuidadoso tratamiento de la seguridad y optimización de las conexiones. También está la forma en que su protocolo ZAB resuelve inteligentemente el problema de la coherencia distribuida. Estos delicados conceptos de diseño sin duda proporcionan una referencia valiosa para el desarrollo de sistemas distribuidos. Espero integrar estas ideas en el código en trabajos futuros.

Supongo que te gusta

Origin blog.csdn.net/qq_28314431/article/details/132939298
Recomendado
Clasificación